数字孪生监控大屏实战模板:云数据中心展示平台

前端数字孪生大屏,使用VUE3+Elementplus+Echarts+TS实现云数据中心展示平台,数字孪生,监控大屏展示,可下载作为课堂作业、界面模板、扩展开发,个人作品等。

若想系统学习Echarts开发,我的课程提供了完整的Echarts基础知识讲解并附加大量实战案例,系列课程地址如下:

1. CSDN课程:https://edu.csdn.net/course/detail/40842

2. 51学堂课程:https://edu.51cto.com/course/40414.html

3. B站课程:https://www.bilibili.com/cheese/play/ss456500998

一.效果展示:


二.源码下载:

点击下载

三.开发视频:

https://www.bilibili.com/video/BV1zDowBLEBy/

四.实现明细:

4.1 开发环境

使用vscode开发,nodejs版本为v24.11.0,其它项目依赖如下:

1. "dayjs": "^1.11.20"

2. "echarts": "^6.0.0"

3. "element-plus": "^2.13.6"

4. "less": "^4.6.4"

5. "pinia": "^3.0.4"

6. "vue": "^3.5.31"

7. "vue-router": "^5.0.4"

4.2 实现明细

  1. main.ts
javascript 复制代码
import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)

app.use(createPinia())
app.use(router)
app.use(ElementPlus)

app.mount('#app')
  1. App.vue
javascript 复制代码
<script setup lang="ts"></script>

<template>
  <RouterView></RouterView>
</template>

<style >
@import url("@/assets/main.css");
</style>
  1. HomeView.vue
javascript 复制代码
<script setup lang="ts">
import ChartItem from '@/components/ChartItem.vue';
import DataFromChartItem from '@/components/DataFromChartItem.vue';
import Header from '@/components/Header.vue';
import PlanTop10ChartItem from '@/components/PlanTop10ChartItem.vue';
import CenterChartItem from '@/components/CenterChartItem.vue';
import CountChartItem from '@/components/CountChartItem.vue';
import UserChartItem from '@/components/UserChartItem.vue';
</script>

<template>
  <div class="page">
    <Header></Header>
    <el-row>
      <el-col :span="18">
        <div class="top">
          <el-row>
            <el-col :span="6">
              <ChartItem title="热门订阅方案TOP10">
                <div class="char-item-2">
                  <PlanTop10ChartItem></PlanTop10ChartItem>
                </div>
              </ChartItem>
            </el-col>
            <el-col :span="18">
              <CenterChartItem></CenterChartItem>
            </el-col>
          </el-row>
        </div>
        <div class="bottom">
          <ChartItem title="近7日各个渠道采集量">
            <div class="char-item">
              <DataFromChartItem></DataFromChartItem>
            </div>
          </ChartItem>
        </div>
      </el-col>
      <el-col :span="6">
          <ChartItem title="近7日方案数">
            <div class="char-item">
              <CountChartItem></CountChartItem>
            </div>
          </ChartItem>
          <ChartItem title="近7日新增用户数">
            <div class="char-item-2">
              <UserChartItem></UserChartItem>
            </div>
          </ChartItem>
      </el-col>
    </el-row>
  </div>
</template>
<style lang="less" scoped>
  .page{
    width:100vw;
    height: 100vh;
    background: url(@/assets/images/bg.jpg);
    background-size: 100% 100%;

    .char-item{
      height: calc(33vh - 20px);
    }
    .char-item-2{
      height: calc(66vh - 131px);
    }
  }
</style>
  1. router/index.ts
javascript 复制代码
import HomeView from '@/views/HomeView.vue'
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [{
    path:"",
    component:HomeView
  }],
})

export default router
  1. UserChartItem.vue
javascript 复制代码
<template>
    <div class="chart-item" ref="chartRef"></div>
    <div class="chart-item" ref="pieChartRef"></div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import * as echarts from "echarts";

const chartRef = ref();
const chart = ref();
const chartOptions = reactive({
    grid:{
        left:'5%',
        top:'10%',
        bottom:'0%',
        right:'5%',
        containLable:false
    },
    yAxis: {
        type: 'category',
        data: ['2021-12-01', '2021-12-02', '2021-12-03', '2021-12-04', '2021-12-05', '2021-12-06', '2021-12-07', '2021-12-08', '2021-12-09', '2021-12-10'],
        axisLine:{
            show:true
        },
        axisLabel:{
            show:false
        }
    },
    xAxis: {
        type: 'value',
        show:false
    },
    legend:{
        top:'1%',
        right:'1%',
        textStyle:{
            color:'#fff'
        }
    },
    series: [
        {
            name:'电脑端',
            data: [120, 200, 150, 80, 70, 110, 130, 432, 766, 234],
            type: 'bar',
            barWidth:15,
            itemStyle:{
                color:{
                    type: 'linear',
                    x: 0,
                    y: 0,
                    x2: 0,
                    y2: 1,
                    colorStops: [{
                        offset: 0, color: '#0095ff' // 0% 处的颜色
                    }, {
                        offset: 1, color: '#008bff' // 100% 处的颜色
                    }],
                    global: false // 缺省为 false
                }
            },
            label:{
                show:true,
                position:'right',
                textStyle:{
                    color:'#fff'
                }
            }
        },
        {
            name:'移动端',
            // xAxisIndex:1,
            data: [-120, -200, -150, -80, -70, -110, -130, -432, -766, -234],
            type: 'bar',
            barWidth:15,
            barGap:'-100%',
            itemStyle:{
                color:{
                    type: 'linear',
                    x: 0,
                    y: 0,
                    x2: 0,
                    y2: 1,
                    colorStops: [{
                        offset: 0, color: '#163a8d' // 0% 处的颜色
                    }, {
                        offset: 1, color: '#163a8d' // 100% 处的颜色
                    }],
                    global: false // 缺省为 false
                }
            },
            label:{
                show:true,
                position:'left',
                formatter:function(pama){
                    return -pama.value;
                },
                textStyle:{
                    color:'#fff'
                }
            }
        }
    ]
});
const pieChartRef = ref();
const pieChart = ref();
const pieChartOptions = reactive({
    color:['#02afff','#004be4','#5f45ff','#00d2ff','#0091e4'],
    legend: {
        left: 'center',
        bottom:'1%',
        textStyle:{
            color:'#fff'
        }
    },
    series: [
        {
            name: '用户占比',
            type: 'pie',
            radius: '60%',
            data: [
                { value: 1048, name: 'QQ' },
                { value: 735, name: '微信' },
                { value: 580, name: '微博' },
                { value: 484, name: 'PC' },
                { value: 300, name: 'H5' }
            ],
            label:{
                textStyle:{
                    color:'#fff'
                }
            }
        }
    ]
});
onMounted(()=>{
    chart.value = echarts.init(chartRef.value);
    chart.value.setOption(chartOptions);

    pieChart.value = echarts.init(pieChartRef.value);
    pieChart.value.setOption(pieChartOptions);
})
</script>
<style lang="less" scoped>
    .chart-item{
        height: 50%;
    }
</style>
  1. PlanTop10ChartItem.vue
javascript 复制代码
<template>
    <div class="tr" v-for="(item,index) in datas">
        <div class="td index">{{ index+1 }}</div>
        <div class="td name">{{ item.name }}</div>
        <div class="td type">{{ item.type }}</div>
        <div class="td scope">{{ item.scope }}次<text class="up" :class="[item.up?'up':'down']">{{ item.up?'↑':'↓' }}</text></div>
    </div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';

const datas = reactive([{
    name:'XXXX新闻信息001',
    type:'新闻',
    scope:12,
    up:false
},{
    name:'XXXX新闻信息002',
    type:'新闻',
    scope:432,
    up:true
},{
    name:'XXXX新闻信息003',
    type:'头条',
    scope:32,
    up:false
},{
    name:'XXXX新闻信息004',
    type:'新闻',
    scope:56,
    up:false
},{
    name:'XXXX新闻信息005',
    type:'新闻',
    scope:32,
    up:true
},{
    name:'XXXX新闻信息006',
    type:'新闻',
    scope:43,
    up:false
},{
    name:'XXXX新闻信息007',
    type:'娱乐',
    scope:65,
    up:false
},{
    name:'XXXX新闻信息008',
    type:'娱乐',
    scope:87,
    up:true
},{
    name:'XXXX新闻信息009',
    type:'娱乐',
    scope:76,
    up:true
},{
    name:'XXXX新闻信息010',
    type:'娱乐',
    scope:876,
    up:true
}])
</script>
<style lang="css" scoped>
    .tr{
        display: flex;
        line-height: 45px;
        color:#9fceff;
        
        .index{
            width:20px;
            text-align: center;
            color: #de8d05;
        }
        .name{
            flex:1;
            border-bottom: 1px dotted #0090ff;
        }
        .type{
           width:80px;
           text-align: center;
            border-bottom: 1px dotted #0090ff;
        }
        .scope{
           width:80px;
           text-align: right;
            border-bottom: 1px dotted #0090ff;

           .up{
            margin-left: 5px;
            font-weight: bold;
            color:#1db364
           }
           .down{
            margin-left: 5px;
            font-weight: bold;
            color:#ff0800
           }
        }
    }
</style>
  1. Header.vue
javascript 复制代码
<template>
    <div class="header">
        <img src="@/assets/images/icon-002.png">
        <div class="left"></div>
        <div class="title">
            军军君数据中心展示平台
        </div>
        <div class="right"></div>
    </div>
</template>
<script setup lang="ts">
</script>
<style lang="less" scoped>
    .header{
        height: 80px;
        position: relative;
        display: flex;
        .left,.right{
            flex:1
        }
        .title{
            line-height: 60px;
            text-align: center;
            font-size: 1.8rem;
            color: #2acaff;
            z-index: 1;
            letter-spacing: 5px;
        }
        img{
            position: absolute;
            left:13%;
            top:-4px;
            height: 100%;
        }
    }
</style>
  1. DataFromChartItem.vue
javascript 复制代码
<template>
    <div class="chart-item" ref="chartRef"></div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import * as echarts from "echarts";

const chartRef = ref();
const chart = ref();
const chartOptions = reactive({
    grid:{
        left:'5%',
        top:'5%',
        bottom:'5%',
        right:'5%',
        containLable:false
    },
    xAxis: {
        type: 'category',
        data: ['2021-12-01', '2021-12-02', '2021-12-03', '2021-12-04', '2021-12-05', '2021-12-06', '2021-12-07', '2021-12-08', '2021-12-09', '2021-12-10'],
        axisLabel:{
            textStyle:{
                color:'#91bdeb'
            }
        },
        splitLine:{
            show:true,
            lineStyle:{
                color:'#0a2c54',
                type:'dashed'
            }
        },
        axisLine:{
            lineStyle:{
                color:'#0a2c54',
            }
        }
    },
    yAxis: {
        type: 'value',
        axisLabel:{
            textStyle:{
                color:'#91bdeb'
            }
        },
        splitLine:{
            lineStyle:{
                color:'#0a2c54',
                type:'dashed'
            }
        },
        axisLine:{
            show:true,
            lineStyle:{
                color:'#0a2c54',
            }
        }
    },
    series: [
        {
            name:'H5',
            data: [120, 200, 150, 80, 70, 110, 130, 432, 766, 234],
            type: 'bar',
            barWidth:15,
            itemStyle:{
                color:{
                    type: 'linear',
                    x: 0,
                    y: 0,
                    x2: 0,
                    y2: 1,
                    colorStops: [{
                        offset: 0, color: '#5f45ff' // 0% 处的颜色
                    }, {
                        offset: 1, color: '#392e95' // 100% 处的颜色
                    }],
                    global: false // 缺省为 false
                }
            }
        },{
            name:'微信',
            data: [54, 768, 98, 455, 35, 768, 234, 679, 168, 432],
            type: 'bar',
            barWidth:15,
            itemStyle:{
                color:{
                    type: 'linear',
                    x: 0,
                    y: 0,
                    x2: 0,
                    y2: 1,
                    colorStops: [{
                        offset: 0, color: '#02cdff' // 0% 处的颜色
                    }, {
                        offset: 1, color: '#02cdff' // 100% 处的颜色
                    }],
                    global: false // 缺省为 false
                }
            }
        },{
            name:'微博',
            data: [54, 657, 782, 21, 323, 433, 543, 564, 867, 342],
            type: 'bar',
            barWidth:15,
            itemStyle:{
                color:{
                    type: 'linear',
                    x: 0,
                    y: 0,
                    x2: 0,
                    y2: 1,
                    colorStops: [{
                        offset: 0, color: '#0090ff' // 0% 处的颜色
                    }, {
                        offset: 1, color: '#0d84df' // 100% 处的颜色
                    }],
                    global: false // 缺省为 false
                }
            }
        },{
            name:'APP',
            data: [435, 353, 150, 274, 82, 961, 543, 453, 432, 432],
            type: 'bar',
            barWidth:15,
            itemStyle:{
                color:{
                    type: 'linear',
                    x: 0,
                    y: 0,
                    x2: 0,
                    y2: 1,
                    colorStops: [{
                        offset: 0, color: '#314976' // 0% 处的颜色
                    }, {
                        offset: 1, color: '#2251aa' // 100% 处的颜色
                    }],
                    global: false // 缺省为 false
                }
            }
        }
    ]
});
onMounted(()=>{
    chart.value = echarts.init(chartRef.value);
    chart.value.setOption(chartOptions);
})
</script>
<style lang="less" scoped>
    .chart-item{
        height: 100%;
    }
</style>
  1. CountChartItem.vue
javascript 复制代码
<template>
    <div class="chart-item" ref="chartRef"></div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import * as echarts from "echarts";

const chartRef = ref();
const chart = ref();
const chartOptions = reactive({
    grid:{
        left:'5%',
        top:'12%',
        bottom:'5%',
        right:'2%',
        containLable:false
    },
    legend:{
        top:'1%',
        right:'1%',
        textStyle:{
            color:'#fff'
        }
    },
    xAxis: {
        type: 'category',
        data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月'],
        axisLabel:{
            textStyle:{
                color:'#91bdeb'
            }
        },
        splitLine:{
            show:true,
            lineStyle:{
                color:'#0a2c54',
                type:'dashed'
            }
        },
        axisLine:{
            lineStyle:{
                color:'#0a2c54',
            }
        }
    },
    yAxis: {
        type: 'value',
        axisLabel:{
            textStyle:{
                color:'#91bdeb'
            }
        },
        splitLine:{
            lineStyle:{
                color:'#0a2c54',
                type:'dashed'
            }
        }
    },
    series: [
        {
            name:'正常方案数',
            data: [120, 200, 150, 80, 70, 110, 130, 432, 766, 234],
            type: 'line',
            stack: 'Total',
            areaStyle: {
                opacity: 0.8,
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                    {
                        offset: 0,
                        color: '#91bdeb55'
                    },
                    {
                        offset: 1,
                        color: '#91bdeb22'
                    }
                ])
            }
        },{
            name:'删除方案数',
            data: [54, 768, 98, 455, 35, 768, 234, 679, 168, 432],
            type: 'line',
            stack: 'Total',
            areaStyle: {
                opacity: 0.8,
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                    {
                        offset: 0,
                        color: '#0a2c5455'
                    },
                    {
                        offset: 1,
                        color: '#0a2c54'
                    }
                ])
            }
        }
    ]
});
onMounted(()=>{
    chart.value = echarts.init(chartRef.value);
    chart.value.setOption(chartOptions);
})
</script>
<style lang="less" scoped>
    .chart-item{
        height: 100%;
    }
</style>
  1. ChartItem.vue
javascript 复制代码
<template>
    <div class="chart-item">
        <div class="title">
            <div class="text">{{ title }}</div>
            <img src="@/assets/images/icon-003.png">
            <div class="line"></div>
        </div>
        <slot></slot>
    </div>
</template>
<script setup lang="ts">

const porps = defineProps({
    title:String
})

</script>
<style lang="less" scoped>
    .chart-item{
        margin: 5px;
        .title{
            color: #ffa200;
            line-height: 30px;
            position: relative;
            padding-left: 80px;

            img{
                position: absolute;
                bottom: 0;
                left:5px;
            }
            .line{
                position: absolute;
                left: 0;
                height: 2px;
                width:80%;
                bottom: 0;
                background: #0483f0;
                max-width: 400px;
            }
        }
    }
</style>
  1. CenterChartItem.vue
javascript 复制代码
<template>
    <div class="scope-chart" ref="scopeChartRef"></div>
    <div class="date-chart" >
        <div class="chart-item">
            <div class="process">
                <el-progress type="circle" width="80" :stroke-width="16" :percentage="value1" :format="()=>'日'"/>
            </div>
            <div class="content">
                <div class="title">日活跃用户</div>
                <div class="value">{{ value1 }}</div>
            </div>
        </div>
        <div class="chart-item">
            <div class="process">
                <el-progress type="circle" width="80" :stroke-width="16" :percentage="value2" :format="()=>'周'"/>
            </div>
            <div class="content">
                <div class="title">周活跃用户</div>
                <div class="value">{{ value2 }}</div>
            </div>
        </div>
        <div class="chart-item">
            <div class="process">
                <el-progress type="circle" width="80" :stroke-width="16"  :percentage="value3" :format="()=>'月'"/>
            </div>
            <div class="content">
                <div class="title">月活跃用户</div>
                <div class="value">{{ value3 }}</div>
            </div>
        </div>
    </div>
</template>
<script setup lang="ts">
    import { onMounted, reactive ,ref} from 'vue';
    import * as echarts from "echarts";

    const value1 = ref(42);
    const value2 = ref(65);
    const value3 = ref(87);


    const scopeChartRef = ref();
    const scopeChart = ref();
    const scopeChartOptions = reactive({
        title: {
            show: true,
            text: '{a|当前用户数}',
            x: '50%',
            y: '55%',
            z: 10,
            textAlign: 'center',
            textStyle: {
                color: '#ffffff',
                fontSize: 14,
                rich:{
                    a:{
                        backgroundColor: '#1b225baa',
                        borderColor: '#0d197d66',
                        borderWidth:1,
                        borderRadius: 4,
                        padding:5
                    }
                }
            }
        },
        series: [
            {
                name: "内部进度条",
                type: "gauge",
                radius: '60%',
                splitNumber: 6,
                axisLine: {
                    lineStyle: {
                        color: [
                            [40 / 100, '#d420ff'],
                            [1, "#47c8ff22"]
                        ],
                        width: 10
                    }
                },
                axisLabel: {
                    show: false,
                },
                axisTick: {
                    show: false,
                },
                splitLine: {
                    show: false,
                },
                pointer: {
                    show: false,
                },
            },
            {
                name: '外部刻度',
                type: 'gauge',
                radius: '60%',
                min: 0, //最小刻度
                max: 100, //最大刻度
                splitNumber: 10, //刻度数量
                startAngle: 220,
                endAngle: -40,
                axisLine: {
                    show: false,
                },
                //仪表盘轴线
                axisLabel: {
                    show: false,
                }, 
				//刻度标签
                axisTick: {
                    show: true,
                    splitNumber: 6,
                    lineStyle: {
                        color: '#00faff', //用颜色渐变函数不起作用
                        width: 1,
                    },
                    length: -5
                }, 
				//刻度样式
                splitLine: {
                    show: true,
                    length: -8,
                    lineStyle: {
                        color: '#00faff', //用颜色渐变函数不起作用
                        width: 1,
                    }
                }, //分隔线样式
                detail: {
                    show: false
                },
                pointer: {
                    show: false
                }
            },
            /*内部*/
            {
                type: 'pie',
                radius:  ['0', '40%'],
                z: 3,
                hoverAnimation: false,
                data: [{
                    name: '合规率',
                    value: 75.85,
                    itemStyle: {
                        normal: {
                            color: 
                            {
                                type: 'radial',
                                x: 0.5,
                                y: 0.5,
                                r: 0.5,
                                colorStops: [{
                                    offset: 0, color: '#025ebb' // 0% 处的颜色
                                }, {
                                    offset: 1, color: '#025ebb22' // 100% 处的颜色
                                }],
                                global: false // 缺省为 false
                            }
                        }
                    },
                    label: {
                        normal: {
                            rich: {
                                a: {
                                    color: '#ffffff',
                                    align: 'center',
                                    fontSize: 28,
                                },
                            },
                            formatter: function (params) {
                                return "{a|" + params.value + "%"+"}";
                            },
                            position: 'center',
                            show: true
                        }
                    },
                    labelLine: {
                        show: false
                    }
                }],
            },
            /*外一层*/
            {
				type: "pie",
                radius:  ['0', '80%'],
                avoidLabelOverlap: false,
                z: 1,
                hoverAnimation: false,
                label: {
                    show: false
                },
                labelLine: {
                    show: false
                },
                data: [{
                    "value": 1
                }],
                itemStyle: {
                    normal: {
						color: 'rgba(0,131,255,0.05)',
                    }
                }
            },
            //外二层圈
            {
                type: "pie",
                radius:  ['0', '100%'],
                avoidLabelOverlap: false,
                z: 0,
                hoverAnimation: false,
                label: {
                    show: false
                },
                labelLine: {
                    show: false
                },
                data: [{
                    "value": 1
                }],
                itemStyle: {
                    normal: {
						color: 'rgba(0,131,255,0.05)',
                    }
                }
            }
        ]
    })
    onMounted(()=>{
        scopeChart.value = echarts.init(scopeChartRef.value);
        scopeChart.value.setOption(scopeChartOptions);
        
    })
</script>
<style lang="less" scoped>
    .scope-chart{
        height: 45vh;
    }
    .date-chart{
        height: 10vh;
        display: flex;
        padding-top: 20px;
        .chart-item{
            flex:1;
            display: flex;
            .process{
                width:40%;
                display: flex;
                justify-content: center;
                justify-items: center;
                align-items: center;
                align-content: center;

                :deep(.el-progress__text){
                    font-size: 1.2rem !important;
                    color: #2bcbff
                }
            }
            .content{
                flex:1;
                margin-left: 10px;
                padding: 20px 0;
                background: url(@/assets/images/icon-001.png);
                background-size: 100% 100%;
                text-align: center;
                .title{
                    color: #9fceff;
                }
                .value{
                    color: #9fceff;
                }
            }
        }
    }
</style>
  1. main.css
javascript 复制代码
@import './base.css';

#app {
  font-weight: normal;
}

a,
.green {
  text-decoration: none;
  color: hsla(160, 100%, 37%, 1);
  transition: 0.4s;
  padding: 3px;
}

@media (hover: hover) {
  a:hover {
    background-color: hsla(160, 100%, 37%, 0.2);
  }
}

@media (min-width: 1024px) {
  body {
  }

  #app {
  }
}
  1. base.css
javascript 复制代码
/* color palette from <https://github.com/vuejs/theme> */
:root {
  --vt-c-white: #ffffff;
  --vt-c-white-soft: #f8f8f8;
  --vt-c-white-mute: #f2f2f2;

  --vt-c-black: #181818;
  --vt-c-black-soft: #222222;
  --vt-c-black-mute: #282828;

  --vt-c-indigo: #2c3e50;

  --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
  --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
  --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
  --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);

  --vt-c-text-light-1: var(--vt-c-indigo);
  --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
  --vt-c-text-dark-1: var(--vt-c-white);
  --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}

/* semantic color variables for this project */
:root {
  --color-background: var(--vt-c-white);
  --color-background-soft: var(--vt-c-white-soft);
  --color-background-mute: var(--vt-c-white-mute);

  --color-border: var(--vt-c-divider-light-2);
  --color-border-hover: var(--vt-c-divider-light-1);

  --color-heading: var(--vt-c-text-light-1);
  --color-text: var(--vt-c-text-light-1);

  --section-gap: 160px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-background: var(--vt-c-black);
    --color-background-soft: var(--vt-c-black-soft);
    --color-background-mute: var(--vt-c-black-mute);

    --color-border: var(--vt-c-divider-dark-2);
    --color-border-hover: var(--vt-c-divider-dark-1);

    --color-heading: var(--vt-c-text-dark-1);
    --color-text: var(--vt-c-text-dark-2);
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  font-weight: normal;
}

body {
  color: var(--color-text);
  background: var(--color-background);
  transition:
    color 0.5s,
    background-color 0.5s;
  line-height: 1.6;
  font-family:
    Inter,
    -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    Oxygen,
    Ubuntu,
    Cantarell,
    'Fira Sans',
    'Droid Sans',
    'Helvetica Neue',
    sans-serif;
  font-size: 15px;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  margin: 0;
  padding: 0;
}
  1. package.json
javascript 复制代码
{
  "name": "cloud-data-center-service",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "run-p type-check \"build-only {@}\" --",
    "preview": "vite preview",
    "build-only": "vite build",
    "type-check": "vue-tsc --build"
  },
  "dependencies": {
    "echarts": "^6.0.0",
    "element-plus": "^2.13.7",
    "pinia": "^3.0.4",
    "vue": "^3.5.32",
    "vue-router": "^5.0.4"
  },
  "devDependencies": {
    "@tsconfig/node24": "^24.0.4",
    "@types/node": "^24.12.2",
    "@vitejs/plugin-vue": "^6.0.6",
    "@vue/tsconfig": "^0.9.1",
    "less": "^4.6.4",
    "npm-run-all2": "^8.0.4",
    "typescript": "~6.0.0",
    "vite": "^8.0.8",
    "vite-plugin-vue-devtools": "^8.1.1",
    "vue-tsc": "^3.2.6"
  },
  "engines": {
    "node": "^20.19.0 || >=22.12.0"
  }
}
  1. vite.config.ts
javascript 复制代码
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    // vueDevTools(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    },
  },
})
相关推荐
吴声子夜歌2 小时前
Vue3——使用axios实现Ajax请求
前端·javascript·ajax·axios
qq4356947012 小时前
JavaWeb05
前端·html
@PHARAOH2 小时前
WHAT - W3C WCAG 2.1 AA 无障碍标准
前端
用户游民2 小时前
Android 项目aab包上传谷歌平台需支持16KB页面
前端
SevgiliD2 小时前
后台下载:获取响应头文件名
前端
Hejjon2 小时前
Vue3 页面刷新时在 onMounted 里获取到的path 一直是 / 问题
前端
yuki_uix2 小时前
CSS 里的"结界":BFC 与层叠上下文的渲染隔离逻辑
前端·面试
说实话起个名字真难啊2 小时前
2026数字中国创新大赛数字安全赛道writeup之web题目一
java·前端·安全
jerrywus3 小时前
Claude Code 真正的用法:skill / agent / hooks / worktree 一篇全搞定
前端·agent·claude