2 Commitit 25e7644eed ... b19fdeeb6b

Tekijä SHA1 Viesti Päivämäärä
  YangJian0701 b19fdeeb6b 0416 3 kuukautta sitten
  YangJian0701 fb7950c1ea 0416 3 kuukautta sitten

+ 8 - 0
package.json

@@ -17,13 +17,21 @@
   },
   "dependencies": {
     "@element-plus/icons-vue": "2.3.1",
+<<<<<<< HEAD
+    "@jiaminghi/data-view": "^2.10.0",
+=======
     "@kjgl77/datav-vue3": "^1.7.4",
+>>>>>>> 25e7644eedaba5882506f3898abaee6bcb67295e
     "@vueup/vue-quill": "1.2.0",
     "@vueuse/core": "10.11.0",
     "axios": "0.28.1",
     "clipboard": "2.0.11",
+<<<<<<< HEAD
+    "echarts": "^5.6.0",
+=======
     "echarts": "5.5.1",
     "echarts-liquidfill": "^3.1.0",
+>>>>>>> 25e7644eedaba5882506f3898abaee6bcb67295e
     "element-plus": "2.7.6",
     "file-saver": "2.0.5",
     "fuse.js": "6.6.2",

BIN
src/assets/images/content_circle.png


BIN
src/assets/images/content_circle_num.png


BIN
src/assets/images/table_row_bg.png


+ 58 - 0
src/components/layout_/index.vue

@@ -0,0 +1,58 @@
+<template>
+    <div class="_layout">
+        <div class="_layout_mains">
+            <div class="_layout_mains_item _layout_mains_left">
+                <slot name="left"></slot>
+            </div>
+            <div class="_layout_mains_content">
+                <slot name="content"></slot>
+            </div>
+            <div class="_layout_mains_item _layout_mains_right">
+                <slot name="right"></slot>
+            </div>
+        </div>
+        
+    </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+</script>
+<style lang="scss">
+._layout {
+    height: 100%;
+    box-sizing: border-box;
+    display: flex;
+    &_mains{
+        flex: 1;
+        margin-top: 46px;
+        margin-bottom:76px;
+        position: relative;
+        display: flex;
+        &_item {
+            height: 100%;
+            width: 25%;
+            position: absolute;
+            top: 0;
+            background: rgba(#021130,0.8);
+        }
+
+        &_left{
+            left: 0;
+        }
+        &_right{
+            right: 0;
+        }
+        &_content {
+            flex: 1;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: #fff;
+            font-weight: bold;
+            font-size: 100px;
+        }
+    }
+    
+}
+</style>

+ 0 - 2
src/main.js

@@ -7,7 +7,6 @@ import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
 import 'element-plus/theme-chalk/dark/css-vars.css'
 import locale from 'element-plus/es/locale/lang/zh-cn'
-
 import '@/assets/styles/index.scss' // global css
 
 import App from './App'
@@ -44,7 +43,6 @@ import ImagePreview from "@/components/ImagePreview"
 import DictTag from '@/components/DictTag'
 
 const app = createApp(App)
-
 // 全局方法挂载
 app.config.globalProperties.useDict = useDict
 app.config.globalProperties.download = download

+ 24 - 0
src/views/system/elevator/index.vue

@@ -0,0 +1,24 @@
+<template>
+   <div class="_energy">
+    <layout>
+        <template #left>
+            <p>这是插槽的内容</p> 
+        </template>
+        <template #content>
+            <p>电梯</p>
+        </template>
+        <template #right>
+            <p>这是右侧插槽的内容</p>
+        </template>
+    </layout>
+   </div>
+</template>
+
+<script setup name="Role">
+import layout from "@/components/layout_/index.vue";
+</script> 
+<style lang="scss">
+._energy{
+    height: 100%;
+}
+</style>

+ 24 - 0
src/views/system/energy/index.vue

@@ -0,0 +1,24 @@
+<template>
+   <div class="_energy">
+    <layout>
+        <template #left>
+            <p>这是插槽的内容</p> 
+        </template>
+        <template #content>
+            <p>能源</p>
+        </template>
+        <template #right>
+            <p>这是右侧插槽的内容</p>
+        </template>
+    </layout>
+   </div>
+</template>
+
+<script setup name="Role">
+import layout from "@/components/layout_/index.vue";
+</script> 
+<style lang="scss">
+._energy{
+    height: 100%;
+}
+</style>

+ 36 - 0
src/views/system/lighting/index.vue

@@ -0,0 +1,36 @@
+<template>
+   <div class="_energy">
+    <layout>
+        <template #left>
+            <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
+                <deviceList/>
+            </div>
+        </template>
+        <template #content>
+            <p>照明</p>
+        </template>
+        <template #right>
+            <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
+                <running style="flex: 1;"/>
+                <switchAll  style="flex: 1;"/>
+               <eventList style="flex: 1;"/>
+            </div>
+        </template>
+    </layout>
+   </div>
+</template>
+
+<script setup name="Role">
+import layout from "@/components/layout_/index.vue";
+import deviceList from './modules/deviceList.vue'
+import running from './modules/running.vue'
+import eventList from './modules/eventList.vue'
+import switchAll from './modules/switchAll.vue'
+
+
+</script> 
+<style lang="scss">
+._energy{
+    height: 100%;
+}
+</style>

+ 122 - 0
src/views/system/lighting/modules/deviceList.vue

@@ -0,0 +1,122 @@
+<template>
+    <div class="_deviceList">
+        <HeadlineTag value="设备列表" style="flex-shrink: 0;"></HeadlineTag>
+        <div class="_deviceList_mains" ref="mainsRef" @mouseenter="pauseCarousel" @mouseleave="resumeCarousel">
+            <div :style="{ transform: `translateY(${scrollY}px)` }">
+                <div class="_deviceList_mains_item" v-for="(item, index) in eventList" :key="index">
+                    <el-text class="w-150px mb-2 _table_row1" truncated style="color: white;flex: .4;">
+                        <el-icon color="#168cdb">
+                            <el-icon><Opportunity /></el-icon>
+                        </el-icon>
+                        {{ item.name }}
+                    </el-text>
+                    <el-text class="w-150px mb-2" truncated style="color: white;flex: .2;">
+                        {{ item.state }}
+                    </el-text>
+                    <el-text class="w-150px mb-2" truncated style="color: white;flex: .2">
+                        {{ item.flag }}
+                    </el-text>
+                    <el-icon color="#168cdb" style="flex: .2;">
+                        <el-icon><Aim /></el-icon>
+                    </el-icon>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from "vue";
+import HeadlineTag from '@/components/HeadlineTag'
+import { Opportunity, Aim } from '@element-plus/icons-vue'
+
+const eventList = ref([
+    { name: '回路1', state: '开启', flag: '在线' },
+    { name: '回路2', state: '关闭', flag: '离线' },
+    { name: '回路3', state: '开启', flag: '在线' },
+    { name: '回路4', state: '关闭', flag: '离线' },
+    { name: '回路5', state: '开启', flag: '在线' },
+    { name: '回路6', state: '关闭', flag: '离线' },
+    { name: '回路7', state: '开启', flag: '在线' },
+    { name: '回路8', state: '关闭', flag: '离线' },
+    { name: '回路9', state: '开启', flag: '在线' },
+    { name: '回路10', state: '关闭', flag: '离线' },
+    { name: '回路11', state: '开启', flag: '在线' },
+    { name: '回路12', state: '关闭', flag: '离线' },
+    { name: '回路13', state: '开启', flag: '在线' },
+    { name: '回路14', state: '关闭', flag: '离线' },
+    { name: '回路15', state: '开启', flag: '在线' },
+    { name: '回路16', state: '关闭', flag: '离线' },
+    { name: '回路17', state: '开启', flag: '在线' },
+    { name: '回路18', state: '关闭', flag: '离线' },
+    { name: '回路19', state: '开启', flag: '在线' },
+    { name: '回路20', state: '关闭', flag: '离线' },
+    { name: '回路21', state: '开启', flag: '在线' },
+    { name: '回路22', state: '关闭', flag: '离线' },
+    { name: '回路23', state: '开启', flag: '在线' },
+    { name: '回路24', state: '关闭', flag: '离线' }
+])
+
+const mainsRef = ref(null)
+const scrollY = ref(0)
+let intervalId = null
+const scrollSpeed = 1 // 滚动速度
+
+const startCarousel = () => {
+    intervalId = setInterval(() => {
+        const itemHeight = mainsRef.value?.querySelector('._deviceList_mains_item')?.offsetHeight;
+        if (!itemHeight) return;
+
+        scrollY.value -= scrollSpeed;
+
+        // 检查第一个元素是否完全离开视口
+        if (Math.abs(scrollY.value) >= itemHeight) {
+            // 将第一个元素移到列表末尾
+            const firstItem = eventList.value.shift();
+            if (firstItem) {
+                eventList.value.push(firstItem);
+            }
+            // 调整滚动位置
+            scrollY.value += itemHeight;
+        }
+    }, 20);
+};
+
+const pauseCarousel = () => {
+    clearInterval(intervalId);
+};
+
+const resumeCarousel = () => {
+    startCarousel();
+};
+
+onMounted(() => {
+    startCarousel();
+});
+
+onUnmounted(() => {
+    clearInterval(intervalId);
+});
+</script>
+
+<style lang="scss">
+._deviceList{
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    &_mains{
+        margin:10px 30px;
+        overflow: hidden; // 隐藏溢出内容
+        cursor: pointer;
+        &_item{
+            display: flex;
+            justify-content: space-between;
+            padding: 10px;
+        }
+        &_item:hover{
+            cursor: pointer;
+            background-image: linear-gradient(to right, #168cdb, transparent); 
+        }
+    }
+}
+</style>

+ 148 - 0
src/views/system/lighting/modules/eventList.vue

@@ -0,0 +1,148 @@
+<template>
+    <div class="_eventList">
+        <HeadlineTag value="事件列表" style="flex-shrink: 0;"></HeadlineTag>
+        <!-- 绑定鼠标移入移出事件 -->
+        <div class="_eventList_mains" ref="mainsRef" @mouseenter="pauseCarousel" @mouseleave="resumeCarousel">
+            <!-- 复制一份数据用于无缝滚动 -->
+            <div :style="{ transform: `translateY(${scrollY}px)` }">
+                <div class="_eventList_mains_item" v-for="(item, index) in eventList.concat(eventList)" :key="index">
+                    <div class="_eventList_mains_item_text">
+                        <div
+                        :class="item.store === 'on' ? '_success' : '_warning'"
+                        class="_eventList_mains_item_text_flag"></div>
+                        <el-text class="w-150px mb-2" truncated style="color: white;margin-left: 10px;">
+                            {{ item.name }}
+                        </el-text>
+                    </div>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.time }}
+                    </el-text>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from "vue";
+import HeadlineTag from '@/components/HeadlineTag'
+
+const eventList = ref([{
+    store: 'on',
+    color: 'rgb(82.4, 155.2, 46.4)',
+    name: '设备启动1',
+    time: '2025-04-15 10:20:00'
+}, {
+    store: 'on',
+    color: 'rgb(82.4, 155.2, 46.4)',
+    name: '设备启动2',
+    time: '2025-04-15 10:20:00'
+}, {
+    store: 'off',
+    color: 'red',
+    name: '设备停止3',
+    time: '2025-04-15 10:20:00'
+}, {
+    store: 'on',
+    color: 'rgb(82.4, 155.2, 46.4)',
+    name: '设备启动4',
+    time: '2025-04-15 10:20:00'
+}, {
+    store: 'off',
+    color: 'red',
+    name: '设备停止5',
+    time: '2025-04-15 10:20:00'
+}, {
+    store: 'off',
+    color: 'red',
+    name: '设备停止6',
+    time: '2025-04-15 10:20:00'
+}, {
+    store: 'on',
+    color: 'rgb(82.4, 155.2, 46.4)',
+    name: '设备启动7',
+    time: '2025-04-15 10:20:00'
+}, {
+    store: 'off',
+    color: 'red',
+    name: '设备停止8',
+    time: '2025-04-15 10:20:00'
+}])
+
+const mainsRef = ref(null)
+const scrollY = ref(0)
+let intervalId = null
+const scrollSpeed = 1 // 滚动速度
+
+const startCarousel = () => {
+    intervalId = setInterval(() => {
+        const itemHeight = mainsRef.value.querySelector('._eventList_mains_item').offsetHeight
+        scrollY.value -= scrollSpeed
+        if (Math.abs(scrollY.value) >= itemHeight * eventList.value.length) {
+            scrollY.value = 0
+        }
+    }, 20)
+}
+
+const pauseCarousel = () => {
+    clearInterval(intervalId)
+}
+
+const resumeCarousel = () => {
+    startCarousel()
+}
+
+onMounted(() => {
+    startCarousel()
+})
+
+onUnmounted(() => {
+    clearInterval(intervalId)
+})
+</script>
+
+<style lang="scss">
+._success {
+    background: #15acaa;	
+}
+._warning {
+    background: #FFC107;	
+}
+._eventList {
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+
+    &_mains {
+        margin: 10px 30px;
+        overflow: hidden; // 隐藏溢出内容
+        // 鼠标移入时改变手势
+        cursor: pointer;
+
+        &_item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 10px 0;
+
+            &_text {
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+                &_flag {
+                    width: 10px;
+                    height: 10px;
+                    border-radius: 50%;
+                    margin-left: 10px; 
+                }
+                &_p {
+                    margin-left: 10px;
+                }
+            }
+        }
+        &_item:hover {
+            background-image: linear-gradient(to right, #168cdb, transparent); 
+        }
+    }
+}
+</style>

+ 113 - 0
src/views/system/lighting/modules/running.vue

@@ -0,0 +1,113 @@
+<template>
+    <div class="_running">
+        <HeadlineTag value="运行统计"></HeadlineTag>
+
+        <div class="_running_mains">
+            <div class="_running_mains_left">
+                <div class="_running_mains_left_tuan"></div>
+
+                <div class="_running_mains_left_conter">
+                    <div class="_running_mains_left_conter_num">62</div>
+                    <div class="_running_mains_left_conter_text">设备总数</div>
+                </div>
+            </div>
+            <div class="_running_mains_right">
+                <div class="_running_mains_right_item" v-for="item,index in runningList" :key="index">
+                    <div class="_running_mains_right_item_tuan">
+                        <span class="_running_mains_right_item_tuan_flag" :style="{backgroundColor: item.color}"></span>
+                        <el-text class="w-150px mb-2" truncated style="color: #ccc;">
+                            {{item.name}}
+                        </el-text>
+                    </div>
+                    <div class="_running_mains_right_item__txt">
+                        {{item.state}}
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import HeadlineTag from '@/components/HeadlineTag'
+const runningList = ref([
+    { name:'开启数量', state:'61', color:'#15acaa'},
+    { name:'关闭数量', state:'1', color:'#FFC107'},
+    { name:'故障数量', state:'0', color:'#F44336'}
+])
+</script>
+<style lang="scss">
+._running {
+    &_mains {
+        margin: 30px;
+        display: flex;
+        align-items: center;
+        &_left {
+            width: 150px;
+            height: 150px;
+            position: relative;
+            &_tuan{
+                width: 100%;
+                height: 100%;
+                background: url("@/assets/images/content_circle.png");
+                background-size: 100% 100%;
+                background-position: center;
+                background-repeat: no-repeat;
+                animation: scanning 4s linear infinite;
+            }
+            &_conter {
+                position: absolute;
+                left: 0;
+                top: 0;
+            	flex-shrink: 0;
+                width: 100%;
+                height: 100%;
+                display: flex;
+                flex-direction: column;
+                align-items: center;
+                justify-content: center;
+                color: #fff;
+                &_num {
+                    font-size: 18px;
+                }
+                &_text {
+                    font-size: 12px;
+                }	
+            }
+        }
+        &_right {
+            margin-left:10px;
+           flex: 1;
+           color: #fff;
+           &_item{
+                display: flex;
+                align-items: center; 
+                gap: 40px;
+                padding: 5px 0;
+                &_tuan {
+                    display: flex;
+                    align-items: center; 
+                    &_flag{
+                        display: block;
+                        width: 7px;
+                        height: 7px;
+                        border-radius: 50%;
+                        margin-right: 10px;
+                    }
+                }
+                &__txt{
+                    font-size:24px;
+                }
+            }
+        }
+
+        
+    }
+}
+@keyframes scanning {
+		to {
+			transform: rotate(1turn);
+		}
+	}
+</style>

+ 185 - 0
src/views/system/lighting/modules/switchAll.vue

@@ -0,0 +1,185 @@
+<template>
+    <div class="_switchAll">
+        <HeadlineTag value="运行分析"></HeadlineTag>
+        <div class="_switchAll_mains">
+            <div ref="chartRef" style="width: 100%; height: 100%;"></div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from 'vue';
+import * as echarts from 'echarts';
+import HeadlineTag from '@/components/HeadlineTag';
+
+const chartRef = ref(null);
+let chart = null;
+
+const generateRandomData = (length, max) => {
+    const randomData = [];
+    for (let i = 0; i < length; i++) {
+        randomData.push(Math.floor(Math.random() * max));
+    }
+    return randomData;
+};
+
+const handleResize = () => {
+    if (chart) {
+        chart.resize();
+    }
+};
+
+onMounted(() => {
+    if (chartRef.value) {
+        chart = echarts.init(chartRef.value);
+
+        const option = {
+            title: null, 
+            tooltip: {
+                trigger: 'axis'
+            },
+            legend: false, 
+            // 调整 grid 配置以在 Y 轴方向拉伸图表
+            grid: {
+                top: '20%', // 减小顶部边距,让图表向上扩展
+                bottom: '20%' // 减小底部边距,让图表向下扩展
+            },
+            xAxis: {
+                type: 'category',
+                data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
+                axisLabel: {
+                    color: '#fff' 
+                },
+            },
+            yAxis: {
+                type: 'value',
+                axisTick: {
+                    show: false // 不显示刻度线
+                },
+                axisLabel: {
+                    show: false // 不显示刻度标签
+                },
+                splitLine: {
+                    show: true // 显示网格线
+                }
+            },
+            yAxis: {
+                type: 'value',
+                axisLabel: {
+                    show: true, // 不显示刻度标签
+                    color: '#fff' 
+                },
+                // 配置 Y 轴网格刻线
+                splitLine: {
+                    show: false, // 显示网格刻线
+                    lineStyle: {
+                        color: '#44585e' // 设置网格刻线颜色 
+                    }
+                },
+                axisTick: {
+                    show: false // 不显示刻度线
+                },
+            },
+            series: [
+                {
+                    name: '开启数量',
+                    type: 'line',
+                    smooth: true,
+                    data: generateRandomData(7, 50),
+                    lineStyle: {
+                        color: '#15acaa'
+                    },
+                    showSymbol: false 
+                },
+                {
+                    name: '关闭数量',
+                    type: 'line',
+                    smooth: true,
+                    data: generateRandomData(9, 60), 
+                    lineStyle: {
+                        color: '#FFC107'
+                    },
+                    showSymbol: false 
+                },
+                {
+                    name: '故障数量',
+                    type: 'line',
+                    smooth: true,
+                    data: generateRandomData(5, 30), 
+                    lineStyle: {
+                        color: '#F44336'
+                    },
+                    showSymbol: false 
+                }
+            ]
+        };
+
+        chart.setOption(option);
+    }
+    window.addEventListener('resize', handleResize);
+});
+
+onUnmounted(() => {
+    window.removeEventListener('resize', handleResize);
+    if (chart) {
+        chart.dispose();
+    }
+});
+</script>
+
+<style lang="scss">
+._divider{
+    height: 1px;
+    border: 1px dashed #168cdb;
+    flex: 1;
+    margin: 0 10px;
+}
+._switchAll{
+    display: flex;
+    flex-direction: column;
+    &_mains{
+        margin:10px 30px;
+        flex: 1;
+        display: flex;
+        &_item{
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 10px;
+            &_name{
+                width: 30px;
+                height: 30px;
+                background: url("@/assets/images/content_circle_num.png");
+                background-size: 100% 100%;
+                background-position: center;
+                background-repeat: no-repeat;
+                // animation: scanning 4s linear infinite;
+                border: 1px solid red; 
+            }
+            &_flag{
+                display: flex;
+                align-items: center;
+                gap: 3px;
+                &_item{
+                    width: 30px;
+                    height: 30px;
+                    border: 3px dashed #168cdb;
+                    box-sizing: border-box;
+                    background:#0e6ead;
+                    color: #fff;
+                    border-radius: 50%;
+                    display: flex;
+                    align-items: center;
+                    justify-content: center;
+                    font-size: 14px;
+                }
+            }
+        }
+        &_item:hover{
+            cursor: pointer;
+            background-image: linear-gradient(to right, #168cdb, transparent); 
+        }
+    }
+}
+
+</style>

+ 24 - 0
src/views/system/video/index.vue

@@ -0,0 +1,24 @@
+<template>
+   <div class="_energy">
+    <layout>
+        <template #left>
+            <p>这是插槽的内容</p> 
+        </template>
+        <template #content>
+            <p>视频</p>
+        </template>
+        <template #right>
+            <p>这是右侧插槽的内容</p>
+        </template>
+    </layout>
+   </div>
+</template>
+
+<script setup name="Role">
+import layout from "@/components/layout_/index.vue";
+</script> 
+<style lang="scss">
+._energy{
+    height: 100%;
+}
+</style>