Merge branch 'dev' of http://192.168.5.5:10010/r/web/bulletin-board-style1 into wn
| | |
| | | "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", |
| | |
| | | "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", |
| | |
| | | "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", |
| | |
| | | "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", |
| | |
| | | export interface Devices { |
| | | /** 本机设备编码 */ |
| | | systemDeviceID: string |
| | | currentDeviceID: string |
| | | systemDeviceStatus: number |
| | |
| | | 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 |
| | |
| | | data: params |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * 获取问题诊断问题列表 |
| | | */ |
| | | export function apiGetProblemList() { |
| | | return request<BaseResponse<Problem[]>>({ |
| | | url: '/v1/system/problemList', |
| | | method: 'get' |
| | | }) |
| | | } |
New file |
| | |
| | | export interface Problem { |
| | | /** true正常 false异常 */ |
| | | CheckResult: boolean |
| | | ItemCode: string |
| | | ItemName: string |
| | | } |
| | |
| | | startTime: number |
| | | endTime: number |
| | | workHours: string |
| | | inputMaterials: inputMaterial[] |
| | | outputMaterials: inputMaterial[] |
| | | inputMaterials: Material[] |
| | | outputMaterials: Material[] |
| | | workers: Worker[] |
| | | allProcedureNames: string[] |
| | | channel: number |
| | |
| | | CurrentProcedureIndex: number |
| | | CanStarted: boolean |
| | | } |
| | | export interface inputMaterial { |
| | | export interface Material { |
| | | materialId: string |
| | | materialName: string |
| | | amount: number |
| | | unit: string |
| | | background: string |
| | | date: string |
| | | } |
| | | |
| | |
| | | 7: 'G' |
| | | } |
| | | |
| | | export const DEVICE_STATUS_NAME_MAP = { |
| | | 1: '正常', |
| | | 2: '异常' |
| | | } |
| | | // plc 轮询间隔 |
| | | export const PLC_POLLING_DURATION = 6_000 |
| | | // 设备信息 轮询间隔 |
| | | export const DEVICE_INFO_POLLING_DURATION = 15_000 |
| | | // 问题诊断 |
| | | export const PROBLEMS_POLLING_DURATION = 30_000 |
| | |
| | | <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> |
| | |
| | | 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(() => { |
| | |
| | | cancel: cancelDevicePolling |
| | | } = useRequest(getDeviceList, { |
| | | manual: true, |
| | | pollingInterval: 6000, |
| | | pollingInterval: DEVICE_INFO_POLLING_DURATION, |
| | | pollingWhenHidden: false |
| | | }) |
| | | |
| | |
| | | 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() |
| | |
| | | } as ProductProgressParams), |
| | | { |
| | | manual: true, |
| | | pollingInterval: 6000, |
| | | pollingInterval: PLC_POLLING_DURATION, |
| | | pollingWhenHidden: false |
| | | } |
| | | ) |
| | |
| | | <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状态, 问题列表中有一条代表云端链接的, 异常即为红色云icon 否则是绿色 true绿云 |
| | | const cloudConnectionIconStatus = computed(() => { |
| | | if (!problemList.value || !problemList.value?.length) { |
| | | // 默认绿灯, 拿到一次数据后才以接口为准 |
| | | return true |
| | | } |
| | | // 没数据就当是链接正常 |
| | | 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"> |
| | |
| | | <div class="device-t">本机设备编码</div> |
| | | <div class="device-b"> |
| | | <div class="device-info"> |
| | | {{ deviceInfo?.currentDeviceID }} |
| | | {{ deviceInfo?.systemDeviceID }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | </div> |
| | | <el-scrollbar always class="scroller"> |
| | | <div class="materials-b"> |
| | | <div v-for="item in inputMaterials" :key="item.materialId"> |
| | | <InputOutMaterialInfo :item="item" :background="item.background"></InputOutMaterialInfo> |
| | | <div v-for="item in props.materialList" :key="item.materialId"> |
| | | <InputOutMaterialInfo :material="item" @detail-click="onDetailClick"></InputOutMaterialInfo> |
| | | </div> |
| | | </div> |
| | | </el-scrollbar> |
| | |
| | | <script setup lang="ts"> |
| | | import InputOutMaterialInfo from '@/views/dashboard/components/InputOutMaterialInfo.vue' |
| | | import BigButton from '@/views/dashboard/components/BigButton.vue' |
| | | import { toRefs } from 'vue' |
| | | const inputMaterials = [ |
| | | { |
| | | materialId: '1111', |
| | | materialName: '输入名称', |
| | | amount: 10, |
| | | unit: '个', |
| | | date: 10 |
| | | }, |
| | | { |
| | | materialId: '2222222222222222', |
| | | materialName: '输入名称2', |
| | | amount: 20, |
| | | unit: '个', |
| | | background: '#33ccff' |
| | | } |
| | | ] |
| | | import type { Material } from '@/api/task' |
| | | |
| | | const props = defineProps<{ |
| | | materialList?: Material[] |
| | | }>() |
| | | const emits = defineEmits<{ |
| | | detailClick: [material: Material] |
| | | }>() |
| | | |
| | | function onDetailClick(material: Material) { |
| | | emits('detailClick', material) |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | |
| | | <div class="card-t-t card_drop"> |
| | | <el-popover :width="200" placement="top-start" trigger="click"> |
| | | <template #reference> |
| | | {{ item.materialId }} |
| | | {{ material.materialId }} |
| | | </template> |
| | | {{ item.materialId }} |
| | | {{ material.materialId }} |
| | | </el-popover> |
| | | </div> |
| | | <div class="card-t-b"> |
| | | 设备12 |
| | | <el-icon class="right-arrow"> |
| | | <Right /> |
| | | </el-icon> |
| | | 设备13 |
| | | <!-- TODO: 接口缺失数据, 待添加--> |
| | | <!-- 设备12--> |
| | | <!-- <el-icon class="right-arrow">--> |
| | | <!-- <Right />--> |
| | | <!-- </el-icon>--> |
| | | <!-- 设备13--> |
| | | </div> |
| | | </div> |
| | | <div class="card-b"> |
| | | <div class="card_drop card-b-l"> |
| | | <el-popover :width="200" placement="top-start" trigger="click"> |
| | | <template #reference> |
| | | {{ item.materialName }} |
| | | {{ material.materialName }} |
| | | </template> |
| | | {{ item.materialName }} |
| | | {{ material.materialName }} |
| | | </el-popover> |
| | | </div> |
| | | <div class="card-b-r"> |
| | | <el-popover v-if="item.date" popper-class="card-info" :width="110" placement="top" trigger="click"> |
| | | <template #reference> {{ item.amount }} {{ item.unit }} </template> |
| | | 预计{{ item.date }}分钟送达 |
| | | <el-popover v-if="material.date" popper-class="card-info" :width="110" placement="top" trigger="click"> |
| | | <template #reference> {{ material.amount }} {{ material.unit }} </template> |
| | | 预计{{ material.date }}分钟送达 |
| | | </el-popover> |
| | | <div v-else>{{ item.amount }} {{ item.unit }}</div> |
| | | <div v-else>{{ material.amount }} {{ material.unit }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <MaterialDetails v-model="showModal"></MaterialDetails> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import type { inputMaterial } from '@/api/task' |
| | | import MaterialDetails from '@/views/dashboard/components/MaterialDetails.vue' |
| | | import { Right } from '@element-plus/icons-vue' |
| | | import { ref, toRefs } from 'vue' |
| | | import type { Material } from '@/api/task' |
| | | import { toRefs } from 'vue' |
| | | export interface InputOutMaterialInfoProps { |
| | | item: inputMaterial |
| | | background?: string |
| | | material: Material |
| | | // TODO: 接口还不支持, 预留 |
| | | type?: '已送达' | '运输中' |
| | | } |
| | | |
| | | const props = withDefaults(defineProps<InputOutMaterialInfoProps>(), { |
| | | background: '#ffcc00' |
| | | }) |
| | | const { item, background } = toRefs(props) |
| | | const showModal = ref(false) |
| | | |
| | | const props = defineProps<InputOutMaterialInfoProps>() |
| | | const { material } = toRefs(props) |
| | | const emits = defineEmits<{ |
| | | detailClick: [material: Material] |
| | | }>() |
| | | function materialInfoClick() { |
| | | showModal.value = true |
| | | emits('detailClick', material.value) |
| | | } |
| | | </script> |
| | | |
| | |
| | | font-size: 12px; |
| | | color: #333; |
| | | padding: 3px 5px; |
| | | // background: $status-done; |
| | | background-color: v-bind(background); |
| | | background: $status-done; |
| | | text-align: left; |
| | | .card-t-t { |
| | | width: 100%; |
| | |
| | | background: red !important; |
| | | font-size: 12px; |
| | | color: #fff; |
| | | border: 0px; |
| | | border: 0; |
| | | border-radius: 10px; |
| | | // height:20px!important; |
| | | line-height: 8px !important; |
| | |
| | | <BaseModal v-model="modelData" :wider="true" @close="closeModal"> |
| | | <template #title>物料详情 </template> |
| | | <div class="details-box"> |
| | | <div class="details-t"> |
| | | <div class="details-t-t">{{ materialObj.form.materialId }}</div> |
| | | <div v-if="material" class="details-t"> |
| | | <div class="details-t-t">{{ material.materialId }}</div> |
| | | <div class="details-t-b"> |
| | | <div class="details-t-b-l"> |
| | | <div class="item">物料名称:{{ materialObj.form.materialName }}</div> |
| | | <div class="item">数量:{{ materialObj.form.amount }}</div> |
| | | <div class="item">物料规格:{{ materialObj.form.amount }}</div> |
| | | <div class="item">物料类型:{{ materialObj.form.amount }}</div> |
| | | <div class="item">物料名称:{{ material.materialName }}</div> |
| | | <div class="item">数量:{{ material.amount }}</div> |
| | | <div class="item">物料规格:{{ material.amount }}</div> |
| | | <div class="item">物料类型:{{ material.amount }}</div> |
| | | </div> |
| | | <BigButton class="btn" bg-color="#03d203f0">已送达</BigButton> |
| | | <!-- TODO: 物料送达缺接口--> |
| | | <BigButton v-if="false" class="btn" bg-color="#03d203f0">已送达</BigButton> |
| | | </div> |
| | | </div> |
| | | <div class="details-b"> |
| | | |
| | | <!-- TODO: 物料送达缺接口--> |
| | | <div v-if="false" class="details-b"> |
| | | <div class="details-b-t">运输详情</div> |
| | | |
| | | <div class="details-b-b"> |
| | |
| | | <script setup lang="ts"> |
| | | import { useVModel } from '@vueuse/core' |
| | | import BigButton from '@/views/dashboard/components/BigButton.vue' |
| | | import { ref } from 'vue' |
| | | import type { Material } from '@/api/task' |
| | | export interface MaterialDetailsProps { |
| | | material?: Material |
| | | modelValue: boolean |
| | | } |
| | | const props = withDefaults(defineProps<MaterialDetailsProps>(), { |
| | | material: undefined, |
| | | modelValue: false |
| | | }) |
| | | const emit = defineEmits<{ |
| | |
| | | function closeModal() { |
| | | modelData.value = false |
| | | } |
| | | // 假数据 |
| | | const materialObj = { |
| | | form: { |
| | | materialId: '1111', |
| | | materialName: '输入名称', |
| | | amount: 10, |
| | | unit: '个', |
| | | date: 10 |
| | | }, |
| | | materialFlow: [ |
| | | { |
| | | label: '已送达', |
| | |
| | | </div> |
| | | <el-scrollbar always class="scroller"> |
| | | <div class="materials-b"> |
| | | <div v-for="item in outputMaterials" :key="item.materialId"> |
| | | <InputOutMaterialInfo :item="item" :background="item.background"></InputOutMaterialInfo> |
| | | <div v-for="item in props.materialList" :key="item.materialId"> |
| | | <InputOutMaterialInfo :material="item" @detail-click="onDetailClick"></InputOutMaterialInfo> |
| | | </div> |
| | | </div> |
| | | </el-scrollbar> |
| | |
| | | <script setup lang="ts"> |
| | | import InputOutMaterialInfo from '@/views/dashboard/components/InputOutMaterialInfo.vue' |
| | | import BigButton from '@/views/dashboard/components/BigButton.vue' |
| | | import { toRefs } from 'vue' |
| | | const outputMaterials = [ |
| | | { |
| | | materialId: '1111', |
| | | materialName: '输入名称', |
| | | amount: 10, |
| | | unit: '个' |
| | | }, |
| | | { |
| | | materialId: '2222222222222222', |
| | | materialName: '输入名称2', |
| | | amount: 20, |
| | | unit: '个', |
| | | background: '#33ccff' |
| | | }, |
| | | { |
| | | materialId: '1111', |
| | | materialName: '输入名称', |
| | | amount: 10, |
| | | unit: '个' |
| | | }, |
| | | { |
| | | materialId: '2222222222222222', |
| | | materialName: '输入名称2', |
| | | amount: 20, |
| | | unit: '个', |
| | | background: '#33ccff' |
| | | }, |
| | | { |
| | | materialId: '1111', |
| | | materialName: '输入名称', |
| | | amount: 10, |
| | | unit: '个' |
| | | }, |
| | | { |
| | | materialId: '2222222222222222', |
| | | materialName: '输入名称2', |
| | | amount: 20, |
| | | unit: '个', |
| | | background: '#33ccff' |
| | | }, |
| | | { |
| | | materialId: '2222222222222222', |
| | | materialName: '输入名称2', |
| | | amount: 20, |
| | | unit: '个', |
| | | background: '#33ccff' |
| | | } |
| | | ] |
| | | import type { Material } from '@/api/task' |
| | | |
| | | const props = defineProps<{ |
| | | materialList?: Material[] |
| | | }>() |
| | | const emits = defineEmits<{ |
| | | detailClick: [material: Material] |
| | | }>() |
| | | |
| | | function onDetailClick(material: Material) { |
| | | emits('detailClick', material) |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | |
| | | <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 ? '正常' : '异常' }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | </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] |
| | | }>() |
| | |
| | | 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 { |
| | |
| | | ></ProcessInfo> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="物料清单" name="物料清单"> |
| | | <InputMaterialsList></InputMaterialsList> |
| | | <OutputMaterialsList></OutputMaterialsList> |
| | | <InputMaterialsList |
| | | :material-list="activeTask?.Procedure.procedure.inputMaterials" |
| | | @detail-click="showMaterialDetailModal" |
| | | ></InputMaterialsList> |
| | | <OutputMaterialsList |
| | | :material-list="activeTask?.Procedure.procedure.outputMaterials" |
| | | @detail-click="showMaterialDetailModal" |
| | | ></OutputMaterialsList> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </template> |
| | |
| | | <div class="task-detail"> |
| | | <TaskControl :task="activeTask" @should-reload="reloadAllData"></TaskControl> |
| | | </div> |
| | | <ColorInfo :order="order" :type="1"></ColorInfo> |
| | | <ColorInfo :order="order" :type="2"></ColorInfo> |
| | | <ColorInfo :type="1"></ColorInfo> |
| | | <ColorInfo :type="2"></ColorInfo> |
| | | </template> |
| | | <template #middleBlock4> |
| | | <SubTitle>人员信息</SubTitle> |
| | |
| | | </template> |
| | | </DashboardLayout> |
| | | <CraftDetailModal v-model="showCraftModelDetail" @close="showCraftModelDetail = false"></CraftDetailModal> |
| | | <MaterialDetails v-model="showMaterialDetail" :material="currentMaterialInfo"></MaterialDetails> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import { computed, ref, watch } from 'vue' |
| | | import ChannelCollapse from '@/views/dashboard/components/ChannelCollapse.vue' |
| | | import type { Worker, Order, Task } from '@/api/task' |
| | | import type { Worker, Order, Task, Material } from '@/api/task' |
| | | import PersonInfo from '@/views/dashboard/components/PersonInfo.vue' |
| | | import ProcessInfo from '@/views/dashboard/components/ProcessInfo.vue' |
| | | import ColorInfo from '@/views/dashboard/components/ColorInfo.vue' |
| | |
| | | import { useDevicesStore } from '@/stores/devices' |
| | | import { useCraftModelStore } from '@/stores/craftModel' |
| | | import CraftDetailModal from '@/views/dashboard/components/CraftDetailModal.vue' |
| | | import MaterialDetails from '@/views/dashboard/components/MaterialDetails.vue' |
| | | |
| | | defineOptions({ |
| | | name: 'DashboardView' |
| | |
| | | const taskStore = useTasksStore() |
| | | const workers = computed(() => { |
| | | return taskStore.activeTask?.Procedure?.procedure?.workers ?? [] |
| | | }) |
| | | |
| | | const process = computed(() => { |
| | | return { product: '产品名称', number: '111', procedure: '工艺名称', isUpdate: true } as any |
| | | }) |
| | | |
| | | const order = computed(() => { |
| | |
| | | console.log(1) |
| | | showCraftModelDetail.value = true |
| | | } |
| | | |
| | | // 是否展示物料详情弹窗 |
| | | const showMaterialDetail = ref(false) |
| | | // 当前要展示的物料详情 |
| | | const currentMaterialInfo = ref<Material>() |
| | | |
| | | /** |
| | | * 显示物料详情弹窗 |
| | | * @param material |
| | | */ |
| | | function showMaterialDetailModal(material: Material) { |
| | | currentMaterialInfo.value = material |
| | | showMaterialDetail.value = true |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |