ff4cc808c7e03a7e8c6e7eb55f1beb77ff07830ec2beee5d20281957a7db5a65.json 9.3 KB

1
  1. {"ast":null,"code":"import { getEnvSensingList } from '@/api';\nexport default {\n name: 'EnvSensing',\n data() {\n return {\n list: [],\n needScroll: false,\n scrollTimer: null,\n paused: false,\n scrollY: 0\n };\n },\n async mounted() {\n const res = await getEnvSensingList();\n this.list = res.data.list;\n this.$nextTick(() => {\n // 延迟检测,确保DOM完全渲染和布局完成\n setTimeout(() => this.checkScroll(), 300);\n });\n },\n beforeDestroy() {\n if (this.scrollTimer) cancelAnimationFrame(this.scrollTimer);\n },\n methods: {\n checkScroll() {\n const wrapper = this.$refs.listWrapper;\n const inner = this.$refs.listInner;\n if (!wrapper || !inner) return;\n // 内容高度超过容器时开启无缝滚动\n this.needScroll = inner.offsetHeight > wrapper.offsetHeight;\n if (this.needScroll) {\n this.$nextTick(() => {\n setTimeout(() => this.startScroll(), 100);\n });\n }\n },\n startScroll() {\n const wrapper = this.$refs.listWrapper;\n const inner = this.$refs.listInner;\n const scrollContent = this.$refs.scrollContent;\n if (!wrapper || !inner || !scrollContent) return;\n const firstHeight = inner.offsetHeight;\n const speed = 0.4; // px per frame (~24px/s at 60fps)\n this.scrollY = 0;\n const step = () => {\n if (!this.paused) {\n this.scrollY += speed;\n // 当滚动到第一份内容末尾时,无缝回到顶部\n if (this.scrollY >= firstHeight) {\n this.scrollY -= firstHeight;\n }\n scrollContent.style.transform = `translateY(${-this.scrollY}px)`;\n }\n this.scrollTimer = requestAnimationFrame(step);\n };\n this.scrollTimer = requestAnimationFrame(step);\n },\n pauseScroll() {\n this.paused = true;\n },\n resumeScroll() {\n this.paused = false;\n }\n }\n};","map":{"version":3,"names":["getEnvSensingList","name","data","list","needScroll","scrollTimer","paused","scrollY","mounted","res","$nextTick","setTimeout","checkScroll","beforeDestroy","cancelAnimationFrame","methods","wrapper","$refs","listWrapper","inner","listInner","offsetHeight","startScroll","scrollContent","firstHeight","speed","step","style","transform","requestAnimationFrame","pauseScroll","resumeScroll"],"sources":["src/components/LabStats/EnvSensing.vue"],"sourcesContent":["<template>\n <div class=\"panel-box env-sensing\">\n <div class=\"panel-title\">实验环境安全智能感知</div>\n <div class=\"panel-content\">\n <div class=\"list-wrapper\" ref=\"listWrapper\" @mouseenter=\"pauseScroll\" @mouseleave=\"resumeScroll\">\n <div ref=\"scrollContent\" class=\"scroll-content\">\n <div ref=\"listInner\" class=\"list-inner\">\n <div class=\"env-item\" v-for=\"(item, idx) in list\" :key=\"'a'+idx\">\n <div class=\"env-header\">\n <span class=\"env-lab\">{{ item.lab }}</span>\n <span class=\"env-dept\">{{ item.dept }}</span>\n </div>\n <div class=\"env-data\">\n <span class=\"data-tag normal\">温度:{{ item.temp }}°C</span>\n <span class=\"data-tag normal\">湿度:{{ item.humidity }}%</span>\n <span class=\"data-tag normal\">TVOC {{ item.tvoc }}mg/m³</span>\n <span class=\"data-tag\" :class=\"item.co2.warn ? 'warn' : 'normal'\">\n <template v-if=\"item.co2.warn\">△</template>CO₂ {{ item.co2.value }}ppm\n </span>\n <span class=\"data-tag\" :class=\"item.o2.warn ? 'warn' : 'normal'\">\n <template v-if=\"item.o2.warn\">△</template>O₂ {{ item.o2.value }}%\n </span>\n </div>\n </div>\n </div>\n <!-- 复制一份用于无缝滚动 -->\n <div class=\"list-inner\" v-if=\"needScroll\">\n <div class=\"env-item\" v-for=\"(item, idx) in list\" :key=\"'b'+idx\">\n <div class=\"env-header\">\n <span class=\"env-lab\">{{ item.lab }}</span>\n <span class=\"env-dept\">{{ item.dept }}</span>\n </div>\n <div class=\"env-data\">\n <span class=\"data-tag normal\">温度:{{ item.temp }}°C</span>\n <span class=\"data-tag normal\">湿度:{{ item.humidity }}%</span>\n <span class=\"data-tag normal\">TVOC {{ item.tvoc }}mg/m³</span>\n <span class=\"data-tag\" :class=\"item.co2.warn ? 'warn' : 'normal'\">\n <template v-if=\"item.co2.warn\">△</template>CO₂ {{ item.co2.value }}ppm\n </span>\n <span class=\"data-tag\" :class=\"item.o2.warn ? 'warn' : 'normal'\">\n <template v-if=\"item.o2.warn\">△</template>O₂ {{ item.o2.value }}%\n </span>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script>\nimport { getEnvSensingList } from '@/api'\n\nexport default {\n name: 'EnvSensing',\n data() {\n return {\n list: [],\n needScroll: false,\n scrollTimer: null,\n paused: false,\n scrollY: 0\n }\n },\n async mounted() {\n const res = await getEnvSensingList()\n this.list = res.data.list\n this.$nextTick(() => {\n // 延迟检测,确保DOM完全渲染和布局完成\n setTimeout(() => this.checkScroll(), 300)\n })\n },\n beforeDestroy() {\n if (this.scrollTimer) cancelAnimationFrame(this.scrollTimer)\n },\n methods: {\n checkScroll() {\n const wrapper = this.$refs.listWrapper\n const inner = this.$refs.listInner\n if (!wrapper || !inner) return\n // 内容高度超过容器时开启无缝滚动\n this.needScroll = inner.offsetHeight > wrapper.offsetHeight\n if (this.needScroll) {\n this.$nextTick(() => {\n setTimeout(() => this.startScroll(), 100)\n })\n }\n },\n startScroll() {\n const wrapper = this.$refs.listWrapper\n const inner = this.$refs.listInner\n const scrollContent = this.$refs.scrollContent\n if (!wrapper || !inner || !scrollContent) return\n const firstHeight = inner.offsetHeight\n const speed = 0.4 // px per frame (~24px/s at 60fps)\n this.scrollY = 0\n\n const step = () => {\n if (!this.paused) {\n this.scrollY += speed\n // 当滚动到第一份内容末尾时,无缝回到顶部\n if (this.scrollY >= firstHeight) {\n this.scrollY -= firstHeight\n }\n scrollContent.style.transform = `translateY(${-this.scrollY}px)`\n }\n this.scrollTimer = requestAnimationFrame(step)\n }\n this.scrollTimer = requestAnimationFrame(step)\n },\n pauseScroll() { this.paused = true },\n resumeScroll() { this.paused = false }\n }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.env-sensing {\n height: 100%;\n display: flex;\n flex-direction: column;\n\n .panel-content {\n flex: 1;\n overflow: hidden;\n padding: 0;\n }\n}\n\n.list-wrapper {\n height: 100%;\n overflow: hidden;\n padding: 0 14px;\n}\n\n.env-item {\n padding: 10px 0;\n border-bottom: 1px solid rgba(26, 58, 106, 0.3);\n}\n\n.env-header {\n display: flex;\n align-items: baseline;\n gap: 10px;\n margin-bottom: 6px;\n}\n\n.env-lab {\n font-size: 13px;\n font-weight: bold;\n color: #fff;\n}\n\n.env-dept {\n font-size: 11px;\n color: $text-muted;\n}\n\n.env-data {\n display: flex;\n flex-wrap: wrap;\n gap: 6px 10px;\n}\n\n.data-tag {\n font-size: 12px;\n color: $text-secondary;\n\n &.normal {\n background: rgba(15, 45, 77, 0.5);\n border: 1px solid rgba(15, 45, 77, 0.8);\n box-shadow: 0 0 4px rgba(15, 45, 77, 0.4);\n border-radius: 3px;\n padding: 1px 6px;\n }\n\n &.warn {\n color: #f44336;\n font-weight: bold;\n background: rgba(244, 67, 54, 0.08);\n border: 1px solid rgba(244, 67, 54, 0.35);\n box-shadow: 0 0 6px rgba(244, 67, 54, 0.2);\n border-radius: 3px;\n padding: 1px 6px;\n }\n}\n</style>\n"],"mappings":"AAoDA,SAAAA,iBAAA;AAEA;EACAC,IAAA;EACAC,KAAA;IACA;MACAC,IAAA;MACAC,UAAA;MACAC,WAAA;MACAC,MAAA;MACAC,OAAA;IACA;EACA;EACA,MAAAC,QAAA;IACA,MAAAC,GAAA,SAAAT,iBAAA;IACA,KAAAG,IAAA,GAAAM,GAAA,CAAAP,IAAA,CAAAC,IAAA;IACA,KAAAO,SAAA;MACA;MACAC,UAAA,YAAAC,WAAA;IACA;EACA;EACAC,cAAA;IACA,SAAAR,WAAA,EAAAS,oBAAA,MAAAT,WAAA;EACA;EACAU,OAAA;IACAH,YAAA;MACA,MAAAI,OAAA,QAAAC,KAAA,CAAAC,WAAA;MACA,MAAAC,KAAA,QAAAF,KAAA,CAAAG,SAAA;MACA,KAAAJ,OAAA,KAAAG,KAAA;MACA;MACA,KAAAf,UAAA,GAAAe,KAAA,CAAAE,YAAA,GAAAL,OAAA,CAAAK,YAAA;MACA,SAAAjB,UAAA;QACA,KAAAM,SAAA;UACAC,UAAA,YAAAW,WAAA;QACA;MACA;IACA;IACAA,YAAA;MACA,MAAAN,OAAA,QAAAC,KAAA,CAAAC,WAAA;MACA,MAAAC,KAAA,QAAAF,KAAA,CAAAG,SAAA;MACA,MAAAG,aAAA,QAAAN,KAAA,CAAAM,aAAA;MACA,KAAAP,OAAA,KAAAG,KAAA,KAAAI,aAAA;MACA,MAAAC,WAAA,GAAAL,KAAA,CAAAE,YAAA;MACA,MAAAI,KAAA;MACA,KAAAlB,OAAA;MAEA,MAAAmB,IAAA,GAAAA,CAAA;QACA,UAAApB,MAAA;UACA,KAAAC,OAAA,IAAAkB,KAAA;UACA;UACA,SAAAlB,OAAA,IAAAiB,WAAA;YACA,KAAAjB,OAAA,IAAAiB,WAAA;UACA;UACAD,aAAA,CAAAI,KAAA,CAAAC,SAAA,uBAAArB,OAAA;QACA;QACA,KAAAF,WAAA,GAAAwB,qBAAA,CAAAH,IAAA;MACA;MACA,KAAArB,WAAA,GAAAwB,qBAAA,CAAAH,IAAA;IACA;IACAI,YAAA;MAAA,KAAAxB,MAAA;IAAA;IACAyB,aAAA;MAAA,KAAAzB,MAAA;IAAA;EACA;AACA","ignoreList":[]},"metadata":{},"sourceType":"module","externalDependencies":[]}