From ff82e86becbd200adabd2ce56fba1f6b3c6c37e1 Mon Sep 17 00:00:00 2001 From: Riku <risaku@163.com> Date: 星期一, 23 六月 2025 23:10:49 +0800 Subject: [PATCH] 2025.6.23 --- src/views/management/TaskSummary.vue | 126 +++- src/views/visualization/SubtaskVisual.vue | 281 ++++++---- src/components/inspection/SceneDevice.vue | 498 ++++++++++++++++++ src/views/visualization/SupervisionVisual.vue | 8 src/views/management/TaskStats.vue | 13 src/components.d.ts | 5 src/api/fysp/mediafileApi.js | 18 src/api/index.js | 15 src/main.js | 5 src/components/FYImageSelectDialog.vue | 304 +++++++++++ src/components/inspection/ProblemItem.vue | 10 src/components/inspection/TaskItem.vue | 219 +++++--- src/views/main/MonitorView.vue | 42 + src/api/fysp/deviceApi.js | 20 src/components/BaseCard.vue | 2 15 files changed, 1,303 insertions(+), 263 deletions(-) diff --git a/src/api/fysp/deviceApi.js b/src/api/fysp/deviceApi.js new file mode 100644 index 0000000..953c7b7 --- /dev/null +++ b/src/api/fysp/deviceApi.js @@ -0,0 +1,20 @@ +import { $fysp } from '../index'; + +export default { + // 鑾峰彇璁惧 + fetchDevices(sceneId, deviceTypeId) { + const params = `?sceneId=${sceneId}&deviceTypeId=${deviceTypeId}`; + return $fysp + .get(`device${params}`) + .then((res) => res) + .then((res) => res.data); + }, + // 鑾峰彇璁惧鐘舵�佷互鍙婅澶囪鎯� + fetchDeviceStatus({ deviceId, sceneId, deviceTypeId }) { + const params = `?deviceId=${deviceId}&sceneId=${sceneId}&deviceTypeId=${deviceTypeId}`; + return $fysp + .get(`device/status${params}`) + .then((res) => res) + .then((res) => res.data); + } +}; diff --git a/src/api/fysp/mediafileApi.js b/src/api/fysp/mediafileApi.js new file mode 100644 index 0000000..eb2c27b --- /dev/null +++ b/src/api/fysp/mediafileApi.js @@ -0,0 +1,18 @@ +import { $fysp } from '../index'; + +export default { + /** + * 鑾峰彇宸℃煡涓殑浠绘剰鍥剧墖 + */ + getRoutineByStGuid(stGuid) { + const params = `?stGuid=${stGuid}`; + return $fysp.get(`mediafile/routine${params}`).then((res) => res.data); + }, + getRoutineByiGuid(iGuid) { + const params = `?iGuid=${iGuid}`; + return $fysp.get(`mediafile/routine${params}`).then((res) => res.data); + }, + updateMediaFile(mediafile) { + return $fysp.post('mediafile', mediafile).then((res) => res.data); + } +}; diff --git a/src/api/index.js b/src/api/index.js index 3a2b325..a501280 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -41,11 +41,11 @@ i.interceptors.request.use( function (config) { // 鍦ㄥ彂閫佽姹備箣鍓嶅仛浜涗粈涔� - console.log('==>璇锋眰寮�濮�') - console.log(`${config.baseURL}${config.url}`) - if (config.data) { - console.log('==>璇锋眰鏁版嵁', config.data) - } + // console.log('==>璇锋眰寮�濮�') + // console.log(`${config.baseURL}${config.url}`) + // if (config.data) { + // console.log('==>璇锋眰鏁版嵁', config.data) + // } return config }, function (error) { @@ -65,6 +65,11 @@ function (response) { // 2xx 鑼冨洿鍐呯殑鐘舵�佺爜閮戒細瑙﹀彂璇ュ嚱鏁般�� // 瀵瑰搷搴旀暟鎹仛鐐逛粈涔� + console.log('==>璇锋眰寮�濮�') + console.log(`${response.config.baseURL}${response.config.url}`) + if (response.config.data) { + console.log('==>璇锋眰鏁版嵁', response.config.data) + } console.log(response) console.log('==>璇锋眰缁撴潫') if (response.status == 200) { diff --git a/src/components.d.ts b/src/components.d.ts index 5103eec..3f60b91 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -19,6 +19,7 @@ ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDivider: typeof import('element-plus/es')['ElDivider'] + ElEmpty: typeof import('element-plus/es')['ElEmpty'] ElIcon: typeof import('element-plus/es')['ElIcon'] ElImage: typeof import('element-plus/es')['ElImage'] ElLink: typeof import('element-plus/es')['ElLink'] @@ -32,14 +33,18 @@ ElStatistic: typeof import('element-plus/es')['ElStatistic'] ElTable: typeof import('element-plus/es')['ElTable'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] + ElTabPane: typeof import('element-plus/es')['ElTabPane'] + ElTabs: typeof import('element-plus/es')['ElTabs'] ElTag: typeof import('element-plus/es')['ElTag'] ElText: typeof import('element-plus/es')['ElText'] + FYImageSelectDialog: typeof import('./components/FYImageSelectDialog.vue')['default'] OptionLocation: typeof import('./components/search/OptionLocation.vue')['default'] OptionSceneType: typeof import('./components/search/OptionSceneType.vue')['default'] OptionTime: typeof import('./components/search/OptionTime.vue')['default'] ProblemItem: typeof import('./components/inspection/ProblemItem.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] + SceneDevice: typeof import('./components/inspection/SceneDevice.vue')['default'] SubtaskExamineItem: typeof import('./components/inspection/SubtaskExamineItem.vue')['default'] SubtaskItem: typeof import('./components/inspection/SubtaskItem.vue')['default'] TaskItem: typeof import('./components/inspection/TaskItem.vue')['default'] diff --git a/src/components/BaseCard.vue b/src/components/BaseCard.vue index dbf4a2c..0a2f89d 100644 --- a/src/components/BaseCard.vue +++ b/src/components/BaseCard.vue @@ -20,7 +20,7 @@ </el-row> </el-space> <!-- <Transition name="el-zoom-in-left"> --> - <div class="m-t-8" v-if="show"> + <div class="m-t-8" v-show="show"> <slot></slot> </div> <!-- </Transition> --> diff --git a/src/components/FYImageSelectDialog.vue b/src/components/FYImageSelectDialog.vue new file mode 100644 index 0000000..965b0c8 --- /dev/null +++ b/src/components/FYImageSelectDialog.vue @@ -0,0 +1,304 @@ +<template> + <!-- <el-dialog + :model-value="dialogVisible" + @opened="handleOpen" + @closed="handleClose" + top="5vh" + width="68%" + destroy-on-close + :close-on-press-escape="false" + > --> + <!-- <el-row justify="end"> + <el-text v-if="onContextMenu != undefined" size="small" type="info">{{ + `锛�${contextMenuStr}锛塦 + }}</el-text> + <div v-if="!readonly"> + <el-text size="small" type="info" class="m-r-8" + >鏈�澶氶�夋嫨{{ maxSelect }}寮犲浘鐗�</el-text + > + <el-button + size="small" + type="primary" + @click="handleSubmit" + :disabled="selectedImgUrlList.length == 0" + >纭畾</el-button + > + <el-button size="small" type="primary" @click="handleCancel" + >鍙栨秷</el-button + > + </div> + </el-row> --> + + <div class="center"> + <el-tabs v-if="typeList.length > 0" v-model="activeId" type="card"> + <el-tab-pane + v-for="item in typeList" + :key="item.typeId" + :label="item.typeName + ' (' + typeImgMap.get(item.typeId).length + ')'" + :name="item.typeId" + > + </el-tab-pane> + </el-tabs> + <el-scrollbar :height="height"> + <div v-if="typeImgMap.get(activeId) && typeImgMap.get(activeId).length > 0" class="imgs"> + <el-image + v-loading="img.loading" + v-for="(img, i) in typeImgMap.get(activeId)" + :key="i" + :class="[img.isSelect ? 'selected' : 'noActive', 'image']" + :style="`width: ${imageWidth}px;height: ${imageWidth}px;`" + fit="cover" + :src="img.url" + :preview-src-list="readonly ? typeImgMap.get(activeId).map((v) => v.url) : []" + :initial-index="i" + @contextmenu="(e) => showContextMenu(e, i)" + @click="onSelect(img, i)" + @load="onOneImgLoadSuccess(img)" + @error="onOneImgLoadError(img)" + /> + </div> + <el-row v-else justify="space-between"> + <el-empty description="鏆傛棤璁板綍" /> + </el-row> + </el-scrollbar> + </div> + <!-- </el-dialog> --> +</template> +<script setup> +import { ref, watch, computed, onMounted, onUnmounted } from 'vue' + +const props = defineProps({ + dialogVisible: Boolean, + /** + * 鍥剧墖鍒嗙被 + * 缁撴瀯{ typeId, typeName } + */ + typeList: { + type: Array, + default: () => [] + }, + typeImgMap: { + type: Array, + default: () => new Map() + }, + // 鏄惁浠ュ彧璇荤殑褰㈠紡鏌ョ湅褰撳墠椤甸潰 + readonly: { + type: Boolean, + default: false + }, + // 鍥剧墖鍙�夋暟閲忥紝褰撲紶鍏ユ暟瀛楁椂锛屼唬琛ㄥ浘鐗囨暟閲� + maxSelect: { + type: Number, + default: 3 + }, + // 鍥剧墖鍙抽敭鐐瑰嚮浜嬩欢 + onContextMenu: { + type: Function + }, + contextMenuStr: { + type: String, + default: '鍙抽敭鐐瑰嚮鍥剧墖瑙﹀彂棰濆鎿嶄綔' + }, + height: { + type: String, + default: '70vh' + }, + imageWidth: { + type: Number, + default: 240 + } +}) + +const emit = defineEmits(['submit', 'cancel', 'update:dialogVisible']) + +const activeId = ref('') + +const selectedImgUrlList = ref([]) + +let loadedImgCount = ref(0) +// 鍔犺浇鐘舵�� +const loading = computed(() => { + if (activeId.value == '') { + return false + } + // 淇濊瘉鏈�寮�濮嬫槸鍔犺浇鐘舵�侊紝涓夊垎涔嬩竴鍔犺浇涔嬪悗鍋滄灞曠ず鍔犺浇鐘舵�� + return !(props.typeImgMap.get(activeId.value).length / 3 <= loadedImgCount.value) +}) +function onOneImgLoadError(img) { + img.loading = false + loadedImgCount.value++ +} +function onOneImgLoadSuccess(img) { + img.loading = false + loadedImgCount.value++ +} +watch( + () => activeId.value, + (nV, oV) => { + loadedImgCount.value = 0 + }, + { immediate: true } +) + +function onSelect(img, i) { + if (props.readonly) { + return + } + const imgList = selectedImgUrlList.value + const index = imgList.indexOf(img) + if (index == -1) { + if (props.maxSelect == 1) { + img.isSelect = true + imgList.push(img) + if (imgList.length > 1) { + imgList.splice(0, 1).forEach((e) => { + e.isSelect = false + }) + } + } else if (props.maxSelect > 1) { + if (imgList.length < props.maxSelect) { + img.isSelect = true + imgList.push(img) + } + } + } else { + imgList.splice(index, 1) + img.isSelect = false + } +} +function handleOpen() { + emit('update:dialogVisible', true) +} +function handleClose() { + selectedImgUrlList.value.forEach((item) => (item.isSelect = false)) + selectedImgUrlList.value = [] + emit('update:dialogVisible', false) +} +function handleSubmit() { + emit('submit', selectedImgUrlList.value) + emit('update:dialogVisible', false) +} + +function handleCancel() { + emit('cancel') + emit('update:dialogVisible', false) +} + +// 鍥剧墖鍙抽敭鐐瑰嚮鏃堕棿 +function showContextMenu(event, index) { + if (props.onContextMenu) { + event.preventDefault() + props.onContextMenu(event, activeId.value, index) + } +} + +watch( + () => props.typeList, + (nV, oV) => { + if (nV != oV && nV.length > 0) { + activeId.value = nV[0].typeId + } + }, + { immediate: true } +) +</script> +<style scoped> +.center { + display: flex; + flex-direction: column; + align-items: center; +} +.text { + padding: 20px; +} + +.main { + /* 浣跨埗鍏冪礌灞呬腑 */ + /* margin: 0 auto; */ + /* width: 100%; */ +} + +.imgs { + width: 100%; + /* border-style:solid; + border-radius: 1px; */ + /* height: 100%; */ + flex-grow: 1 !important; + overflow-y: auto !important; + /* 鍐呭鐨勫唴杈硅窛 */ + display: flex !important; + flex-wrap: wrap !important; + /* overflow: hidden; */ +} + +.image { + margin: 5px; + /* height: 250px; + width: 240px; */ + border-radius: 4px; +} + +.selected { + margin: 3px; + color: #4abe84; + box-shadow: 0 2px 7px 0 rgba(85, 110, 97, 0.35); + border: 2px solid rgba(74, 190, 132, 1); +} + +.selected:before { + content: ''; + position: absolute; + right: 0; + bottom: 0; + border: 17px solid #4abe84; + border-top-color: transparent; + border-left-color: transparent; +} + +.selected:after { + content: ''; + width: 5px; + height: 12px; + position: absolute; + right: 6px; + bottom: 6px; + border: 2px solid #fff; + border-top-color: transparent; + border-left-color: transparent; + transform: rotate(45deg); +} + +.noActive { + /* padding: 5px; */ +} + +.blurry { + filter: blur(3px); +} +.filters { + display: flex; + padding: 5px; +} + +::v-deep .el-dialog__body { + padding: 10px calc(var(--el-dialog-padding-primary) + 10px) !important; +} + +:deep(.el-tabs__item) { + /* color: var(--el-text-color-info); */ +} + +:deep(.el-tabs__item.is-active) { + color: var(--el-color-warning); +} + +:deep(.el-tabs--card > .el-tabs__header .el-tabs__nav) { + border: 1px solid rgba(255, 255, 255, 0.541); +} +:deep(.el-tabs--card > .el-tabs__header .el-tabs__item) { + border-left: 1px solid rgba(255, 255, 255, 0.541); +} +:deep(.el-tabs--card > .el-tabs__header .el-tabs__item:first-child) { + border-left: none; +} +</style> diff --git a/src/components/inspection/ProblemItem.vue b/src/components/inspection/ProblemItem.vue index 34c195d..21f6a57 100644 --- a/src/components/inspection/ProblemItem.vue +++ b/src/components/inspection/ProblemItem.vue @@ -1,7 +1,7 @@ <template> <div> - <el-text tag="b" type="warning" size="small">{{ index }}. </el-text> - <el-text type="warning" size="small">{{ title }}</el-text> + <el-text tag="b" size="large">{{ index }}. </el-text> + <el-text size="large">{{ title }}</el-text> </div> <!-- <div> <el-text>{{ proStatus.name }}</el-text> @@ -9,7 +9,7 @@ <template v-for="(pic, t) in pics" :key="t"> <template v-if="pic.path.length > 0"> <div> - <el-text size="small" type="info">{{ pic.title }}</el-text> + <el-text size="default" type="info">{{ pic.title }}</el-text> </div> <el-space> <el-image @@ -61,8 +61,8 @@ </script> <style scoped> .image { - width: 60px; - height: 60px; + width: 134px; + height: 134px; border-radius: 2px; } </style> diff --git a/src/components/inspection/SceneDevice.vue b/src/components/inspection/SceneDevice.vue new file mode 100644 index 0000000..18a8f77 --- /dev/null +++ b/src/components/inspection/SceneDevice.vue @@ -0,0 +1,498 @@ +<template> + <!-- <CompGenericWrapper type="drawer"> + <template #content> --> + <!-- 閫夐」 --> + <!-- 璁惧绫诲瀷 --> + <el-row> + <el-col> + <el-tabs class="child_select" placeholder="璁惧绫诲瀷" v-model="currSelect.topDeviceTypeId"> + <el-tab-pane v-for="item in deviceTopTypes" :key="item.id" :name="item.id"> + <template #label> + <el-badge :value="item.count" :type="item.count == 0 ? 'danger' : 'primary'"> + <span class="custom-tabs-label"> + <span>{{ item.label }}</span> + </span> + </el-badge> + </template> + </el-tab-pane> + </el-tabs> + </el-col> + </el-row> + <el-collapse v-model="activeNames" style="border: 4px"> + <el-collapse-item + v-for="item in formInfo" + :key="item.id" + :name="item.id" + class="collapse-item-class" + > + <template #title> + <div style="display: flex; width: 100%; justify-content: space-between"> + <div style=""> + <el-descriptions style="" :column="3" size="small" border> + <el-descriptions-item + width="64px" + :label="currSelect.topDeviceTypeId == 0 ? '绔欑偣鍚嶇О' : '璁惧鍚嶇О'" + :span="3" + >{{ item.name || '鏃�' }}</el-descriptions-item + > + <el-descriptions-item label="渚涘簲鍟�">{{ + item.supplier || '鏃�' + }}</el-descriptions-item> + <el-descriptions-item label="杩愮淮鍟�">{{ + item.maintainer || '鏃�' + }}</el-descriptions-item> + <el-descriptions-item label="杩愮淮棰戞"> + <el-select + v-model="item.maintainFrequency" + :disabled="isDisabled" + style="width: 150px" + > + <el-option + v-for="frequency of maintainFrequencysArray" + :key="frequency.key" + :label="frequency.value" + :value="frequency.key" + ></el-option> + </el-select> + </el-descriptions-item> + <el-descriptions-item label="杩愮淮浜哄憳">{{ + item.maintainStaff || '鏃�' + }}</el-descriptions-item> + <el-descriptions-item label="杩愮淮鑱旂郴鏂瑰紡">{{ + item.maintainTel || '鏃�' + }}</el-descriptions-item> + <el-descriptions-item label="鍝佺墝鍨嬪彿">{{ + item.brandModel || '鏃�' + }}</el-descriptions-item> + <el-descriptions-item label="杩愯鐘舵��"> + <el-select v-model="item.runningStatus" :disabled="isDisabled" style="width: 150px"> + <el-option + v-for="status of runStatusArray" + :key="status.key" + :label="status.value" + :value="status.key" + ></el-option> + </el-select> + </el-descriptions-item> + <el-descriptions-item label="绫诲瀷"> + {{ item._typename || '鏃�' }} + </el-descriptions-item> + </el-descriptions> + </div> + + <div style="display: flex"> + <!-- <div class="sub-title">{{ item.name }}</div> --> + <!-- 鍥剧墖 --> + <div class="image-container"> + <div + class="block-div" + @click="onClickPic($event)" + v-for="(status, index) in item._statusList" + :key="index" + > + <el-image + v-if="index == 0" + fit="cover" + class="pic-style" + :src="status._picUrl" + :preview-src-list="Array.of(status._picUrl)" + /> + <span class="abstract_pic_text" v-if="index == 0">{{ + `鏈�鏂扮姸鎬佸浘鐗� ${status.dlCreateTime.slice(0, 10)}` + }}</span> + </div> + </div> + </div> + </div> + </template> + <!-- 璇︾粏鍐呭寮�濮� --> + <el-form :model="item" class="form_class"> + <el-form-item label="鐘舵��"> + <el-tabs tab-position="top"> + <el-tab-pane + v-for="(status, i) in item._statusList" + :label="status.dlCreateTime.slice(0, 10)" + :key="i" + > + <el-form :model="status" class="form-class"> + <el-form-item label="浣嶇疆" style="margin-bottom: 10px"> + {{ status.dlLocation }} + </el-form-item> + <el-form-item label="鍥剧墖"> + <!-- 鍥剧墖 --> + <el-space> + <div v-if="status._paths && status._paths.length > 0"> + <el-image + v-for="(path, i) in status._paths" + fit="cover" + class="pic-style" + :src="path" + :preview-src-list="Array.of(path)" + :key="i" + /> + </div> + <el-empty v-else></el-empty> + </el-space> + </el-form-item> + </el-form> + </el-tab-pane> + </el-tabs> + </el-form-item> + </el-form> + <!-- 璇︾粏鍐呭缁撴潫 --> + </el-collapse-item> + </el-collapse> + <!-- 绌虹姸鎬� --> + <el-empty v-if="isEmpty" /> + <!-- </template> + </CompGenericWrapper> --> +</template> + +<script> +import deviceApi from '@/api/fysp/deviceApi' +import { $fysp } from '@/api/index' +import { toLabel } from '@/enum/device/device' +export default { + components: {}, + props: { + scene: Object + }, + watch: { + // 閫夋嫨鏀瑰彉鐩戝惉 + currSelect: { + handler(newObj, oldObj) { + this.getList() + }, + deep: true + } + }, + data() { + return { + activeNames: [], + // 鎺у埗鏄惁灞曠ず绌虹姸鎬� + isEmpty: false, + // 璇︽儏鎸夐挳澶у皬 + detailSize: '22px', + // 琛ㄥ崟璇︽儏鐐瑰嚮鎸夐挳鐨勫浘鏍� + isDetail: false, + currSelect: { + topDeviceTypeId: 0 + }, + // 鎺у埗琛ㄥ崟鏄惁鍙互缂栬緫 + isDisabled: true, + formInfo: {}, + rules: [], + // 璁惧绫诲瀷 + deviceTopTypes: [ + { id: 0, label: '鐩戞帶璁惧' }, + { id: 1, label: '娌荤悊璁惧' }, + { id: 2, label: '鐢熶骇璁惧' } + ], + // 杩愯鐘舵�� + runStatusArray: [ + { key: 0, value: '鏈仈缃�' }, + { key: 1, value: '涓婄嚎涓�' }, + { key: 2, value: '涓嬬嚎' }, + { key: 3, value: '鎷嗛櫎' } + ], + // 缁存姢棰戠巼鐘舵�� + maintainFrequencysArray: [ + { key: 1, value: '姣忔湀涓�娆�' }, + { key: 2, value: '姣忓搴︿竴娆�' }, + { key: 3, value: '姣忓崐骞翠竴娆�' }, + { key: 4, value: '姣忓勾涓�娆�' } + ], + // 绉熻祦鏂瑰紡 + ownershipArray: [ + { key: 0, value: '璐拱' }, + { key: 1, value: '绉熻祦' } + ], + scene: {} + } + }, + + mounted() {}, + methods: { + // 鑾峰彇褰撳墠绫诲瀷璁惧鏁伴噺 + getTabsCount() { + this.deviceTopTypes.forEach((item) => { + deviceApi.fetchDevices(this.scene.guid, item.id).then((result) => { + item.count = result.data.length + }) + }) + }, + // 鑾峰彇杩愯鐘舵�佸搴旂殑value + getRunStatusValueByRunStatusKey(status) { + var runningStatusValueArray = this.runStatusArray.filter((runStatus) => { + return runStatus.key == status + }) + if (runningStatusValueArray.length > 0) { + return runningStatusValueArray[0].value + } + }, + // 灞曠ず琛ㄥ崟鐨勮鎯呯殑鐐瑰嚮浜嬩欢 + showDetail(item) { + item._isDetail = !item._isDetail + }, + init(scene) { + // 鐖剁粍浠朵富鍔ㄨ皟鐢ㄥ垵濮嬪寲瀛愮粍浠剁殑鏂规硶 + this.scene = scene + + this.getList() + this.getTabsCount() + }, + // 閲嶇疆灞曠ず鐨勬暟鎹� + initList() { + this.formInfo = [] + this.isEmpty = false + }, + // 鏍囧噯鍖栧睘鎬у悕 + convertKeys(obj) { + // 灏嗕竴涓猨s瀵硅薄涓墍鏈塪i锛寃i锛宲i寮�澶寸殑灞炴�у叏閮ㄦ敼鎴愬幓鎺夎繖浜涘墠缂�骞朵笖閲嶆柊鍙樹负椹煎嘲寮忓懡鍚� + const newObj = {} + for (const key in obj) { + let newKey = key + if (key.startsWith('di')) { + newKey = key.substring(2) + } else if (key.startsWith('wi')) { + newKey = key.substring(2) + } else if (key.startsWith('pi')) { + newKey = key.substring(2) + } + newKey = newKey.charAt(0).toLowerCase() + newKey.slice(1) + newObj[newKey] = obj[key] + } + return newObj + }, + // 鏂板瀛楁 + initFormData(data) { + data._isDetail = false + }, + getList() { + deviceApi.fetchDevices(this.scene.guid, this.currSelect.topDeviceTypeId).then((result) => { + this.initList() + if (result.data == null || result.data.length <= 0) { + this.isEmpty = true + return + } + // 鏍囧噯鍖栧睘鎬у悕 + for (let index = 0; index < result.data.length; index++) { + var element = this.convertKeys(result.data[index]) + this.initFormData(element) + // 鑾峰彇璁惧鐘舵�佷俊鎭� + let data = { + deviceId: element.id, + sceneId: element.sceneGuid, + deviceTypeId: this.currSelect.topDeviceTypeId + } + deviceApi.fetchDeviceStatus(data).then((status) => { + var statusData = status.data + var imgPaths = [] + if (statusData) { + if (statusData.length == 0) { + this.formInfo.push(element) + return + } + element = this.convertKeys(result.data[index]) + element = this.setDeviceType(element) + element._picUrls = imgPaths + for (let index = 0; index < statusData.length; index++) { + const statusItem = statusData[index] + // 璁惧瀵硅薄娣诲姞涓�涓睘鎬у垪琛ㄥ睘鎬х敤鏉ヤ繚瀛樿澶囩姸鎬� + this.saveStatus(element, statusItem) + element.dlLocation = statusItem.dlLocation + this.formInfo.push(element) + } + } + }) + } + }) + }, + setDeviceType(element) { + var type = [] + type = toLabel(element.sceneTypeId, this.currSelect.topDeviceTypeId, [ + element.typeId, + element.subtypeId + ]) + element._typename = type.join('-') + return element + }, + // 淇濆瓨鐘舵�佷俊鎭� + saveStatus(device, status) { + var _picUrl = $fysp.imgUrl + status.dlPicUrl + status._picUrl = _picUrl + status._paths = _picUrl.split(';') + device._picUrls.push(_picUrl) + if ('_statusList' in device) { + device._statusList.push(status) + } else { + device._statusList = Array.of(status) + } + // 鎺掑簭 + device._statusList.sort(function (x, y) { + return new Date(x.dlCreateTime) - new Date(y.dlCreateTime) // 闄嶅簭锛屽崌搴忓垯鍙嶄箣 + }) + }, + submit() {}, + cancel() {}, + modifyObjectKeys(obj) { + const newObj = {} + for (const key in obj) { + // 璺宠繃浠� 'dl' 鎴� '_' 寮�澶寸殑灞炴�� + if (key.startsWith('dl') || key.startsWith('_')) { + newObj[key] = obj[key] + continue + } + // 鏍规嵁 topDeviceTypeId 娣诲姞鍓嶇紑 + let prefix = '' + switch (this.currSelect.topDeviceTypeId) { + case 0: + prefix = 'di' + break + case 1: + prefix = 'pi' + break + case 2: + prefix = 'wi' + break + default: + // 濡傛灉 topDeviceTypeId 涓嶆槸 0, 1, 鎴� 2锛屼笉娣诲姞鍓嶇紑 + newObj[key] = obj[key] + continue + } + + // 娣诲姞鍓嶇紑骞惰浆鎹负椹煎嘲寮忓懡鍚� + const newKey = `${prefix}${key.charAt(0).toUpperCase() + key.slice(1)}` + newObj[newKey] = obj[key] + } + return newObj + }, + // 鐢熸垚鎺ュ彛鍙傛暟 + generateQuery(obj) { + // 闇�瑕佹牴鎹満鏅被鍨嬬‘瀹氭帴鍙e弬鏁扮殑灞炴�у悕 + var query = this.modifyObjectKeys(obj) + return query + }, + onClickPic(e, item) { + e.stopPropagation() + } + } +} +</script> + +<style scoped> +.image-container { + justify-content: flex-end; + display: flex; + /* width: 300px; */ + /* flex-direction: row-reverse; */ + /* height: 225px; */ + /* overflow: hidden; 纭繚鍥剧墖涓嶄細瓒呭嚭瀹瑰櫒 */ +} +.pic-style { + width: 150px; + height: 150px; + border-radius: 4px; +} +.card-style { + height: 400px; + margin-bottom: 10px; + border-color: rgba(0, 0, 0, 0.308); +} +.centerDiv { + text-align: center; /* 姘村钩灞呬腑 */ +} +.dot { + position: absolute; + top: 0; + right: 0; + width: 10px; + height: 10px; + background-color: #f56c6c; + border-radius: 50%; +} +.abstract_main { + width: 98%; +} +.abstract_main_item { + display: flex; + flex-direction: column; + margin-right: 50px; + margin-top: 10px; + /* width: 20%; */ +} +.abstract_other_item { + /* display: flex; + flex-direction: column; */ + /* margin-left: 50px; */ + /* margin-top: 10px; + width: 100vh; */ +} +.abstract_main_item_inner { + display: flex; + justify-content: center; +} +.abstract_other_item_inner { + margin-left: 10px; + display: flex; +} +.abstract_main_title { + /* margin-left: -400px; */ + color: #303133; + font-size: 16px; +} +.abstract_main_title { + color: #606266; + font-size: 13px; + margin-top: 10px; +} +.abstract_other_title { + color: #606266; + font-size: 13px; + margin-top: 45px; +} +.abstract_main_text { + color: #303133; + font-size: 17px; + margin-top: 5px; +} +.abstract_pic_text { + display: block; + color: var(--el-text-color-secondary); + font-size: 14px; + /* margin-top: 20px; */ +} +.block-div { + display: block; +} +.form_class { + /* margin-left: 10px; */ +} + +.el-collapse { + /* 鎶樺彔闈㈡澘鎶樺彔鏃剁殑楂樺害 */ + --el-collapse-header-height: auto; +} +.el-collapse-item__header { + width: 100%; +} +.form-class { + width: 50vw; +} +.form-item-class { + margin-bottom: 10px; +} +.sub-title { + font-size: var(--el-font-size-large); + margin-bottom: 30px; + margin-left: 20px; +} +.collapse-item-class { + height: 100%; + border: 5px; +} + +::-webkit-scrollbar { + height: 0; +} +</style> diff --git a/src/components/inspection/TaskItem.vue b/src/components/inspection/TaskItem.vue index 433d7d1..dcd6f49 100644 --- a/src/components/inspection/TaskItem.vue +++ b/src/components/inspection/TaskItem.vue @@ -1,43 +1,69 @@ <template> - <div v-if="value"> - <el-row justify="start"> - <el-text>{{ value.name }}</el-text> + <div v-if="value" class="wrapper"> + <el-row justify="center"> + <el-text size="large">{{ value.districtName }}</el-text> + <!-- <el-tag type="info">{{ value.districtName }}</el-tag> --> </el-row> <div> - <el-text>鎬婚噺</el-text> - <el-text v-if="value._totaltask > 0" size="default">{{ - value._completetask + '/' + value._totaltask - }}</el-text> - <el-text v-else size="default">{{ value.completetask + '/' + value.totaltask }}</el-text> - <el-progress - style="width: 300px" - type="line" - status="warning" - :text-inside="true" - :stroke-width="18" - :striped="percentFormat(value.completetask, value.totaltask) < 100" - striped-flow - :percentage="percentFormat(value.completetask, value.totaltask)" - > - <template #default="{ percentage }"> - <span class="percentage-value">{{ percentage }}%</span> - </template> - </el-progress> + <div class="text_title">瀹炴柦杩涘害</div> + <template v-if="value._totaltask > 0"> + <el-space> + <!-- <el-text size="default">{{ value._completetask + '/' + value._totaltask }}</el-text> --> + <el-text>鎬昏</el-text> + <el-progress + style="width: 350px" + type="line" + status="warning" + :text-inside="true" + :stroke-width="22" + :striped="percentFormat(value._completetask, value._totaltask) < 100" + striped-flow + :percentage="percentFormat(value._completetask, value._totaltask)" + > + <template #default="{ percentage }"> + <span class="percentage-value">{{ + `${value._completetask}/${value._totaltask} (${percentage}%)` + }}</span> + </template> + </el-progress> + </el-space> + </template> + <template v-else> + <el-space> + <!-- <el-text size="default">{{ value.completetask + '/' + value.totaltask }}</el-text> --> + <el-text>鎬昏</el-text> + <el-progress + style="width: 350px" + type="line" + status="warning" + :text-inside="true" + :stroke-width="22" + :striped="percentFormat(value.completetask, value.totaltask) < 100" + striped-flow + :percentage="percentFormat(value.completetask, value.totaltask)" + > + <template #default="{ percentage }"> + <span class="percentage-value">{{ + `${value.completetask}/${value.totaltask} (${percentage}%)` + }}</span> + </template> + </el-progress> + </el-space> + </template> </div> <!-- </el-col> --> <!-- <el-col span="12" class="flex-bottom"> --> <!-- <div>{{ name }}</div> --> <!-- <div>{{ planTime }}</div> --> <!-- <div>{{ userName }}</div> --> - <el-row class="m-t-8"> - <div - align="center" - :style="'width: ' + 300 / value.count.length + 'px'" - v-for="item in value.count" - :key="item.sceneType" - > + <!-- :style="'width: ' + 300 / value.count.length + 'px'" --> + <!-- <el-row class="m-t-8"> --> + <div v-for="item in value.count" :key="item.sceneType"> + <el-space v-if="item.finish > 0"> + <el-text size="default" truncated>{{ item.sceneType }}</el-text> <el-progress - :stroke-width="18" + :style="'width:' + width" + :stroke-width="16" status="exception" :text-inside="true" :striped="percentFormat(item.finish, item.total) < 100" @@ -45,72 +71,85 @@ :percentage="percentFormat(item.finish, item.total)" > <template #default="{ percentage }"> - <span class="percentage-value-small">{{ percentage }}%</span> + <span class="percentage-value-small">{{ + `${item.finish}/${item.total} (${percentage}%)` + }}</span> </template> </el-progress> - <el-text size="small" truncated>{{ item.sceneType }}</el-text> <!-- <el-text size="small">{{ item.finish + '/' + item.total }}</el-text> --> <!-- <span class="percentage-value-small">{{ percentFormat(item.finish, item.total) }}%</span> --> <!-- <div class="percentage-label-small">{{ item.sceneType }}</div> --> <!-- <span class="percentage-label-small">{{ item.finish + '/' + item.total }} </span> --> - </div> - </el-row> + </el-space> + </div> + <div> + <div class="text_title">鏃ョ▼杩涘害</div> + <el-space> + <el-text style="color: transparent;">鏃ョ▼</el-text> + <el-progress + style="width: 350px" + type="line" + color="#00b487" + :text-inside="true" + :stroke-width="22" + :percentage="percentFormat(date, dayCount)" + > + <template #default="{ percentage }"> + <span class="percentage-value">{{ `${dateStr} (${percentage}%)` }}</span> + </template> + </el-progress> + </el-space> + </div> + <!-- </el-row> --> </div> </template> -<script> +<script setup> +import { ref, computed } from 'vue' +import { useAreaStore } from '@/stores/area.js' +import dayjs from 'dayjs' + /** * 宸℃煡浠诲姟鍖哄煙缁熻淇℃伅 */ -export default { - props: { - // name: String, - // province: String, - // district: String, - // planTime: String, - // startTime: String, - // endTime: String, - // userName: String, - // status: String, - // totaltask: Number, - // completetask: Number, - // count: Array, +const areaStore = useAreaStore() - value: Object - }, - data() { - return {} - }, - watch: {}, - computed: { - // total() { - // let t = 0 - // this.count.forEach((c) => { - // t += c.total - // }) - // return t - // }, - // finish() { - // let t = 0 - // this.count.forEach((c) => { - // t += c.finish - // }) - // return t - // } - }, - methods: { - percentFormat(finish, total) { - if (total == 0) { - return 0 - } else { - const per = finish / total > 1 ? 1 : finish / total - return Math.round(per * 100) - } - }, - format(percentage) { - percentage === 100 ? 'Full' : `${percentage}%` - } +const props = defineProps({ + value: Object +}) + +const width = ref('300px') + +const dayCount = computed(() => dayjs(areaStore.area.endtime).daysInMonth()) +const date = computed(() => { + const today = dayjs() + const planEndTime = dayjs(areaStore.area.endtime) + if (today.isBefore(planEndTime)) { + return today.date() + } else { + return planEndTime.daysInMonth() } +}) +const dateStr = computed(()=>{ + const today = dayjs() + const planEndTime = dayjs(areaStore.area.endtime) + if (today.isBefore(planEndTime)) { + return today.format('MM鏈圖D鏃�') + } else { + return today.format('MM鏈圖D鏃�') + } +}) + +function percentFormat(finish, total) { + if (total == 0) { + return 0 + } else { + const per = finish / total > 1 ? 1 : finish / total + return Math.round(per * 100) + } +} +function format(percentage) { + percentage === 100 ? 'Full' : `${percentage}%` } </script> @@ -118,6 +157,19 @@ .wrapper { border: var(--el-border); border-radius: var(--el-border-radius-base); + box-shadow: var(--el-box-shadow-lighter); + background-color: rgba(161, 161, 161, 0.068); + padding: 8px 8px; +} + +.text_title { + border-left: 6px solid rgb(49, 221, 6); + border-bottom: 1px solid rgb(49, 221, 6); + padding: 0px 4px 0px 4px; + width: 100px; + font-size: 15px; + margin-bottom: 4px; + /* color: #00b487; */ } .flex-bottom { @@ -145,4 +197,7 @@ /* margin-top: 10px; */ font-size: var(--el-font-size-small); } +:deep(.el-progress-bar__outer) { + background-color: rgba(211, 211, 211, 0.411); +} </style> diff --git a/src/main.js b/src/main.js index 78f6786..c50ba05 100644 --- a/src/main.js +++ b/src/main.js @@ -3,6 +3,11 @@ import * as ElementPlusIconsVue from '@element-plus/icons-vue' import 'element-plus/theme-chalk/src/dark/css-vars.scss' +import 'element-plus/theme-chalk/src/overlay.scss'; +import 'element-plus/theme-chalk/src/message.scss'; +import 'element-plus/theme-chalk/src/message-box.scss'; +import 'element-plus/theme-chalk/src/notification.scss'; + import App from './App.vue' import router from './router' import timeUtil from './utils/time-util' diff --git a/src/views/main/MonitorView.vue b/src/views/main/MonitorView.vue index fc0eea2..0640fd7 100644 --- a/src/views/main/MonitorView.vue +++ b/src/views/main/MonitorView.vue @@ -1,27 +1,31 @@ <template> <BaseMap></BaseMap> <el-row class="overlay-container" v-if="true"> - <el-col :span="17"> - <el-scrollbar class="page-left-top"> - <!-- <VisualizationView></VisualizationView> --> + <el-col :span="7" class="page-right"> + <el-scrollbar height="var(--fy-body-height)" class="p-events-auto" style="width: 450px"> + <TaskStats></TaskStats> + <TaskSummary></TaskSummary> </el-scrollbar> - <el-scrollbar class="page-left-bottom p-events-auto"> - <!-- <InspectionView></InspectionView> --> - </el-scrollbar> + </el-col> + <el-col :span="10"> + <el-row justify="end"> + <SubtaskVisual class="subtask-visual"></SubtaskVisual> + </el-row> + <!-- <el-scrollbar class="page-left-top"> --> + <!-- <VisualizationView></VisualizationView> --> + <!-- </el-scrollbar> --> + <!-- <el-scrollbar class="page-left-bottom p-events-auto"> + <InspectionView></InspectionView> + </el-scrollbar> --> </el-col> <el-col :span="7" class="page-right"> <el-scrollbar height="var(--fy-body-height)" class="p-events-auto"> <ManagementView></ManagementView> </el-scrollbar> </el-col> - <!-- <el-col :span="7" class="page-right"> - <el-scrollbar height="var(--fy-body-height)"> - <StatisticView></StatisticView> - </el-scrollbar> - </el-col> --> </el-row> <SupervisionVisual class="supervision-view"></SupervisionVisual> - <TaskStats class="task-stats"></TaskStats> + <WorkStream class="work-stream"></WorkStream> <!-- <ProblemTrack class="problem-track"></ProblemTrack> --> </template> @@ -47,6 +51,8 @@ import SupervisionVisual from '@/views/visualization/SupervisionVisual.vue' import WorkStream from '@/views/inspection/WorkStream.vue' import TaskStats from '@/views/management/TaskStats.vue' +import TaskSummary from '@/views/management/TaskSummary.vue' +import SubtaskVisual from '@/views/visualization/SubtaskVisual.vue' // provide('mapHeight', 'calc(var(--fy-body-height) / 4 * 3)') provide('mapHeight', 'calc(var(--fy-body-height))') @@ -64,10 +70,10 @@ pName: '涓婃捣甯�', cCode: '3100', cName: '涓婃捣甯�', - dCode: '310106', - dName: '闈欏畨鍖�' + dCode: '310104', + dName: '寰愭眹鍖�' }) -areaStore.setSceneType({ label: '宸ュ湴', value: '1' }) +areaStore.setSceneType({ label: '鍏ㄩ儴鍦烘櫙', value: null }) // 鑾峰彇鏈湀鐨勬墍鏈夊贰鏌ョ粺璁′俊鎭� subtaskStore.fetchTopTaskProgress(areaStore.area) @@ -131,4 +137,10 @@ } .problem-track { } + +.subtask-visual { + margin-top: 50px; + /* min-width: 450px; + max-width: 600px; */ +} </style> diff --git a/src/views/management/TaskStats.vue b/src/views/management/TaskStats.vue index 7092c58..271414c 100644 --- a/src/views/management/TaskStats.vue +++ b/src/views/management/TaskStats.vue @@ -10,7 +10,7 @@ </el-row> --> <!-- <el-row> --> <TaskItem v-for="item in tasks" :key="item.guid" :value="item"></TaskItem> - <TaskSummary></TaskSummary> + <!-- <TaskSummary></TaskSummary> --> <!-- </el-row> --> <!-- <el-row> @@ -74,11 +74,12 @@ } const task = { - name: tInfo.name, - province: tInfo.provinceName, - district: tInfo.districtName, - totaltask: tInfo.totaltask, - completetask: tInfo.completetask, + // name: tInfo.name, + // province: tInfo.provinceName, + // district: tInfo.districtName, + // totaltask: tInfo.totaltask, + // completetask: tInfo.completetask, + ...tInfo, _totaltask, _completetask, count: [] diff --git a/src/views/management/TaskSummary.vue b/src/views/management/TaskSummary.vue index 5317441..1926d9f 100644 --- a/src/views/management/TaskSummary.vue +++ b/src/views/management/TaskSummary.vue @@ -1,18 +1,20 @@ <template> - <el-row> 宸℃煡姹囨�� </el-row> - <el-segmented v-model="value" :options="options" block /> - <div v-show="value == '浠婃棩姹囨��'"> - <div ref="echart1" class="bar-chart"></div> - </div> - <div v-show="value == '鏈懆姹囨��'"> - <div ref="echart2" class="bar-chart"></div> - </div> - <div v-show="value == '涓婂懆姹囨��'"> - <div ref="echart3" class="bar-chart"></div> - </div> - <div v-show="value == '鏈堝害姹囨��'"> - <div ref="echart4" class="bar-chart"></div> - </div> + <BaseCard title="宸℃煡姹囨��"> + <!-- <el-row> 宸℃煡姹囨�� </el-row> --> + <el-segmented v-model="value" :options="options" block /> + <div v-show="value == '浠婃棩姹囨��'"> + <div ref="echart1" class="bar-chart"></div> + </div> + <div v-show="value == '鏈懆姹囨��'"> + <div ref="echart2" class="bar-chart"></div> + </div> + <div v-show="value == '涓婂懆姹囨��'"> + <div ref="echart3" class="bar-chart"></div> + </div> + <div v-show="value == '鏈湀姹囨��'"> + <div ref="echart4" class="bar-chart"></div> + </div> + </BaseCard> </template> <script setup> @@ -30,8 +32,8 @@ const emits = defineEmits(['update:height']) -const value = ref('鏈堝害姹囨��') -const options = ['浠婃棩姹囨��', '鏈懆姹囨��', '涓婂懆姹囨��', '鏈堝害姹囨��'] +const value = ref('鏈湀姹囨��') +const options = ['浠婃棩姹囨��', '鏈懆姹囨��', '涓婂懆姹囨��', '鏈湀姹囨��'] const subtaskToday = ref([]) const subtaskWeek = ref([]) @@ -139,7 +141,7 @@ yAxis: [ { type: 'category', - data: ['鏁存敼鏁�', '闂鏁�', '瀹屾垚閲�'] + data: ['澶嶆牳鏁�', '鏁存敼鏁�', '闂鏁�', '瀹屾垚閲�'] } ], series: series @@ -153,6 +155,7 @@ const totalCount = { numByTotal: {}, numByDistrict: {}, + numByStreet: {}, numByScene: {}, numByUser: {} } @@ -160,6 +163,7 @@ const proCount = { numByTotal: {}, numByDistrict: {}, + numByStreet: {}, numByScene: {}, numByUser: {} } @@ -167,19 +171,24 @@ const changeCount = { numByTotal: {}, numByDistrict: {}, + numByStreet: {}, numByScene: {}, numByUser: {} } - // // 鎸夌敤鎴峰垎绫� - // const userCount = { - // numByTotal: {}, - // numByDistrict: {}, - // numByScene: {}, - // numByUser: {} - // } + // 澶嶆牳鏁� + const reCheckCount = { + numByTotal: {}, + numByDistrict: {}, + numByStreet: {}, + numByScene: {}, + numByUser: {} + } + const historySceneId = [] + dataList.forEach((d) => { const tName = '鎬昏' const dName = d.subtask.districtname + const townName = d.scene.townname const sType = d.sceneType const uName = d.subtask.deployerrealname @@ -190,6 +199,10 @@ // 浠诲姟閲忓垎鍖哄幙 totalCount.numByDistrict[dName] = totalCount.numByDistrict[dName] ? totalCount.numByDistrict[dName] + 1 + : 1 + // 浠诲姟閲忓垎琛楅晣 + totalCount.numByStreet[townName] = totalCount.numByStreet[townName] + ? totalCount.numByStreet[townName] + 1 : 1 // 浠诲姟閲忓垎鍦烘櫙绫诲瀷 totalCount.numByScene[sType] = totalCount.numByScene[sType] @@ -205,6 +218,10 @@ // 闂鏁板垎鍖哄幙 proCount.numByDistrict[dName] = proCount.numByDistrict[dName] ? proCount.numByDistrict[dName] + d.proCheckedNum + : d.proCheckedNum + // 闂鏁板垎琛楅晣 + proCount.numByStreet[townName] = proCount.numByStreet[townName] + ? proCount.numByStreet[townName] + d.proCheckedNum : d.proCheckedNum // 闂鏁板垎鍦烘櫙绫诲瀷 proCount.numByScene[sType] = proCount.numByScene[sType] @@ -223,6 +240,10 @@ changeCount.numByDistrict[dName] = changeCount.numByDistrict[dName] ? changeCount.numByDistrict[dName] + d.changeCheckedNum : d.changeCheckedNum + // 鏁存敼鏁板垎琛楅晣 + changeCount.numByStreet[townName] = changeCount.numByStreet[townName] + ? changeCount.numByStreet[townName] + d.changeCheckedNum + : d.changeCheckedNum // 鏁存敼鏁板垎鍦烘櫙绫诲瀷 changeCount.numByScene[sType] = changeCount.numByScene[sType] ? changeCount.numByScene[sType] + d.changeCheckedNum @@ -231,12 +252,40 @@ changeCount.numByUser[uName] = changeCount.numByUser[uName] ? changeCount.numByUser[uName] + d.changeCheckedNum : d.changeCheckedNum + + if (historySceneId.length == 0) { + reCheckCount.numByTotal[tName] = 0 + reCheckCount.numByDistrict[dName] = 0 + reCheckCount.numByScene[sType] = 0 + reCheckCount.numByUser[uName] = 0 + } else if (historySceneId.indexOf(d.sceneId) != -1) { + // 澶嶆牳鏁版�昏 + reCheckCount.numByTotal[tName] = reCheckCount.numByTotal[tName] + ? reCheckCount.numByTotal[tName] + 1 + : 1 + // 澶嶆牳鏁板垎鍖哄幙 + reCheckCount.numByDistrict[dName] = reCheckCount.numByDistrict[dName] + ? reCheckCount.numByDistrict[dName] + 1 + : 1 + // 澶嶆牳鏁板垎琛楅晣 + reCheckCount.numByStreet[townName] = reCheckCount.numByStreet[townName] + ? reCheckCount.numByStreet[townName] + 1 + : 1 + // 澶嶆牳鏁板垎鍦烘櫙绫诲瀷 + reCheckCount.numByScene[sType] = reCheckCount.numByScene[sType] + ? reCheckCount.numByScene[sType] + 1 + : 1 + // 澶嶆牳鏁板垎鐢ㄦ埛 + reCheckCount.numByUser[uName] = reCheckCount.numByUser[uName] + ? reCheckCount.numByUser[uName] + 1 + : 1 + } else { + historySceneId.push(d.sceneId) + } }) let series = {} - totalCount - proCount - changeCount + parseSeries(series, reCheckCount) parseSeries(series, changeCount) parseSeries(series, proCount) parseSeries(series, totalCount) @@ -291,12 +340,33 @@ label: { show: true, formatter: '{c}' - // position: [0, 10], + // position: 'top', }, data: [value] } } } + // for (const key in c.numByStreet) { + // const value = c.numByStreet[key] + // if (series[key]) { + // series[key].data.push(value) + // } else { + // series[key] = { + // name: `琛楅晣锛�${key}`, + // type: 'bar', + // stack: 'street', + // emphasis: { + // focus: 'series' + // }, + // label: { + // show: true, + // formatter: '{c}' + // // position: 'top', + // }, + // data: [value] + // } + // } + // } for (const key in c.numByScene) { const value = c.numByScene[key] if (series[key]) { diff --git a/src/views/visualization/SubtaskVisual.vue b/src/views/visualization/SubtaskVisual.vue index 5ed728e..3d0196e 100644 --- a/src/views/visualization/SubtaskVisual.vue +++ b/src/views/visualization/SubtaskVisual.vue @@ -1,149 +1,196 @@ <template> - <el-scrollbar v-if="mapStore.focusMarker" :height="mapHeight"> - <el-card class="p-events-auto wrapper"> + <el-scrollbar v-if="mapStore.focusMarker" class="wrapper"> + <el-card class="p-events-auto"> <el-row justify="space-between"> - <div class="font-small">{{ scene.name }}</div> + <!-- <div class="font-small">{{ scene.name }}</div> --> + <el-text size="large">{{ scene.name }}</el-text> <el-button icon="Close" circle @click="mapStore.focusMarker = undefined"></el-button> </el-row> + <el-row justify="space-between"> + <el-text size="small">{{ '鍦板潃锛�' + scene.location }}</el-text> + </el-row> + <el-space class="m-t-8"> + <el-tag type="info" effect="plain"> + {{ scene.districtname + scene.townname }} + </el-tag> + <el-tag type="info" effect="plain"> + {{ scene.type }} + </el-tag> + </el-space> <el-divider></el-divider> - <div class="font-small">鐘舵�侊細{{ subtask.status }}</div> - <div class="font-small">璁″垝锛歿{ $fm.formatYMD(subtask.planstarttime) }}</div> - <div v-if="subtask.status != '鏈墽琛�'" class="font-small"> - <span>鎵ц锛歿{ $fm.formatYMDH(subtask.executionstarttime) }}</span> - <span> - </span> - <span>{{ $fm.formatYMDH(subtask.executionendtime) }}</span> + <el-row justify="space-between"> + <el-col :span="8" style="text-align: center"> + <el-text>鐘舵�侊細{{ subtask.status }}</el-text> + </el-col> + <el-col :span="8" style="text-align: center"> + <el-text>璁″垝锛歿{ $fm.formatYMD(subtask.planstarttime) }}</el-text> + </el-col> + <el-col v-if="subtask.status != '鏈墽琛�'" :span="8" style="text-align: center"> + <el-text> + <span>鎵ц锛歿{ $fm.formatH(subtask.executionstarttime) }}</span> + <!-- <span> - </span> + <span>{{ $fm.formatYMDH(subtask.executionendtime) }}</span> --> + </el-text> + </el-col> + </el-row> + + <el-segmented v-model="value" :options="options" block /> + <div v-show="value == '鐜板満闂'"> + <problem-item + v-for="(item, i) in problemList" + :key="item.guid" + :index="i + 1" + :problem="item" + ></problem-item> + <el-empty v-if="problemList.length == 0" description="鏃犵幇鍦洪棶棰�"> + <template #image> </template> + </el-empty> </div> - <div class="font-small">闂锛�</div> - <problem-item - v-for="(item, i) in problemList" - :key="item.guid" - :index="i + 1" - :problem="item" - ></problem-item> - <!-- <div v-for="item in problemList" :key="item.guid"> - {{ item.problemname }} - </div> --> - <!-- <el-timeline style="max-width: 600px"> - <el-timeline-item - v-for="(activity, index) in activities" - :key="index" - :timestamp="activity.timestamp" - :hide-timestamp="activity.running" - :type="activity.running ? 'danger' : 'success'" - :size="activity.running ? 'large' : 'normal'" - :hollow="false" - > - {{ activity.content }} - </el-timeline-item> - </el-timeline> --> + <div v-show="value == '鍦烘櫙鍥剧墖'"> + <FYImageSelectDialog + readonly + height="500px" + :imageWidth="134" + v-loading="scenePicLoading" + :typeList="scenePicTypeList" + :typeImgMap="scenePicTypeMap" + ></FYImageSelectDialog> + </div> + <div v-show="value == '璁惧璁炬柦'"> + + </div> </el-card> </el-scrollbar> </template> -<script> -import { inject } from 'vue' +<script setup> +import { inject, ref, computed, watch } from 'vue' import { useMapStore } from '@/stores/map.js' import { mapStores } from 'pinia' +import { $fysp } from '@/api/index.js' import problemApi from '@/api/fysp/problemApi.js' +import mediafileApi from '@/api/fysp/mediafileApi.js' +import deviceApi from '@/api/fysp/deviceApi' /** * 鍏蜂綋宸℃煡浠诲姟鍙鍖� * 鍖呮嫭鍦板浘瀹氫綅淇℃伅灞曠ず銆佸贰鏌ヤ换鍔″叏娴佺▼骞抽摵灞曠ず */ -export default { - setup() { - const mapHeight = inject('mapHeight') +const mapHeight = inject('mapHeight') +const height = 'height:' + mapHeight - const height = 'height:' + mapHeight - return { height, mapHeight } - }, - props: { - // subtask: { - // type: Object, - // default: () => { - // return { - // guid: 'SMuheEkjswioSn7A', - // name: '涓鐢熸�佹暟瀛楁腐椤圭洰宸℃煡涓鐢熸�佹暟瀛楁腐椤圭洰宸℃煡', - // district: '閲戝北鍖�', - // planTime: '2024-06-04', - // startTime: '2024-06-04 13:31:26', - // endTime: '2024-06-04 13:33:37', - // userName: '鏈辨寮�', - // status: '宸茬粨鏉�', - // total: 4, - // checked: 2 - // } - // } - // } - }, - data() { - return { - // activities: [ - // { - // content: '浠诲姟鍒涘缓', - // timestamp: '2024-06-04 08:00', - // running: false - // }, - // { - // content: '寮�濮嬪贰鏌�', - // timestamp: '2024-06-04 09:00', - // running: false - // }, - // { - // content: '缁撴潫宸℃煡', - // timestamp: '2024-06-04 09:15', - // running: false - // }, - // { - // content: '瀹屾垚闂瀹℃牳', - // timestamp: '2024-06-04 10:15', - // running: false - // }, - // { - // content: '闂鏁存敼涓�...', - // timestamp: '2024-06-04 10:15', - // running: true - // } - // ] - problemList: [] - } - }, - computed: { - ...mapStores(useMapStore), - subtask() { - return this.mapStore.focusMarker ? this.mapStore.focusMarker.subtask : undefined - }, - scene() { - return this.mapStore.focusMarker ? this.mapStore.focusMarker.scene : undefined - }, - inspection() { - return this.mapStore.focusMarker ? this.mapStore.focusMarker.inspection : undefined - } - }, - watch: { - subtask(nV, oV) { - if (nV != undefined && nV != oV) { - this.fetchProblem(nV.stguid) +const mapStore = useMapStore() +const subtask = computed(() => (mapStore.focusMarker ? mapStore.focusMarker.subtask : undefined)) +const scene = computed(() => (mapStore.focusMarker ? mapStore.focusMarker.scene : undefined)) +const inspection = computed(() => + mapStore.focusMarker ? mapStore.focusMarker.inspection : undefined +) + +const value = ref('鐜板満闂') +const options = ['鐜板満闂', '鍦烘櫙鍥剧墖', '璁惧璁炬柦'] + +const problemList = ref([]) +const problemListLoading = ref(false) + +const scenePicTypeList = ref([]) +const scenePicTypeMap = ref(new Map()) +const scenePicLoading = ref(false) + +watch(subtask, (nV, oV) => { + if (nV != undefined && nV != oV) { + fetchProblem(nV.stguid) + getRoutineByStGuid(nV.stguid) + } +}) +function fetchProblem(stguid) { + problemListLoading.value = true + problemApi + .fetchProblems(stguid) + .then((res) => { + problemList.value = res + }) + .finally(() => (problemListLoading.value = false)) +} + +// 鍥剧墖鍒嗙被 +function getRoutineByStGuid(stguid) { + scenePicLoading.value = true + mediafileApi + .getRoutineByStGuid(stguid) + .then((res) => { + let typeList = [] + let typeMap = new Map() + const data = res.data + for (const e of data) { + let img = { + url: $fysp.imgUrl + e.extension1 + e.guid + '.jpg', + data: e + } + const businesstype = e.businesstype + const businesstypeid = e.businesstypeid + if (typeList.find((item) => item.typeId == businesstypeid) != undefined) { + typeMap.get(businesstypeid).push(img) + } else { + typeList.push({ + typeId: businesstypeid, + typeName: businesstype + }) + typeMap.set(businesstypeid, [img]) + } } + scenePicTypeList.value = typeList + scenePicTypeMap.value = typeMap + }) + .finally(() => (scenePicLoading.value = false)) +} + +function fetchDevices() { + deviceApi.fetchDevices(scene.value.guid, this.currSelect.topDeviceTypeId).then((result) => { + this.initList() + if (result.data == null || result.data.length <= 0) { + this.isEmpty = true + return } - }, - methods: { - fetchProblem(stguid) { - problemApi.fetchProblems(stguid).then((res) => { - this.problemList = res + // 鏍囧噯鍖栧睘鎬у悕 + for (let index = 0; index < result.data.length; index++) { + var element = this.convertKeys(result.data[index]) + this.initFormData(element) + // 鑾峰彇璁惧鐘舵�佷俊鎭� + let data = { + deviceId: element.id, + sceneId: element.sceneGuid, + deviceTypeId: this.currSelect.topDeviceTypeId + } + deviceApi.fetchDeviceStatus(data).then((status) => { + var statusData = status.data + var imgPaths = [] + if (statusData) { + if (statusData.length == 0) { + this.formInfo.push(element) + return + } + element = this.convertKeys(result.data[index]) + element = this.setDeviceType(element) + element._picUrls = imgPaths + for (let index = 0; index < statusData.length; index++) { + const statusItem = statusData[index] + // 璁惧瀵硅薄娣诲姞涓�涓睘鎬у垪琛ㄥ睘鎬х敤鏉ヤ繚瀛樿澶囩姸鎬� + this.saveStatus(element, statusItem) + element.dlLocation = statusItem.dlLocation + this.formInfo.push(element) + } + } }) } - } + }) } </script> <style scoped> .wrapper { - /* position: absolute; */ - top: 0; - right: 0; - /* background-color: wheat; */ + width: 450px; + max-height: 800px; } .el-card { diff --git a/src/views/visualization/SupervisionVisual.vue b/src/views/visualization/SupervisionVisual.vue index 3f78a95..3c1c421 100644 --- a/src/views/visualization/SupervisionVisual.vue +++ b/src/views/visualization/SupervisionVisual.vue @@ -49,12 +49,12 @@ pName: '涓婃捣甯�', cCode: '3100', cName: '涓婃捣甯�', - dCode: '310106', - dName: '闈欏畨鍖�' + dCode: '310104', + dName: '寰愭眹鍖�' }, sceneType: { - label: '宸ュ湴', - value: '1' + label: '鍏ㄩ儴鍦烘櫙', + value: null }, time: '' } -- Gitblit v1.9.3