src/api/index.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/scene/SceneTable.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/utils/chart/chart-option.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/realtimemode/RealtimeMode.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sourcetrace/SourceTrace copy.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sourcetrace/SourceTrace.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sourcetrace/UnderwayAdvice.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sourcetrace/component/ClueRecordItem.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sourcetrace/component/PollutedClueItem.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sourcetrace/component/PollutedExceptionItem.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/index.js
@@ -13,10 +13,10 @@ } if (debug) { // ip1 = 'http://192.168.0.103:8084/'; ip1 = 'http://localhost:8084/'; // ws = `192.168.0.103:9031`; ws = `localhost:9031`; ip1 = 'http://192.168.0.103:8084/'; // ip1 = 'http://localhost:8084/'; ws = `192.168.0.103:9031`; // ws = `localhost:9031`; } const $http = axios.create({ src/components/scene/SceneTable.vue
@@ -29,6 +29,7 @@ <div>{{ parseInt(row.length) + 'ç±³' }}</div> </template> </el-table-column> <slot></slot> <!-- <el-table-column prop="districtName" label="åºå¿" src/utils/chart/chart-option.js
@@ -137,7 +137,7 @@ left: '12%', right: '2%', top: '7%', bottom: '20%' bottom: '30%' }, legend: { show: false src/views/realtimemode/RealtimeMode.vue
@@ -29,7 +29,7 @@ class="source-trace" v-model:factorType="factorType" ></SourceTrace> <UnderwayAdvice></UnderwayAdvice> <!-- <PollutedClueItem></PollutedClueItem> --> </div> </template> @@ -45,6 +45,7 @@ import DeviceChange from './component/DeviceChange.vue'; import SourceTrace from '@/views/sourcetrace/SourceTrace.vue'; import UnderwayAdvice from '@/views/sourcetrace/UnderwayAdvice.vue'; import PollutedClueItem from '@/views/sourcetrace/component/PollutedClueItem.vue'; import { realTimeMapAnimation } from '@/utils/map/animation'; import { fetchHistoryData, @@ -67,7 +68,8 @@ RealTimeTrend, DeviceChange, SourceTrace, UnderwayAdvice UnderwayAdvice, PollutedClueItem }, setup() { const { loading, fetchData } = useFetchData(10000); @@ -142,7 +144,7 @@ // startTime: '2024-12-13 16:35:00', // startTime: '2024-11-27 11:50:41', // Pm, ä¸è·ç¦»å·¥å° // startTime: '2024-08-30 15:28:00', // voc è¿è·ç¦»æ±½ä¿® startTime: '2024-07-23 15:22:00', startTime: '2024-07-23 15:21:30', // startTime: '2024-07-23 14:39:00', endTime: '2025-01-16 11:51:41', page, src/views/sourcetrace/SourceTrace copy.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,345 @@ <template> <el-row> <el-col span="2"> <CardButton direction="left" name="å¨ææº¯æº" @click="() => (show = !show)" ></CardButton> </el-col> <el-col v-show="show" span="10"> <BaseCard> <template #content> <el-scrollbar ref="scrollbarRef" class="scrollbar"> <div ref="scrollContentRef" style="display: flex; width: fit-content" > <TransitionGroup name="list"> <div v-for="(item, index) in streams" :key="index"> <PollutedExceptionItem :item="item" @showMarksAndPolygon="showMarksAndPolygon" ></PollutedExceptionItem> </div> </TransitionGroup> </div> </el-scrollbar> </template> </BaseCard> </el-col> </el-row> </template> <script setup> /** * å¨ææº¯æºä¿¡æ¯ç®¡ç * éè¿websocketæ¹å¼æ¥æ¶å端æ¨éçå¼å¸¸ä¿¡æ¯å¹¶å±ç¤º */ import { reactive, ref, onMounted, onUnmounted, unref } from 'vue'; import websocket from '@/api/websocket'; import sector from '@/utils/map/sector'; import mapUtil from '@/utils/map/util'; import { sceneTypes, sceneIcon } from '@/constant/scene-types'; import marks from '@/utils/map/marks'; import { map, onMapMounted } from '@/utils/map/index_old'; import { FactorDatas } from '@/model/FactorDatas'; import factorDataParser from '@/utils/chart/factor-data-parser'; import websocketMsgParser from '@/views/sourcetrace/websocketMsgParser.js'; import PollutedExceptionItem from './component/PollutedExceptionItem.vue'; const props = defineProps({ factorType: String }); const emits = defineEmits(['update:factorType']); const height = `30vh`; const width = `60vh`; const show = ref(false); const scrollContentRef = ref(); const scrollbarRef = ref(); function scrollToBottom() { const h1 = scrollContentRef.value.clientHeight + 100; setTimeout(() => { scrollbarRef.value.setScrollTop(h1); }, 100); } function scrollToTop() { setTimeout(() => { scrollbarRef.value.setScrollTop(0); }, 100); } const streams = reactive([]); const inputVal = ref(''); const handleSend = () => { websocket.send(inputVal.value); }; let showFirstClueTask; function dealMsg(data) { const { type, content } = websocketMsgParser.parseMsg(data); // 污æçº¿ç´¢ PollutedClue if (type == '1') { const obj = reactive(JSON.parse(content)); // obj.showMore = true; obj.showMore = false; console.log('污æçº¿ç´¢: ', obj); if (streams.length == 0) { streams.push(obj); } else { // streams.forEach((s) => { // showMarksAndPolygon(s); // }); hideAll(); streams.unshift(obj); } show.value = true; // scrollToBottom(); scrollToTop(); // drawPolygon(obj.pollutedArea); parseChartData(obj); if (showFirstClueTask) { clearTimeout(showFirstClueTask); } showFirstClueTask = setTimeout(() => { showMarksAndPolygon(obj); }, 1000); } } onMounted(() => { websocket.registerReceiveEvent(dealMsg); }); onUnmounted(() => { websocket.removeReceiveEvent(dealMsg); sector.clearSectorPt(); mapUtil.clearMap(); // if (layer != undefined) { // mapUtil.removeViews(layer); // layer = undefined; // } }); function hideAll() { streams.forEach((s) => { if (polygonMap.has(s.guid)) { s.showMore = false; map.remove(polygonMap.get(s.guid)); } }); } function showMarksAndPolygon(item) { item.showMore = !item.showMore; if (item.showMore) { hideAll(); item.showMore = true; drawPolygon(item); } else { if (polygonMap.has(item.guid)) { map.remove(polygonMap.get(item.guid)); } } } // ç»å¶æ±¡æåºåï¼é«å¾·å°å¾çå¤è¾¹å½¢å¯¹è±¡ï¼éè¿vueçreactiveå è£ ä¸ºååºå¼å¯¹è±¡åï¼æ æ³æ£ç¡®å¨å°å¾ä¸ä½¿ç¨ï¼ const polygonMap = new Map(); function drawPolygon(item) { const pollutedArea = item.pollutedArea; if (polygonMap.has(item.guid)) { map.add(polygonMap.get(item.guid)); } else { const bounds = pollutedArea.polygon.map((v) => [v.first, v.second]); // eslint-disable-next-line no-undef const pollutedAreaPolygon = new AMap.Polygon({ map: map, //æ¾ç¤ºè¯¥è¦çç©çå°å¾å¯¹è±¡ strokeWeight: 2, //è½®å»çº¿å®½åº¦ path: bounds, //å¤è¾¹å½¢è½®å»çº¿çèç¹åæ æ°ç» fillOpacity: 0, //å¤è¾¹å½¢å¡«å éæåº¦ fillColor: '#CCF3FF', //å¤è¾¹å½¢å¡«å é¢è² strokeColor: '#02ffea', //线æ¡é¢è² // strokeColor: '#0552f7', //线æ¡é¢è² strokeStyle: 'dashed', zIndex: 9 }); polygonMap.set(item.guid, pollutedAreaPolygon); } // map.setFitView(polygonMap.get(item.guid)); } function parseChartData(obj) { // console.log('æçº¿å¾ï¼start'); const factorDatas = new FactorDatas(); factorDatas.setData(obj.pollutedData.historyDataList, 0, () => { obj._chartOptions = factorDataParser.parseData(factorDatas, [ { label: obj.pollutedData.factorName, name: obj.pollutedData.factorName, value: obj.pollutedData.factorId + '' } ]); // console.log('æçº¿å¾ï¼', obj._chartOptions); }); } /******************************************************************************************************************** */ /** * æ·»å 䏿¡å·¥ä½æµä¿¡æ¯ * @param {*} data */ const putWorkStream = (data) => { data.substring(); const obj = JSON.parse(data); console.log('sourcetrace: ', obj); obj._statusStr = exceptionStatus(obj.status); if (streams.length == 0) { streams.push(obj); } else { const index = streams.findIndex((v) => { return v.guid == obj.guid; }); if (index != -1) { const old = streams[index]; obj.showMore = old.showMore; old.relatedSceneList.forEach((s) => { const index = obj.relatedSceneList.findIndex((v) => { return v.guid == s.guid; }); if (index == -1) { obj.relatedSceneList.push(s); } }); streams.splice(index, 1, obj); } else { streams.unshift(obj); } show.value = true; } // scrollToBottom(); scrollToTop(); const excObj = streams.find((v) => { return v.factorId + '' == props.factorType; }); if (excObj) { drawSector(excObj); } }; function exceptionStatus(value) { switch (value) { case 1: return 'å¼å¸¸åçä¸'; case 2: return 'å¼å¸¸å·²ç»æ'; default: return 'å¼å¸¸å·²ç»æ'; } } let lastDrawObjGuid; function drawSector(exceptionObj) { emits('update:factorType', exceptionObj.factorId + ''); setTimeout(() => { if (exceptionObj.guid != lastDrawObjGuid) { sector.clearSectorPt(); lastDrawObjGuid = exceptionObj.guid; } // 1. ç»å¶æ°æå½¢åºå const datavo = exceptionObj.midData; const factorDatas = new FactorDatas(); factorDatas.setData([datavo], 0, () => { const pr = sector.drawSectorPt(factorDatas, 0); // è°æ´è§è§å± 䏿¾ç¤º // mapUtil.setCenter(pr.p); drawMarks(exceptionObj.relatedSceneList); }); }, 1000); } let layer = undefined; function drawMarks(sceneList) { if (layer != undefined) { mapUtil.removeViews(layer); // layer = undefined; } if (sceneList.length != 0) { const icons = []; sceneList.forEach((s) => { icons.push(sceneIcon(s.typeId)); }); layer = marks.createLabelMarks(icons, sceneList, true); } } </script> <style scoped> :deep(.el-statistic) { --el-statistic-title-color: rgb(215, 215, 215); --el-statistic-content-color: white; } :deep(.el-text.el-text--primary) { --el-text-color: white; } :deep(.el-link) { --el-link-text-color: #23dad1; } .scrollbar { min-width: 300px; max-width: 60vw; /* height: 35vh; */ /* color: #02ffea; */ } .clue-card { padding: 0 4px; /* margin-right: 2px; */ width: 340px; height: 35vh; border-right: 1px solid white; border-radius: 2px; } .border-dashed { /* border: 1px dashed white; */ border: 1px dashed #ffbc58; padding: 0px 1px; margin-bottom: 4px; } </style> <style> .list-move, /* 对移å¨ä¸çå ç´ åºç¨çè¿æ¸¡ */ .list-enter-active, .list-leave-active { transition: all 0.5s ease; } .list-enter-from, .list-leave-to { opacity: 0; transform: translateX(-30px); } /* ç¡®ä¿å°ç¦»å¼çå ç´ ä»å¸å±æµä¸å é¤ ä»¥ä¾¿è½å¤æ£ç¡®å°è®¡ç®ç§»å¨çå¨ç»ã */ .list-leave-active { position: absolute; } </style> src/views/sourcetrace/SourceTrace.vue
@@ -1,33 +1,54 @@ <template> <el-row> <el-col span="2"> <el-col span="2" class="flex-col"> <el-row justify="end"> <CardButton direction="left" name="å¨ææº¯æº" @click="() => (show = !show)" ></CardButton> </el-row> <el-row class="flex-col"> <PollutedExceptionItem :item="selectedException" @showMarksAndPolygon="showMarksAndPolygon" ></PollutedExceptionItem> </el-row> </el-col> <el-col v-show="show" span="10"> <BaseCard> <template #content> <el-checkbox-group v-model="selectedMsgTypes" size="default" :min="1"> <el-space> <el-checkbox value="1">å¼å¸¸åç</el-checkbox> <el-checkbox value="2">污æçº¿ç´¢</el-checkbox> </el-space> </el-checkbox-group> <el-scrollbar ref="scrollbarRef" class="scrollbar"> <div <!-- <div ref="scrollContentRef" style="display: flex; width: fit-content" > > --> <TransitionGroup name="list"> <div v-for="(item, index) in streams" :key="index"> <PollutedClueItem <div v-for="item in filterStreams" :key="item.guid ? item.guid : item.time" > <ClueRecordItem :item="item" @showMarksAndPolygon="showMarksAndPolygon" ></PollutedClueItem> @open="handleOpen(item)" ></ClueRecordItem> </div> </TransitionGroup> </div> <!-- </div> --> </el-scrollbar> </template> </BaseCard> </el-col> <PollutedClueItem v-model="clueDialog" :item="selectedClue" ></PollutedClueItem> </el-row> </template> <script setup> @@ -35,7 +56,9 @@ * å¨ææº¯æºä¿¡æ¯ç®¡ç * éè¿websocketæ¹å¼æ¥æ¶å端æ¨éçå¼å¸¸ä¿¡æ¯å¹¶å±ç¤º */ import { reactive, ref, onMounted, onUnmounted, unref } from 'vue'; import { reactive, ref, onMounted, onUnmounted, computed, watch } from 'vue'; import moment from 'moment'; import websocket from '@/api/websocket'; import sector from '@/utils/map/sector'; import mapUtil from '@/utils/map/util'; @@ -46,7 +69,9 @@ import factorDataParser from '@/utils/chart/factor-data-parser'; import websocketMsgParser from '@/views/sourcetrace/websocketMsgParser.js'; import PollutedClueItem from './component/PollutedClueItem.vue'; import PollutedExceptionItem from './component/PollutedExceptionItem.vue'; import ClueRecordItem from './component/ClueRecordItem.vue'; import PollutedClueItem from '@/views/sourcetrace/component/PollutedClueItem.vue'; const props = defineProps({ factorType: String @@ -58,8 +83,13 @@ const width = `60vh`; const show = ref(false); const clueDialog = ref(false); const scrollContentRef = ref(); const scrollbarRef = ref(); const selectedException = ref(); const selectedClue = ref(); const selectedMsgTypes = ref(['1', '2']); function scrollToBottom() { const h1 = scrollContentRef.value.clientHeight + 100; @@ -75,6 +105,11 @@ } const streams = reactive([]); const filterStreams = computed(() => { return streams.filter((v) => { return selectedMsgTypes.value.indexOf(v._type) != -1; }); }); const inputVal = ref(''); const handleSend = () => { @@ -88,32 +123,60 @@ // 污æçº¿ç´¢ PollutedClue if (type == '1') { const obj = reactive(JSON.parse(content)); obj._type = type; // obj.showMore = true; obj.showMore = false; console.log('污æçº¿ç´¢: ', obj); console.log('污æå¼å¸¸åç: ', obj); if (streams.length == 0) { streams.push(obj); } else { // streams.forEach((s) => { // showMarksAndPolygon(s); // }); hideAll(); streams.unshift(obj); } // if (streams.length == 0) { // streams.push(obj); // } else { // // streams.forEach((s) => { // // showMarksAndPolygon(s); // // }); // // hideAll(); // streams.unshift(obj); // } addNewMsg(obj); show.value = true; // scrollToBottom(); scrollToTop(); // scrollToTop(); // drawPolygon(obj.pollutedArea); parseChartData(obj); if (showFirstClueTask) { clearTimeout(showFirstClueTask); // if (showFirstClueTask) { // clearTimeout(showFirstClueTask); // } // showFirstClueTask = setTimeout(() => { // showMarksAndPolygon(obj); // }, 1000); } else if (type == '2') { const obj = JSON.parse(content); obj._type = type; console.log('污æçº¿ç´¢ç»æ: ', obj); obj._timestr = timeFormatter(obj.time); // streams.unshift(obj); addNewMsg(obj); } showFirstClueTask = setTimeout(() => { showMarksAndPolygon(obj); } // æç §ä¸å®æ¶é´é´éæ°å¢ä¸æ¡æ¶æ¯ let addNewMsgTask; const leftMsgList = []; function addNewMsg(msg, inside) { if (!addNewMsgTask && (leftMsgList.length == 0 || inside)) { streams.splice(0, 0, msg); addNewMsgTask = setTimeout(() => { clearTimeout(addNewMsgTask); addNewMsgTask = undefined; if (leftMsgList.length > 0) { const next = leftMsgList.shift(); addNewMsg(next, true); } }, 1000); } else { leftMsgList.push(msg); } } @@ -129,6 +192,32 @@ // layer = undefined; // } }); watch(clueDialog, (nV, oV) => { if (nV != oV && !nV) { selectedClue.value._selected = false; } }); function handleOpen(item) { switch (item._type) { case '1': if (selectedException.value) { selectedException.value._selected = false; } showMarksAndPolygon(item); selectedException.value = item; break; case '2': if (selectedClue.value) { selectedClue.value._selected = false; } selectedClue.value = item; clueDialog.value = true; break; } item._selected = true; } function hideAll() { streams.forEach((s) => { @@ -148,6 +237,7 @@ } else { if (polygonMap.has(item.guid)) { map.remove(polygonMap.get(item.guid)); selectedException.value._selected = false; } } } @@ -190,6 +280,10 @@ ]); // console.log('æçº¿å¾ï¼', obj._chartOptions); }); } function timeFormatter(time) { return moment(time).format('YYYY-MM-DD HH:mm:ss'); } /******************************************************************************************************************** */ @@ -301,11 +395,27 @@ --el-link-text-color: #23dad1; } .el-checkbox { --el-checkbox-text-color: white; --main-color: #23dad1; --el-checkbox-checked-text-color: var(--main-color); --el-checkbox-checked-input-border-color: var(--main-color); --el-checkbox-checked-bg-color: var(--main-color); --el-checkbox-input-border-color-hover: var(--main-color); --el-checkbox-disabled-checked-input-fill: var(--main-color); --el-checkbox-disabled-checked-input-border-color: var(--main-color); --el-checkbox-disabled-checked-icon-color: white; margin-right: 6px; /* height: initial; */ } .scrollbar { min-width: 300px; max-width: 60vw; /* height: 35vh; */ width: 400px; /* max-width: 60vw; */ height: 45vh; /* color: #02ffea; */ padding-right: 10px; } .clue-card { @@ -323,18 +433,24 @@ padding: 0px 1px; margin-bottom: 4px; } .flex-col { display: flex; flex-direction: column; justify-content: space-between; } </style> <style> .list-move, /* 对移å¨ä¸çå ç´ åºç¨çè¿æ¸¡ */ .list-enter-active, .list-leave-active { /* transition: all 0.8s cubic-bezier(0.55, 0, 0.1, 1); */ transition: all 0.5s ease; } .list-enter-from, .list-leave-to { opacity: 0; transform: translateX(30px); transform: scaleY(0.01) translate(300px, 0); } /* ç¡®ä¿å°ç¦»å¼çå ç´ ä»å¸å±æµä¸å é¤ src/views/sourcetrace/UnderwayAdvice.vue
@@ -26,6 +26,9 @@ </el-text> </el-row> </template> --> <el-button icon="Plus" @click="addAdvice"></el-button> <el-button icon="Minus" @click="removeAdvice"></el-button> <el-scrollbar height="200"> <TransitionGroup name="list"> <div v-for="(item, index) in analysisResultList" :key="index"> <template v-if="index == 0"> @@ -73,6 +76,7 @@ </template> </div> </TransitionGroup> </el-scrollbar> </template> <template #footer> </template> </CardDialog> @@ -144,6 +148,14 @@ function timeFormatter(time) { return moment(time).format('YYYY-MM-DD HH:mm:ss'); } function addAdvice() { analysisResultList.unshift(analysisResultList[0]); } function removeAdvice() { analysisResultList.splice(0, 1); } </script> <style scoped> :deep(.el-text) { @@ -155,7 +167,7 @@ /* color: #ffd82a; */ } </style> <style> <!-- <style> .list-move, /* 对移å¨ä¸çå ç´ åºç¨çè¿æ¸¡ */ .list-enter-active, .list-leave-active { @@ -165,7 +177,7 @@ .list-enter-from, .list-leave-to { opacity: 0; transform: translateX(30px); transform: translateX(-30px); } /* ç¡®ä¿å°ç¦»å¼çå ç´ ä»å¸å±æµä¸å é¤ @@ -173,4 +185,4 @@ .list-leave-active { position: absolute; } </style> </style> --> src/views/sourcetrace/component/ClueRecordItem.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,96 @@ <template> <div :class="'wrapper' + (item._selected ? ' wrapper-select' : '')"> <div v-if="item._type == '1'"> <el-row justify="space-between"> <el-space> <el-tag v-if="noWarn" type="info" effect="dark" size="small" >å¼å¸¸</el-tag > <el-tag v-else type="warning" effect="dark" size="small">å¼å¸¸</el-tag> <el-text type="primary">{{ item.pollutedData.startTime + ' - ' + item.pollutedData.endTime }}</el-text> </el-space> <el-link type="primary" @click="emits('open', item)"> 详æ </el-link> </el-row> <el-col :span="24"> <el-text type="primary">{{ item.pollutedData.factorName + formatException(item.pollutedData.exceptionType) + 'ï¼' + formatDistanceType(item.pollutedArea.distanceType) }}</el-text> <el-text :type="noWarn ? 'primary' : 'warning'"> {{ item.pollutedSource.sceneList.length == 0 ? 'æªæ¾å°å¯çæ±¡ææº' : 'æ¾å°' + item.pollutedSource.sceneList.length + '个å¯çæ±¡ææº' }} </el-text> </el-col> <!-- <el-col :span="2"> </el-col> --> </div> <div v-else-if="item._type == '2'"> <el-row justify="space-between"> <el-tag type="danger" effect="dark" size="small">线索</el-tag> <el-link type="primary" @click="emits('open')"> 详æ </el-link> </el-row> <el-text type="danger">{{ item.advice }}</el-text> </div> </div> </template> <script setup> import { computed } from 'vue'; const props = defineProps({ item: Object }); const emits = defineEmits(['open']); const noWarn = computed(() => { return props.item && props.item.pollutedSource.sceneList.length == 0; }); function formatException(value) { switch (value) { case 4: return 'é级çªå'; case 9: return 'å¿«éä¸å'; default: return 'é级çªå'; } } function formatDistanceType(value) { switch (value) { case 'TYPE1': return '50米以å '; case 'TYPE2': return '50ç±³ - 500米以å '; case 'TYPE3': return '50ç±³ - 1å ¬é以å '; case 'TYPE4': return '50ç±³ - 2å ¬é以å '; default: break; } } </script> <style scoped> .wrapper { margin-bottom: 8px; border-bottom: 1px dashed rgba(253, 253, 253, 0.651); } .wrapper-select { background: linear-gradient( rgba(228, 228, 228, 0.274), rgba(64, 165, 248, 0.089) ); } .no-warning { color: var(--el-text-color-disabled) !important; } </style> src/views/sourcetrace/component/PollutedClueItem.vue
@@ -1,222 +1,135 @@ <template> <!-- <BaseCard> <template #content> --> <el-scrollbar class="clue-card"> <el-row justify="space-between"> <!-- <el-tag v-if="index == 0" type="danger">ææ°</el-tag> --> <el-text type="primary">{{ 'åçæ¶é´ï¼' + item.pollutedData.startTime + ' - ' + item.pollutedData.endTime }}</el-text> <el-link type="primary" :underline="true" @click="showMarksAndPolygon(item)" <CardDialog :model-value="modelValue" @update:model-value="handleDialogShow" title="污æçº¿ç´¢" draggable :modal="false" width="400px" > {{ item.showMore ? 'æ¶èµ·å¼å¸¸' : 'å®ä½å¼å¸¸' }} </el-link> </el-row> <div> <el-text type="primary"> 污æåºåï¼{{ item.pollutedArea.address }} </el-text> </div> <div> <el-text type="primary"> 溯æºè·ç¦»ï¼{{ formatDistanceType(item.pollutedArea.distanceType) }} </el-text> </div> <div> <el-text type="primary"> å¼å¸¸ç±»åï¼{{ item.pollutedData.exception }} </el-text> </div> <el-row style="border-top: 1px solid white"> <el-col :span="6"> <el-statistic title="çªåå å" :value="item.pollutedData.factorName" /> </el-col> <el-col :span="6"> <el-statistic v-if="item.pollutedData.exceptionType == 4" title="ååå¹ åº¦" :value="formatPercentage(item.pollutedData.avgPer)" /> <el-statistic v-else-if="item.pollutedData.exceptionType == 9" title="ååéç" :value="formatPercentage(item.pollutedData.avgPer)" /> </el-col> <el-col :span="6"> <el-statistic title="åçæ¬¡æ°" :value="item.pollutedData.times" /> </el-col> <el-col :span="6"> <el-statistic title="å¹³åé£é" :value="item.pollutedData.windSpeed" suffix="m/s" /> </el-col> </el-row> <el-row justify="space-between"> <!-- <el-link type="primary" underline @click="showMarksAndPolygon(item)" > {{ (item.showMore ? 'æ¶èµ·æº¯æºåºæ¯' : 'æ¥ç溯æºåºæ¯') + 'ï¼' + item.pollutedSource.sceneList.length + 'ï¼' }} </el-link> --> </el-row> <!-- <div style="width: 320px; height: 80px"> --> <RealTimeLineChart v-for="(item1, index1) in item._chartOptions" :key="index1" :model-value="item1" chart-height="80px" ></RealTimeLineChart> <!-- </div> --> <div class="border-dashed"> <el-text type="" tag="mark"> {{ item.pollutedSource.conclusion }} </el-text> </div> <SceneTable :show-marks="item.showMore" :scene-list="item.pollutedSource.sceneList" ></SceneTable> <!-- <el-space gap="4"> <el-tag :type="item.status == 1 ? 'danger' : 'info'">{{ item._statusStr }}</el-tag> <el-text type="default">{{ item.exception }}</el-text> </el-space> <el-row gap="4"> <el-text type="primary">åçæ¶é´ï¼</el-text> <el-text type="primary">{{ item.startTime + ' è³ ' }}</el-text> <el-text type="primary">{{ item.status == 1 ? 'å½å' : item.endTime }}</el-text> </el-row> <template #default> <template v-if="item"> <el-row> <el-col :span="6"> <el-statistic title="å å" :value="item.factorName" /> </el-col> <el-col :span="6"> <el-statistic title="åå¼" :value="item.avg" /> </el-col> <el-col :span="6"> <el-statistic title="å³°å¼" :value="item.max" /> </el-col> <el-col :span="6"> <el-statistic title="è°·å¼" :value="item.min" /> </el-col> <el-text type="primary" size="small">{{ item._timestr }}</el-text> </el-row> <el-space> <el-icon color="#F56C6C" :size="40"><WarnTriangleFilled /></el-icon> <el-text type="primary"> {{ item.advice }} </el-text> </el-space> <el-row justify="space-between"> <el-link type="primary" @click="item.showMore = !item.showMore" > {{ (item.showMore ? 'æ¶èµ·æº¯æºåºæ¯' : 'æ¥ç溯æºåºæ¯') + 'ï¼' + item.relatedSceneList.length + 'ï¼' }} </el-link> <el-link type="primary" @click="drawSector(item)"> æ¥çå¼å¸¸ <el-text type="primary" size="small"> æ¨è路线æ»é¿{{ item.direction.distance }}ç±³ </el-text> <el-link type="primary" size="small" @click="showPolyline"> {{ lineShow ? 'æ¶èµ·è·¯çº¿' : 'å®ä½è·¯çº¿' }} </el-link> </el-row> <SceneTable v-show="item.showMore" :scene-list="item.relatedSceneList" ></SceneTable> <el-divider /> --> </el-scrollbar> <!-- </template> </BaseCard> --> :show-marks="lineShow" :scene-list="formatSceneList(item.sortedSceneList)" > <el-table-column prop="_count" width="42" label="æº¯æºæ¬¡æ°" /> </SceneTable> </template> </template> <template #footer> </template> </CardDialog> </template> <script setup> import { ref } from 'vue'; import { ref, onMounted, onUnmounted, reactive, watch } from 'vue'; import { sceneTypes, sceneIcon } from '@/constant/scene-types'; import mapLine from '@/utils/map/line'; import mapUtil from '@/utils/map/util'; import marks from '@/utils/map/marks'; const props = defineProps({ modelValue: Boolean, item: Object }); const emits = defineEmits(['showMarksAndPolygon']); const lineShow = ref(true); // ä¸ä¸æ¡å¯¼èªè·¯çº¿ let lastPolyline = undefined; // ä¸ä¸ä¸ªå¯¼èªç®çå° // let lastDestination = undefined; // let layer = undefined; function showMarksAndPolygon(item) { emits('showMarksAndPolygon', item); const emits = defineEmits(['update:modelValue']); watch( () => [props.item, props.modelValue], (nV, oV) => { if (nV[0] != oV[0]) { const polyline = mapLine.drawDirection( nV[0].direction.paths.map((v) => [v.first, v.second]) ); // polylineList.unshift(polyline); if (lastPolyline) { mapUtil.removeViews(lastPolyline); } lastPolyline = polyline; lineShow.value = true; } else if (nV[1]) { showPolyline(true); } } ); function showPolyline(show) { if (typeof show === 'boolean') { lineShow.value = show; } else { lineShow.value = !lineShow.value; } function formatPercentage(value) { return Math.round(value * 100) + '%'; } function formatDistanceType(value) { switch (value) { case 'TYPE1': return '50ç±³'; case 'TYPE2': return '50ç±³ - 500ç±³'; case 'TYPE3': return '50ç±³ - 1å ¬é'; case 'TYPE4': return '50ç±³ - 2å ¬é'; default: break; if (lineShow.value && lastPolyline) { mapUtil.addViews(lastPolyline); } else { mapUtil.removeViews(lastPolyline); } } function formatChangeRate() { // function removeLayer() { // if (layer != undefined) { // mapUtil.removeViews(layer); // layer = undefined; // } // } // function drawMarks(sceneList) { // removeLayer(); // if (sceneList.length != 0) { // const icons = []; // sceneList.forEach((s) => { // icons.push(sceneIcon(s.typeId)); // }); // layer = marks.createLabelMarks(icons, sceneList, false); // } // } function formatSceneList(sceneList) { return sceneList.map((v) => { return { ...v.first, _count: v.second }; }); } function handleDialogShow(value) { showPolyline(value); emits('update:modelValue', value); } </script> <style scoped> :deep(.el-statistic) { --el-statistic-title-color: rgb(215, 215, 215); --el-statistic-content-color: white; } :deep(.el-text.el-text--primary) { /* :deep(.el-text.el-text--primary) { --el-text-color: white; } :deep(.el-link) { --el-link-text-color: #23dad1; } .scrollbar { min-width: 300px; max-width: 60vw; /* height: 35vh; */ /* color: #02ffea; */ } .clue-card { padding: 0 4px; /* margin-right: 2px; */ width: 340px; height: 35vh; border-right: 1px solid white; border-radius: 2px; } .border-dashed { /* border: 1px dashed white; */ border: 1px dashed #ffbc58; padding: 0px 1px; margin-bottom: 4px; } } */ </style> src/views/sourcetrace/component/PollutedExceptionItem.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,237 @@ <template> <!-- <CardDialog :model-value="modelValue" @update:model-value="handleDialogShow" title="污æå¼å¸¸" draggable :modal="false" > <template #default> --> <BaseCard v-if="item" v-show="item.showMore"> <template #content> <el-scrollbar class="clue-card"> <el-row justify="space-between"> <!-- <el-tag v-if="index == 0" type="danger">ææ°</el-tag> --> <el-text type="primary">{{ 'åçæ¶é´ï¼' + item.pollutedData.startTime + ' - ' + item.pollutedData.endTime }}</el-text> <el-link type="primary" :underline="true" @click="showMarksAndPolygon(item)" > {{ item.showMore ? 'æ¶èµ·å¼å¸¸' : 'å®ä½å¼å¸¸' }} </el-link> </el-row> <div> <el-text type="primary"> 污æåºåï¼{{ item.pollutedArea.address }} </el-text> </div> <div> <el-text type="primary"> 溯æºè·ç¦»ï¼{{ formatDistanceType(item.pollutedArea.distanceType) }} </el-text> </div> <div> <el-text type="primary"> å¼å¸¸ç±»åï¼{{ item.pollutedData.exception }} </el-text> </div> <el-row style="border-top: 1px solid white"> <el-col :span="6"> <el-statistic title="çªåå å" :value="item.pollutedData.factorName" /> </el-col> <el-col :span="6"> <el-statistic v-if="item.pollutedData.exceptionType == 4" title="ååå¹ åº¦" :value="formatPercentage(item.pollutedData.avgPer)" /> <el-statistic v-else-if="item.pollutedData.exceptionType == 9" title="ååéç" :value="formatChangeRate(item.pollutedData.avgRate)" suffix="" /> </el-col> <el-col :span="6"> <el-statistic title="åçæ¬¡æ°" :value="item.pollutedData.times" /> </el-col> <el-col :span="6"> <el-statistic title="å¹³åé£é" :value="item.pollutedData.windSpeed" suffix="m/s" /> </el-col> </el-row> <el-row justify="space-between"> <!-- <el-link type="primary" underline @click="showMarksAndPolygon(item)" > {{ (item.showMore ? 'æ¶èµ·æº¯æºåºæ¯' : 'æ¥ç溯æºåºæ¯') + 'ï¼' + item.pollutedSource.sceneList.length + 'ï¼' }} </el-link> --> </el-row> <!-- <div style="width: 320px; height: 80px"> --> <RealTimeLineChart v-for="(item1, index1) in item._chartOptions" :key="index1" :model-value="item1" chart-height="80px" ></RealTimeLineChart> <!-- </div> --> <div class="border-dashed"> <el-text type="" tag="mark"> {{ item.pollutedSource.conclusion }} </el-text> </div> <SceneTable :show-marks="item.showMore" :scene-list="item.pollutedSource.sceneList" ></SceneTable> <!-- <el-space gap="4"> <el-tag :type="item.status == 1 ? 'danger' : 'info'">{{ item._statusStr }}</el-tag> <el-text type="default">{{ item.exception }}</el-text> </el-space> <el-row gap="4"> <el-text type="primary">åçæ¶é´ï¼</el-text> <el-text type="primary">{{ item.startTime + ' è³ ' }}</el-text> <el-text type="primary">{{ item.status == 1 ? 'å½å' : item.endTime }}</el-text> </el-row> <el-row> <el-col :span="6"> <el-statistic title="å å" :value="item.factorName" /> </el-col> <el-col :span="6"> <el-statistic title="åå¼" :value="item.avg" /> </el-col> <el-col :span="6"> <el-statistic title="å³°å¼" :value="item.max" /> </el-col> <el-col :span="6"> <el-statistic title="è°·å¼" :value="item.min" /> </el-col> </el-row> <el-row justify="space-between"> <el-link type="primary" @click="item.showMore = !item.showMore" > {{ (item.showMore ? 'æ¶èµ·æº¯æºåºæ¯' : 'æ¥ç溯æºåºæ¯') + 'ï¼' + item.relatedSceneList.length + 'ï¼' }} </el-link> <el-link type="primary" @click="drawSector(item)"> æ¥çå¼å¸¸ </el-link> </el-row> <SceneTable v-show="item.showMore" :scene-list="item.relatedSceneList" ></SceneTable> <el-divider /> --> </el-scrollbar> </template> </BaseCard> <!-- </template> </CardDialog> --> </template> <script setup> import { ref } from 'vue'; const props = defineProps({ modelValue: Boolean, item: Object }); const emits = defineEmits(['showMarksAndPolygon', 'update:modelValue']); function showMarksAndPolygon(item) { emits('showMarksAndPolygon', item); } function formatPercentage(value) { return Math.round(value * 100) + '%'; } function formatDistanceType(value) { switch (value) { case 'TYPE1': return '50ç±³'; case 'TYPE2': return '50ç±³ - 500ç±³'; case 'TYPE3': return '50ç±³ - 1å ¬é'; case 'TYPE4': return '50ç±³ - 2å ¬é'; default: break; } } function formatChangeRate(value) { return Math.round(value * 100) / 100 + ''; } </script> <style scoped> :deep(.el-statistic) { --el-statistic-title-color: rgb(215, 215, 215); --el-statistic-content-color: white; } :deep(.el-text.el-text--primary) { --el-text-color: white; } :deep(.el-link) { --el-link-text-color: #23dad1; } .scrollbar { min-width: 300px; max-width: 60vw; /* height: 35vh; */ /* color: #02ffea; */ } .clue-card { padding: 0 4px; /* margin-right: 2px; */ width: 340px; height: 35vh; border-right: 1px solid white; border-radius: 2px; } .border-dashed { /* border: 1px dashed white; */ border: 1px dashed #ffbc58; padding: 0px 1px; margin-bottom: 4px; } </style>