<!-- Description: 设备管理-指令下发 Author: 李亚光 Date: 2024-09-02 --> <script lang="ts" setup name="instructionIssued"> import { ElMessage, ElMessageBox } from 'element-plus' import editDialog from './components/editDialog.vue' import { getInstructionListPage, removeInstruction } from '@/api/home/device/instruction' import { getDeviceTypeListPage } from '@/api/home/device/type' import { getProductListPage } from '@/api/home/device/product' import { getDictByCode } from '@/api/system/dict' import { shortcuts } from '@/utils/common' import { instructionProductList } from './components/instruction' import { uniqueMultiArray } from '@/utils/Array' import { encrypt, decrypt, isEncrypt } from '@/utils/security1' const $route = useRoute() // 字典 const deviceTypeList = ref<{ id: string; name: string; value: string }[]>([]) // 设备类型 const deviceTypeQueryList = ref<{ id: string; name: string; value: string }[]>([]) // 设备类型 const productList = ref<{ id: string; name: string; value: string }[]>([]) // 产品 const productAllList = ref<{ id: string; name: string; value: string }[]>([]) // 产品 const statusList = ref<{ id: string; name: string; value: string }[]>([]) // 下发状态 // 表格数据 const list = ref([ ]) const total = ref(0) // 初始展示列 const columns = ref<any>([ { text: '设备编号', value: 'devcode', align: 'center', width: '180', isCustom: true }, { text: '设备类型', value: 'deviceTypeName', align: 'center', width: '220' }, { text: '指令内容', value: 'framecontentDesc', align: 'center' }, { text: '下发状态', value: 'statusName', align: 'center', width: '120' }, { text: '操作人员', value: 'operatorName', align: 'center', width: '120' }, { text: '备注', value: 'maker', align: 'center', width: '180' }, { text: '操作时间', value: 'writetime', align: 'center', width: '180' }, ]) // 最终展示列 const columnsConfig = ref([]) // 修改列 const editColumns = (data: any) => { columnsConfig.value = data } const loadingTable = ref(true) // 查询条件 const listQuery = ref({ limit: 20, offset: 1, devcode: '', // 设备编号 deviceType: '', // 设备类型 productId: '', // 产品 status: '', // 下发状态 operatorName: '', // 操作人员 beginTime: '', endTime: '', }) // 开始结束时间 const datetimerange = ref() watch(() => datetimerange.value, (newVal) => { listQuery.value.beginTime = '' listQuery.value.endTime = '' if (Array.isArray(newVal)) { if (newVal.length) { listQuery.value.beginTime = `${newVal[0]}` listQuery.value.endTime = `${newVal[1]}` } } }) // 查询数据 const fetchData = () => { loadingTable.value = true // getInstructionListPage(listQuery.value).then((res) => { list.value = res.data.rows.map((item: any) => ({ ...item, statusName: statusList.value[statusList.value.findIndex(citem => item.status === citem.value)].name, deviceTypeName: deviceTypeList.value[deviceTypeList.value.findIndex(citem => item.deviceType === citem.value)]?.name || '', framecontentDesc: item.framecontentDesc ? item.framecontentDesc : solveInstruction(item, item.framecontent, item.productId), instructionTypeCustrom: typeInstruction(item.productId), // 产品 showDeviceTips: false, // 展示设备编号提示 operatorName: isEncrypt(item.operatorName) ? decrypt(item.operatorName) : item.operatorName, })) // 设备类型和厂商 list.value.forEach((item: any) => { if (productAllList.value.filter((citem) => citem.id === item.productId).length) { item.showDeviceTips = true item.deviceTips = { typeName: productAllList.value.filter((citem) => citem.id === item.productId)[0].deviceTypeName, manufactureName: productAllList.value.filter((citem) => citem.id === item.productId)[0].manufacturerName } } }) total.value = res.data.total loadingTable.value = false }).catch(() => { loadingTable.value = false }) // 解析指令内容成文字 function solveInstruction(row: any, instruction: string, productId: string) { let result = '' // 判断产品和指令 if (!instruction) { result = '' return result } // 当前指令类型 const instructionDevice = { bjwxd: false, // 北京无线电 brsGwsb: false, // 百瑞生-管网哨兵 bfmhkGwsb: false, // 北分麦哈克-管网哨兵 ncxRqznjsz: false // 诺成新-燃气智能警示桩 } as { [key: string]: boolean } // 当前支持下发配置的产品 const productConfig = instructionProductList // 当前产品 for (const i in instructionDevice) { instructionDevice[i] = false } const currentProduct = productAllList.value.filter((item) => item.id === productId)[0] as any const currentProductConfig = productConfig.filter((item: any) => currentProduct.deviceTypeName.includes(item.deviceName) && currentProduct.manufacturerName.includes(item.manufacturerName)) if (currentProductConfig.length) { instructionDevice[currentProductConfig[0].value] = true } // 北京无线电 if (instructionDevice.bjwxd) { result = row.framecontentDesc } // 百瑞生-管网哨兵 else if (instructionDevice.brsGwsb) { const instructionContent = JSON.parse(instruction) const solve = instructionContent.map((item: { command: string, value: string }) => { const content = currentProductConfig[0].instruction[item.command] || '' const switch1 = { 0: '关', 1: '开' } as { [key: string]: string } return `${content.replace('-', '')}:${content.includes('-') ? (switch1[item.value] || '') : item.value}` }) result = solve.join() } // 北分麦哈克-管网哨兵 else if (instructionDevice.bfmhkGwsb) { const instructionContent = JSON.parse(instruction) const solve = instructionContent.map((item: { command: string, value: string }) => { const content = currentProductConfig[0].instruction[item.command] || '' const switch1 = { 0: '关', 1: '开' } as { [key: string]: string } return `${content.replace('-', '')}:${content.includes('-') ? (switch1[item.value] || '') : item.value}` }) result = solve.join() } // 诺成新-燃气智能警示桩 else if (instructionDevice.ncxRqznjsz) { const instructionContent = JSON.parse(instruction) const solve = instructionContent.map((item: { command: string, value: string }) => { if (item.command === 'switch') { let result = [] for (let i = 0; i < item.value.length; i++) { result.push(item.value[i]) } item.value = result.join() } const content = (currentProductConfig[0].instruction[item.command] || '').split(',') const value = item.value.split(',') const switch1 = { 0: '关', 1: '开' } as { [key: string]: string } const str = content.map((citem: string, index: number) => { if (item.command === 'time') { return `${citem}:${value[index].substring(0, 2)}点` } else { return `${citem.replace('-', '')}:${citem.includes('-') ? (switch1[value[index]] || '') : value[index]}` } }) return str.join() }) result = solve.join() } return result } // 当前产品 function typeInstruction(productId: string) { let result = '' if (!productId) { result = '' return result } // 当前指令类型 const instructionDevice = { bjwxd: false, // 北京无线电 brsGwsb: false, // 百瑞生-管网哨兵 bfmhkGwsb: false, // 北分麦哈克-管网哨兵 ncxRqznjsz: false // 诺成新-燃气智能警示桩 } as { [key: string]: boolean } // 当前支持下发配置的产品 const productConfig = instructionProductList // 当前产品 for (const i in instructionDevice) { instructionDevice[i] = false } const currentProduct = productAllList.value.filter((item) => item.id === productId)[0] as any const currentProductConfig = productConfig.filter((item: any) => currentProduct.deviceTypeName.includes(item.deviceName) && currentProduct.manufacturerName.includes(item.manufacturerName)) if (currentProductConfig.length) { instructionDevice[currentProductConfig[0].value] = true result = currentProductConfig[0].value } return result } } // 重置查询条件f const reset = () => { datetimerange.value = [] listQuery.value = { limit: 20, offset: 1, devcode: '', // 设备编号 deviceType: '', // 设备类型 productId: '', // 产品 status: '', // 下发状态 operatorName: '', // 操作人员 beginTime: '', endTime: '', } fetchData() } // 页数发生变化后的操作,可能是页码变化,可能是每页容量变化,此函数必写 const changePage = (val: { size: number; page: number }) => { if (val && val.size) { listQuery.value.limit = val.size } if (val && val.page) { listQuery.value.offset = val.page } fetchData() } // 新建编辑操作 const editRef = ref() const editRow = (type: string, row: any) => { editRef.value.initDialog(type, row) } // 删除 const removeRow = (row: any) => { ElMessageBox.confirm( '确定要删除该指令吗?', '确认操作', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }, ).then(() => { removeInstruction([row.id]).then((response) => { if (response.code === 200) { ElMessage({ message: '删除成功', type: 'success', }) fetchData() } }) }) } // 获取字典 const fetchDict = async () => { // 设备类型 const res = await getDeviceTypeListPage({ offset: 1, limit: 99999 }) deviceTypeList.value = res.data.rows.map((item: any) => ({ name: item.typeName || '', id: item.id, value: item.id, })) // 产品 const res1 = await getProductListPage({ offset: 1, limit: 99999 }) productAllList.value = res1.data.rows productList.value = res1.data.rows.filter((item: any) => instructionProductList.some((citem: any) => item.manufacturerName.includes(citem.manufacturerName) && item.deviceTypeName.includes(citem.deviceName))).map((item: any) => ({ name: item.productName || '', id: item.id, value: item.id, })) deviceTypeQueryList.value = uniqueMultiArray(res1.data.rows.filter((item: any) => instructionProductList.some((citem: any) => item.manufacturerName.includes(citem.manufacturerName) && item.deviceTypeName.includes(citem.deviceName))).map((item: any) => ({ name: item.deviceTypeName, id: item.deviceType, value: item.deviceType, })), 'value') // 下发状态 const res2 = await getDictByCode('issuedStatus') statusList.value = res2.data } onMounted(async () => { await fetchDict() fetchData() // 判断是否 从别处跳转过来(设备详情-控制记录-新建) if ($route.query.row) { editRef.value.initDialog('addOther', {}) } }) const { proxy } = getCurrentInstance() as any // 跳转设备详情 const $router = useRouter() const toDeviceDetail = (row: any) => { // console.log(row, 'row') if (!row.devcode || !row.deviceTypeName) { ElMessage.warning('缺少设备关键信息') return } $router.push({ name: 'DeviceManageDetail', params: { type: 'detail', }, query: { row: JSON.stringify({ devcode: row.devcode, deviceType: row.deviceTypeName, deviceTypeName: row.deviceTypeName, devTypeName: row.deviceTypeName, }), }, }) } </script> <template> <!-- 布局 --> <app-container> <!-- 新建编辑弹窗 --> <edit-dialog ref="editRef" @refresh="fetchData" /> <!-- 筛选条件 --> <search-area :need-clear="true" @search="fetchData" @clear="reset"> <search-item> <el-input v-model="listQuery.devcode" placeholder="设备编号" clearable /> </search-item> <search-item> <el-select v-model="listQuery.deviceType" placeholder="设备类型" clearable filterable class="select" style="width: 192px;"> <el-option v-for="item in deviceTypeQueryList" :key="item.id" :label="item.name" :value="item.value" /> </el-select> </search-item> <search-item> <el-select v-model="listQuery.productId" placeholder="产品" clearable filterable class="select" style="width: 192px;"> <el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.value" /> </el-select> </search-item> <search-item> <el-select v-model="listQuery.status" placeholder="下发状态" clearable filterable class="select" style="width: 192px;"> <el-option v-for="item in statusList" :key="item.id" :label="item.name" :value="item.value" /> </el-select> </search-item> <search-item> <el-input v-model="listQuery.operatorName" placeholder="操作人员" clearable /> </search-item> <search-item> <el-date-picker v-model="datetimerange" type="datetimerange" format="YYYY-MM-DD HH:mm:ss" :shortcuts="shortcuts" value-format="YYYY-MM-DD HH:mm:ss" range-separator="至" start-placeholder="操作开始时间" end-placeholder="操作结束时间" clearable /> </search-item> </search-area> <!-- 表头标题 --> <table-container :is-config="true" config-title="device-instruction" :columns="columns" :config-columns="columnsConfig" :edit="editColumns"> <template #btns-right> <!-- 操作 --> <div> <!-- <el-button v-if="proxy.hasPerm('/device/instruction/batch')" type="primary"> 批量下发 </el-button> --> <el-button v-if="proxy.hasPerm('/device/instruction/add')" type="primary" @click="editRow('add', {})"> 新建 </el-button> </div> </template> <!-- 查询结果Table显示 --> <normal-table :data="list" :total="total" :columns="columnsConfig" :query="listQuery" :list-loading="loadingTable" @change="changePage"> <template #preColumns> <el-table-column label="序号" width="55" align="center"> <template #default="scope"> {{ (listQuery.offset - 1) * listQuery.limit + scope.$index + 1 }} </template> </el-table-column> </template> <template #isCustom="{ scope, column }"> <!-- 设备编号 --> <span v-if="column.text === '设备编号'" class="pointer link" @click="toDeviceDetail(scope.row)"> <el-tooltip v-if="scope.row.showDeviceTips" class="box-item" effect="dark" :content="`${scope.row.deviceTips.typeName}(${scope.row.deviceTips.manufactureName})`" placement="top"> {{ scope.row[column.value] }} </el-tooltip> <template v-else> {{ scope.row[column.value] }} </template> </span> </template> <template #columns> <el-table-column label="操作" align="center" width="120"> <template #default="scope"> <el-button v-if="proxy.hasPerm('/device/instruction/detail')" type="primary" link size="small" @click="editRow('detail', scope.row)"> 查看 </el-button> <el-button v-if="proxy.hasPerm('/device/instruction/again') && scope.row.status === '2'" type="primary" link size="small" @click="editRow('edit', scope.row)"> 重新下发 </el-button> <el-button v-if="proxy.hasPerm('/device/instruction/delete')" type="danger" link size="small" @click="removeRow(scope.row)"> 删除 </el-button> </template> </el-table-column> </template> </normal-table> </table-container> </app-container> </template> <style lang="scss" scoped> .pointer { &:hover { cursor: pointer; } } .link { color: #0d76d4 !important; &:hover { text-decoration: underline !important; } } </style>