From a34c1293e82c0afacacecfc1fb850afe27b4873b Mon Sep 17 00:00:00 2001 From: songshankun <songshankun@foxmail.com> Date: 星期五, 03 十一月 2023 11:31:58 +0800 Subject: [PATCH] feat: 问题诊断列表弹窗对接接口数据,抽离轮询时间配置,添加设备切换按钮 --- src/stores/plc.ts | 3 src/components/icons/AlertLightIcon.vue | 2 src/views/dashboard/components/TroubleTrackerModal.vue | 36 +++----- package-lock.json | 19 ++++ src/views/dashboard/components/DeviceNumberInfo.vue | 2 src/common/constants/index.ts | 10 +- package.json | 1 src/stores/devices.ts | 3 src/api/device.ts | 1 src/api/index.ts | 11 ++ src/api/problem.ts | 6 + src/views/dashboard/components/DashboardTitle.vue | 88 ++++++++++++++++++--- 12 files changed, 137 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1451e6f..6d767bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "xstate": "^4.38.3" }, "devDependencies": { + "@iconify-json/bx": "^1.1.7", "@iconify-json/material-symbols-light": "^1.1.0", "@iconify-json/mdi": "^1.1.55", "@rushstack/eslint-patch": "^1.3.3", @@ -811,6 +812,15 @@ "resolved": "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true + }, + "node_modules/@iconify-json/bx": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/@iconify-json/bx/-/bx-1.1.7.tgz", + "integrity": "sha512-Ugh8uUU9VtK8fI9BBnhLA7VvhPh7erSmJz+eqjvl8HCRRjkz5mbMO5/KYpCOriUVdiiKB9Yv1ObMqS73WLMSwA==", + "dev": true, + "dependencies": { + "@iconify/types": "*" + } }, "node_modules/@iconify-json/material-symbols-light": { "version": "1.1.0", @@ -5463,6 +5473,15 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, + "@iconify-json/bx": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/@iconify-json/bx/-/bx-1.1.7.tgz", + "integrity": "sha512-Ugh8uUU9VtK8fI9BBnhLA7VvhPh7erSmJz+eqjvl8HCRRjkz5mbMO5/KYpCOriUVdiiKB9Yv1ObMqS73WLMSwA==", + "dev": true, + "requires": { + "@iconify/types": "*" + } + }, "@iconify-json/material-symbols-light": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/@iconify-json/material-symbols-light/-/material-symbols-light-1.1.0.tgz", diff --git a/package.json b/package.json index 99df410..9360d7f 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "xstate": "^4.38.3" }, "devDependencies": { + "@iconify-json/bx": "^1.1.7", "@iconify-json/material-symbols-light": "^1.1.0", "@iconify-json/mdi": "^1.1.55", "@rushstack/eslint-patch": "^1.3.3", diff --git a/src/api/device.ts b/src/api/device.ts index 6023675..83a9c45 100644 --- a/src/api/device.ts +++ b/src/api/device.ts @@ -1,4 +1,5 @@ export interface Devices { + /** 鏈満璁惧缂栫爜 */ systemDeviceID: string currentDeviceID: string systemDeviceStatus: number diff --git a/src/api/index.ts b/src/api/index.ts index afab391..84fceb8 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -3,6 +3,7 @@ import type { PLCResponse } from './plc' import type { Devices } from './device' import type { CraftModel } from './craftModel' +import type { Problem } from './problem' export interface BaseResponse<T = any> { code: number @@ -141,3 +142,13 @@ data: params }) } + +/** + * 鑾峰彇闂璇婃柇闂鍒楄〃 + */ +export function apiGetProblemList() { + return request<BaseResponse<Problem[]>>({ + url: '/v1/system/problemList', + method: 'get' + }) +} diff --git a/src/api/problem.ts b/src/api/problem.ts new file mode 100644 index 0000000..af784f6 --- /dev/null +++ b/src/api/problem.ts @@ -0,0 +1,6 @@ +export interface Problem { + /** true姝e父 false寮傚父 */ + CheckResult: boolean + ItemCode: string + ItemName: string +} diff --git a/src/common/constants/index.ts b/src/common/constants/index.ts index 995f28e..a739be6 100644 --- a/src/common/constants/index.ts +++ b/src/common/constants/index.ts @@ -17,7 +17,9 @@ 7: 'G' } -export const DEVICE_STATUS_NAME_MAP = { - 1: '姝e父', - 2: '寮傚父' -} +// plc 杞闂撮殧 +export const PLC_POLLING_DURATION = 6_000 +// 璁惧淇℃伅 杞闂撮殧 +export const DEVICE_INFO_POLLING_DURATION = 15_000 +// 闂璇婃柇 +export const PROBLEMS_POLLING_DURATION = 30_000 diff --git a/src/components/icons/AlertLightIcon.vue b/src/components/icons/AlertLightIcon.vue index 3a70684..27c398b 100644 --- a/src/components/icons/AlertLightIcon.vue +++ b/src/components/icons/AlertLightIcon.vue @@ -19,14 +19,12 @@ <g> <path style="opacity: 0.988" - fill="#d71d05" d="M 87.5,-0.5 C 95.1667,-0.5 102.833,-0.5 110.5,-0.5C 146.888,7.72465 167.388,30.3913 172,67.5C 172.5,101.165 172.667,134.832 172.5,168.5C 123.833,168.5 75.1667,168.5 26.5,168.5C 26.3333,132.498 26.5,96.4985 27,60.5C 33.9986,27.0017 54.1653,6.66837 87.5,-0.5 Z M 101.5,40.5 C 103.678,52.6006 105.011,64.9339 105.5,77.5C 116.858,77.4139 128.191,77.9139 139.5,79C 123.945,100.223 108.778,121.723 94,143.5C 93.167,128.176 92.667,112.842 92.5,97.5C 80.4954,97.6665 68.4954,97.4999 56.5,97C 71.8692,78.4097 86.8692,59.5764 101.5,40.5 Z" /> </g> <g> <path style="opacity: 0.995" - fill="#d81d05" d="M 199.5,183.5 C 199.5,186.833 199.5,190.167 199.5,193.5C 197.167,195.167 195.167,197.167 193.5,199.5C 130.833,199.5 68.1667,199.5 5.5,199.5C 3.83333,197.167 1.83333,195.167 -0.5,193.5C -0.5,190.167 -0.5,186.833 -0.5,183.5C 1.67098,181.5 4.00432,179.666 6.5,178C 68.5,177.333 130.5,177.333 192.5,178C 194.996,179.666 197.329,181.5 199.5,183.5 Z" /> </g> diff --git a/src/stores/devices.ts b/src/stores/devices.ts index 4c74113..fb0fd53 100644 --- a/src/stores/devices.ts +++ b/src/stores/devices.ts @@ -3,6 +3,7 @@ import { getDeviceList } from '@/api' import { useRequest } from 'vue-hooks-plus' import type { Devices } from '@/api/device' +import { DEVICE_INFO_POLLING_DURATION } from '@/common/constants' export const useDevicesStore = defineStore('device', () => { const deviceInfo = computed(() => { @@ -18,7 +19,7 @@ cancel: cancelDevicePolling } = useRequest(getDeviceList, { manual: true, - pollingInterval: 6000, + pollingInterval: DEVICE_INFO_POLLING_DURATION, pollingWhenHidden: false }) diff --git a/src/stores/plc.ts b/src/stores/plc.ts index 50e7926..b42f370 100644 --- a/src/stores/plc.ts +++ b/src/stores/plc.ts @@ -5,6 +5,7 @@ import { useRequest } from 'vue-hooks-plus' import { useTasksStore } from '@/stores/tasks' import type { PLCResponse } from '@/api/plc' +import { PLC_POLLING_DURATION } from '@/common/constants' // 鍏ㄥ眬 watcher ref 闃叉澶氭璋冪敤 usePLCStore 鏃堕噸澶嶆敞鍐屼睛鍚櫒 const unwatch = ref() @@ -31,7 +32,7 @@ } as ProductProgressParams), { manual: true, - pollingInterval: 6000, + pollingInterval: PLC_POLLING_DURATION, pollingWhenHidden: false } ) diff --git a/src/views/dashboard/components/DashboardTitle.vue b/src/views/dashboard/components/DashboardTitle.vue index b55e9fb..57f1a01 100644 --- a/src/views/dashboard/components/DashboardTitle.vue +++ b/src/views/dashboard/components/DashboardTitle.vue @@ -1,41 +1,103 @@ <template> <div class="dashboard-title"> - <div class="title-text">鏅鸿兘宸ヤ綔鍙� 鈥� {{ deviceStore?.deviceInfo?.currentDeviceID ?? '' }}</div> + <div class="title-text"> + 鏅鸿兘宸ヤ綔鍙� 鈥� {{ deviceStore?.deviceInfo?.currentDeviceID ?? '' }} + <el-icon size="32" color="#0db7f5" style="margin-left: 20px; cursor: pointer" @click="openDevicesModal"> + <IconSlider></IconSlider> + </el-icon> + </div> <div class="title-status"> - <div class="connection-info" @click="openSelectDeviceModal"> - <el-icon size="30" color="red"> + <div class="connection-info" @click="openProblemsModal"> + <el-icon size="30" :color="problemsIconStatus ? '#00ff00' : '#ff0000'"> <AlertLightIcon></AlertLightIcon> </el-icon> </div> <div class="cloud-connection-status"> - <el-icon size="45" color="#ff0000"> - <IconCloudOff></IconCloudOff> + <el-icon v-if="cloudConnectionIconStatus" size="45" color="#00ff00"> + <IconCloudDone></IconCloudDone> </el-icon> - <el-icon size="45" color="#00ff00"> - <IconCloudDone></IconCloudDone> + <el-icon v-else size="45" color="#ff0000"> + <IconCloudOff></IconCloudOff> </el-icon> </div> </div> </div> - <TroubleTrackerModal v-model="showModal"></TroubleTrackerModal> + <TroubleTrackerModal v-model="showProblemsModal" :problems="problemList"></TroubleTrackerModal> </template> <script setup lang="ts"> import AlertLightIcon from '@/components/icons/AlertLightIcon.vue' -import { ref } from 'vue' +import { computed, onUnmounted, ref } from 'vue' import { useDevicesStore } from '@/stores/devices' import TroubleTrackerModal from '@/views/dashboard/components/TroubleTrackerModal.vue' import IconCloudDone from '~icons/material-symbols-light/cloud-done-outline' import IconCloudOff from '~icons/material-symbols-light/cloud-off-outline' +import IconSlider from '~icons/bx/slider' +import { useRequest } from 'vue-hooks-plus' +import { apiGetProblemList } from '@/api' +import { PROBLEMS_POLLING_DURATION } from '@/common/constants' -const showModal = ref(false) - -function openSelectDeviceModal() { - showModal.value = true +// 鏄惁鏄剧ず闂璇婃柇modal +const showProblemsModal = ref(false) +/** + * 鎵撳紑闂璇婃柇modal + */ +function openProblemsModal() { + showProblemsModal.value = true } +// 鏄惁鏄剧ず璁惧鍒囨崲modal +const showDevicesModal = ref(false) +/** + * 鎵撳紑璁惧鍒囨崲modal + */ +function openDevicesModal() { + showDevicesModal.value = true +} + +// 鑾峰彇褰撳墠璁惧鍚� const deviceStore = useDevicesStore() + +// 闂璇婃柇鍒楄〃 +const problemList = computed(() => { + return problemsRes?.value?.data ?? [] +}) +// 闂璇婃柇icon鐘舵��, 闂鍒楄〃涓湁涓�鏉″紓甯稿嵆涓虹孩鐏� 鍚﹀垯鏄豢鐏� true缁跨伅 +const problemsIconStatus = computed(() => { + if (!problemList.value || !problemList.value?.length) { + // 榛樿缁跨伅, 鎷垮埌涓�娆℃暟鎹悗鎵嶄互鎺ュ彛涓哄噯 + return true + } + return !problemList.value.some((ele) => !ele.CheckResult) +}) +// 浜戠杩炴帴icon鐘舵��, 闂鍒楄〃涓湁涓�鏉′唬琛ㄤ簯绔摼鎺ョ殑, 寮傚父鍗充负绾㈣壊浜慽con 鍚﹀垯鏄豢鑹� true缁夸簯 +const cloudConnectionIconStatus = computed(() => { + if (!problemList.value || !problemList.value?.length) { + // 榛樿缁跨伅, 鎷垮埌涓�娆℃暟鎹悗鎵嶄互鎺ュ彛涓哄噯 + return true + } + // 娌℃暟鎹氨褰撴槸閾炬帴姝e父 + const cloudConnection = problemList.value.find((ele) => ele.ItemCode === 'cloud') + return cloudConnection ? cloudConnection?.CheckResult : true +}) + +/** + * 杞闂璇婃柇 + */ +const { + data: problemsRes, + run: startProblemsPolling, + cancel: cancelProblemsPolling +} = useRequest(apiGetProblemList, { + manual: true, + pollingInterval: PROBLEMS_POLLING_DURATION, + pollingWhenHidden: false +}) +startProblemsPolling() +onUnmounted(() => { + cancelProblemsPolling() +}) </script> <style scoped lang="scss"> diff --git a/src/views/dashboard/components/DeviceNumberInfo.vue b/src/views/dashboard/components/DeviceNumberInfo.vue index eaff37b..82086ed 100644 --- a/src/views/dashboard/components/DeviceNumberInfo.vue +++ b/src/views/dashboard/components/DeviceNumberInfo.vue @@ -4,7 +4,7 @@ <div class="device-t">鏈満璁惧缂栫爜</div> <div class="device-b"> <div class="device-info"> - {{ deviceInfo?.currentDeviceID }} + {{ deviceInfo?.systemDeviceID }} </div> </div> </div> diff --git a/src/views/dashboard/components/TroubleTrackerModal.vue b/src/views/dashboard/components/TroubleTrackerModal.vue index 31c8c01..d5ef715 100644 --- a/src/views/dashboard/components/TroubleTrackerModal.vue +++ b/src/views/dashboard/components/TroubleTrackerModal.vue @@ -4,17 +4,17 @@ <template #title>闂璇婃柇 </template> <div class="modal-content"> <el-scrollbar always class="scroller"> - <div v-if="fakeTroubles?.length" class="trouble"> - <div v-for="(item, index) in fakeTroubles" :key="index" class="trouble-item"> + <div v-if="problems?.length" class="trouble"> + <div v-for="(item, index) in problems" :key="index" class="trouble-item"> <div class="trouble-content"> <div class="trouble-icon"> - <el-icon v-if="item.status === 2" size="30" color="#ff0000"><WarnTriangleFilled /></el-icon> - <el-icon v-if="item.status === 1" size="30" color="#00ff00"><CircleCheckFilled /></el-icon> + <el-icon v-if="item.CheckResult" size="30" color="#00ff00"><CircleCheckFilled /></el-icon> + <el-icon v-if="!item.CheckResult" size="30" color="#ff0000"><WarnTriangleFilled /></el-icon> </div> - <div class="trouble-text">{{ item.content }}</div> + <div class="trouble-text">{{ item.ItemName }}</div> </div> - <div class="trouble-status" :class="{ green: item.status === 1, red: item.status === 2 }"> - {{ DEVICE_STATUS_NAME_MAP[item.status] }} + <div class="trouble-status" :class="{ green: item.CheckResult, red: !item.CheckResult }"> + {{ item.CheckResult ? '姝e父' : '寮傚父' }} </div> </div> </div> @@ -25,15 +25,18 @@ </template> <script setup lang="ts"> import { useVModel } from '@vueuse/core' -import { ref } from 'vue' import { CircleCheckFilled, WarnTriangleFilled } from '@element-plus/icons-vue' -import { DEVICE_STATUS_NAME_MAP } from '@/common/constants' +import type { Problem } from '@/api/problem' +import { toRefs } from 'vue' export interface TroubleTrackerModalProps { modelValue: boolean + problems?: Problem[] } const props = withDefaults(defineProps<TroubleTrackerModalProps>(), { - modelValue: false + modelValue: false, + problems: undefined }) +const { problems } = toRefs(props) const emit = defineEmits<{ 'update:modelValue': [show: boolean] }>() @@ -42,19 +45,6 @@ function closeModal() { modelData.value = false } - -const fakeTroubles = ref<{ content: string; status: 1 | 2 }[]>([{ content: '浜戠缃戠粶杩炴帴', status: 1 }]) -// TODO: 绛夋帴鍙� -fakeTroubles.value.push( - ...Array(100) - .fill(0) - .map(() => { - return { - content: '浜戠缃戠粶杩炴帴', - status: Math.ceil(Math.random() + 1) - } as { content: string; status: 1 | 2 } - }) -) </script> <style scoped lang="scss"> .modal-content { -- Gitblit v1.8.0