<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<script type="module" src="./main.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
index.html
global.css
main.js
App.vue
HelloBicool.vue
package.json
现在支持上传本地图片了!
index.html
global.css
body {
background-color: #fefefe;
}
编辑器加载中
main.js
import { createApp } from 'vue'
import './global.css'
import App from './App.vue'
createApp(App).mount('#app')
console.log(["Hello 笔.COOL 控制台"])
import Chart from 'chart.js/auto'
const app = createApp(App)
app.config.globalProperties.$Chart = Chart
app.mount('#app')
编辑器加载中
App.vue
<script setup>
import HelloBicool from './HelloBicool.vue'
import { ref } from "vue"
</script>
<template>
<div class="container">
<HelloBicool :title="title" :descr="descr" />
</div>
</template>
<style lang="scss" scoped>
$bg: #f0f2f5;
.container {
background: $bg;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
.logo {
height: 40px;
width: 40px;
margin-top: 20px;
}
</style>
编辑器加载中
HelloBicool.vue
<template>
<div class="container">
<!-- 左侧数据面板 -->
<div class="left-panel">
<DataCard title="实时故障统计">
<FaultStats :stats="faultData" />
</DataCard>
<DataCard title="监控的设备列表">
<DeviceList :devices="devices" />
</DataCard>
<div class="flex-grid">
<DataCard title="设备健康度评分" class="half">
<GaugeChart :value="healthScore" />
</DataCard>
<DataCard title="声压级别" class="half">
<SoundLevelTable :data="soundLevels" />
</DataCard>
</div>
</div>
<!-- 中间占位区域 -->
<div class="three-container">
<div class="placeholder-text">3D Visualization Area</div>
</div>
<!-- 右侧数据面板 -->
<div class="right-panel">
<DataCard title="运维建议">
<MaintenanceTips :tips="maintenanceTips" />
</DataCard>
<DataCard title="运行趋势预测">
<LineChart :data="trendData" />
</DataCard>
</div>
</div>
</template>
<script setup>
import {ref} from 'vue'
// 模拟数据
const faultData = ref({
critical: 2,
warning: 5,
normal: 28
})
const devices = ref([
{ name: '变压器#1', status: 'normal' },
{ name: '断路器#2', status: 'warning' },
{ name: '电容器#3', status: 'critical' },
])
const healthScore = ref(85)
const soundLevels = ref([
{ point: '东侧', value: '65dB' },
{ point: '南侧', value: '68dB' },
{ point: '西侧', value: '63dB' },
])
const maintenanceTips = ref([
'建议更换#2断路器触点',
'检测变压器冷却系统',
'检查电容器绝缘性能'
])
const trendData = ref([
{ time: '00:00', value: 82 },
{ time: '04:00', value: 85 },
{ time: '08:00', value: 88 },
{ time: '12:00', value: 84 },
])
</script>
<style scoped>
.container {
display: grid;
grid-template-columns: 300px 1fr 300px;
height: 100vh;
background: #13192f;
color: #fff;
overflow: hidden;
}
.three-container {
position: relative;
border: 2px solid rgb(0, 208, 137);
margin: 10px;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 0 20px rgba(0, 208, 137, 0.3);
display: flex;
align-items: center;
justify-content: center;
}
.placeholder-text {
color: rgba(0, 208, 137, 0.3);
font-size: 1.5em;
user-select: none;
}
.left-panel, .right-panel {
padding: 20px;
display: flex;
flex-direction: column;
gap: 20px;
overflow-y: auto;
}
.flex-grid {
display: flex;
gap: 20px;
}
.half {
flex: 1;
}
</style>
<!-- 子组件样式 -->
<style>
.data-card {
background: #1a223f;
border: 1px solid rgb(0, 208, 137);
border-radius: 8px;
padding: 20px;
box-shadow: 0 0 15px rgba(0, 208, 137, 0.2);
}
.chart-container {
height: 200px;
position: relative;
}
.device-item {
padding: 8px;
margin: 5px 0;
background: rgba(255,255,255,0.05);
border-radius: 4px;
}
.status-indicator {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 10px;
}
.status-indicator.normal { background: #00d089 }
.status-indicator.warning { background: #ffeb3b }
.status-indicator.critical { background: #f44336 }
.gauge-chart {
width: 100%;
height: 180px;
display: flex;
justify-content: center;
align-items: center;
font-size: 2.5em;
color: rgb(0, 208, 137);
position: relative;
}
.gauge-back {
position: absolute;
width: 100%;
height: 100%;
border: 3px solid rgba(0, 208, 137, 0.3);
border-radius: 50%;
clip-path: inset(0 50% 0 0);
}
</style>
<!-- 子组件实现 -->
<script>
const DataCard = {
template: `
<div class="data-card">
<h3 style="margin: 0 0 15px; color: rgb(0, 208, 137)">{{ title }}</h3>
<slot></slot>
</div>
`,
props: ['title']
}
const FaultStats = {
template: `
<div class="chart-container">
<div v-for="(value, key) in stats" :key="key" class="stat-item">
<span class="label">{{ key }}:</span>
<span :class="['value', key]">{{ value }}</span>
</div>
</div>
`,
props: ['stats']
}
const DeviceList = {
template: `
<div class="device-list">
<div v-for="device in devices" :key="device.name" class="device-item">
<span class="status-indicator" :class="device.status"></span>
{{ device.name }}
</div>
</div>
`,
props: ['devices']
}
const GaugeChart = {
template: `
<div class="gauge-chart">
{{ value }}%
<div class="gauge-back"></div>
</div>
`,
props: ['value']
}
const LineChart = {
template: `
<div class="chart-container">
<canvas ref="chart"></canvas>
</div>
`,
mounted() {
const ctx = this.$refs.chart.getContext('2d')
new this.$Chart(ctx, {
type: 'line',
data: {
labels: this.data.map(d => d.time),
datasets: [{
label: '健康度',
data: this.data.map(d => d.value),
borderColor: 'rgb(0, 208, 137)',
tension: 0.4
}]
}
})
}
}
components: {
DataCard,
FaultStats,
DeviceList,
GaugeChart,
LineChart
}
</script>
编辑器加载中
package.json
注意:新添加的依赖包首次加载可能会报错,稍后再次刷新即可
{
"dependencies": {
"vue": "3.5.13",
"three":"^0.167.1"
}
}
编辑器加载中
预览页面