feat:设备管理页面对接

master
黄伟杰 2 months ago
parent f84277c967
commit dc5cb0990f

@ -0,0 +1,50 @@
import request from '@/config/axios'
export interface OrgNodeVO {
id?: number | string
customerId?: number | string
parentId?: number | string
nodeType?: number | string
name?: string
sort?: number | string
createTime?: string
children?: OrgNodeVO[]
deviceId?: number | string
}
export interface OrgNodeQuery {
customerId?: number | string
}
export interface OrgNodeSaveReqVO {
id?: number | string
customerId?: number | string
parentId: number | string
nodeType: number | string
name: string
sort?: number | string
createTime?: string
}
export interface OrgNodeDeviceListReqVO {
nodeId: number | string
nodeType: number | string
}
export const OrgNodeApi = {
getOrgNodeTree: async (params?: OrgNodeQuery) => {
return await request.get<OrgNodeVO[]>({ url: '/iot/org-node/tree', params })
},
createOrgNode: async (data: OrgNodeSaveReqVO) => {
return await request.post({ url: '/iot/org-node/create', data })
},
updateOrgNode: async (data: OrgNodeSaveReqVO) => {
return await request.put({ url: '/iot/org-node/update', data })
},
getDeviceListByNode: async (params: OrgNodeDeviceListReqVO) => {
return await request.get({ url: '/iot/org-node/device-list-by-node', params })
},
deleteOrgNode: async (id: number | string) => {
return await request.delete({ url: '/iot/org-node/delete?id=' + id })
}
}

@ -732,7 +732,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
hidden: true,
activeMenu: '/iot/device/device'
},
component: () => import('@/views/iot/device/index.vue')
component: () => import('@/views/iot/device/management/index.vue')
},
{
path: 'ota/operation/firmware/detail/:id',

@ -0,0 +1,319 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="680px" :fullscreen="false">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="110px"
v-loading="formLoading"
>
<el-form-item label="父组织" prop="parentId">
<el-tree-select
v-model="formData.parentId"
:data="parentTreeOptions"
:props="treeProps"
node-key="id"
check-strictly
clearable
filterable
:render-after-expand="false"
placeholder="请选择父组织"
class="!w-full"
/>
</el-form-item>
<el-form-item label="节点类型" prop="nodeType">
<el-radio-group v-model="formData.nodeType">
<el-radio v-for="item in currentNodeTypeOptions" :key="item.value" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<template v-if="formData.nodeType === 4">
<el-form-item label="设备编号" prop="deviceCode">
<el-input v-model="formData.deviceCode" :disabled="formType === 'update'" />
</el-form-item>
<el-form-item label="设备名称" prop="deviceName">
<el-input v-model="formData.deviceName" />
</el-form-item>
<el-form-item label="设备模型" prop="deviceModelId">
<el-select
v-model="formData.deviceModelId"
clearable
filterable
:disabled="formType === 'update'"
placeholder="请选择设备模型"
class="!w-full"
>
<el-option
v-for="item in modelList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</template>
<template v-else>
<el-form-item label="节点名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入节点名称" />
</el-form-item>
</template>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="formLoading" @click="submitForm"></el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DeviceApi } from '@/api/iot/device'
import { DeviceModelApi, DeviceModelVO } from '@/api/iot/devicemodel'
import { OrgNodeApi } from '@/api/iot/orgNode'
import { getIntDictOptions } from '@/utils/dict'
type TreeNode = {
id: string
deviceId?: string
parentId?: string
customerId?: string
nodeType?: number
name: string
children?: TreeNode[]
}
defineOptions({ name: 'IoTDeviceManagementNodeForm' })
const props = defineProps<{
treeData: TreeNode[]
customerId?: string
}>()
const emit = defineEmits<{
success: []
}>()
const { t } = useI18n()
const message = useMessage()
const dialogVisible = ref(false)
const formLoading = ref(false)
const formType = ref<'create' | 'update'>('create')
const dialogTitle = computed(() =>
formType.value === 'create' ? t('action.create') : t('action.update')
)
const formRef = ref()
const modelList = ref<DeviceModelVO[]>([])
const treeProps = { children: 'children', label: 'name', value: 'id' }
const currentParentNode = ref<TreeNode>()
const formData = ref({
id: undefined as number | undefined,
customerId: undefined as number | undefined,
parentId: undefined as string | undefined,
nodeType: 2,
name: '',
deviceCode: '',
deviceName: '',
deviceModelId: undefined as number | undefined
})
const nodeTypeOptions = computed(() => {
const list = getIntDictOptions('iot_node_type').filter((item) => [2, 3, 4].includes(item.value))
if (list.length) return list
return [
{ label: '车间', value: 2 },
{ label: '产线', value: 3 },
{ label: '设备', value: 4 }
]
})
const currentNodeTypeOptions = computed(() => {
const parentType = Number(currentParentNode.value?.nodeType || 1)
const allowed =
parentType === 2 ? [3, 4] : parentType === 3 ? [4] : parentType === 1 ? [2, 3, 4] : []
return nodeTypeOptions.value.filter((item) => allowed.includes(item.value))
})
const parentTreeOptions = computed(() => {
const filterNode = (nodes: TreeNode[]): TreeNode[] => {
return nodes
.filter((node) => Number(node.nodeType) !== 4)
.map((node) => ({
...node,
children: node.children?.length ? filterNode(node.children) : []
}))
}
return filterNode(props.treeData || [])
})
const formRules = computed(() => {
const common = {
parentId: [{ required: true, message: '父组织不能为空', trigger: 'change' }],
nodeType: [{ required: true, message: '节点类型不能为空', trigger: 'change' }]
}
if (formData.value.nodeType === 4) {
return {
...common,
deviceCode: [{ required: true, message: '设备编号不能为空', trigger: 'blur' }],
deviceName: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
deviceModelId: [{ required: true, message: '设备模型不能为空', trigger: 'change' }]
}
}
return {
...common,
name: [{ required: true, message: '节点名称不能为空', trigger: 'blur' }]
}
})
const getDefaultNodeType = (parent?: TreeNode) => {
const parentType = Number(parent?.nodeType || 1)
if (parentType === 2) return 3
if (parentType === 3) return 4
return 2
}
const loadModels = async () => {
if (modelList.value.length) return
const data = await DeviceModelApi.getDeviceModelList()
modelList.value = Array.isArray(data) ? data : []
}
watch(
() => formData.value.nodeType,
async (nodeType) => {
if (nodeType === 4) {
await loadModels()
}
}
)
const findNodeById = (id?: string): TreeNode | undefined => {
if (!id) return undefined
const stack = [...(props.treeData || [])]
while (stack.length) {
const node = stack.shift()!
if (node.id === id) return node
if (node.children?.length) stack.push(...node.children)
}
return undefined
}
const getCustomerIdByNode = (node?: TreeNode) => {
if (!node) return Number(props.customerId || '') || undefined
if (Number(node.nodeType) === 1) {
return Number(node.customerId || node.id || props.customerId || '') || undefined
}
let current = node
while (current) {
if (Number(current.nodeType) === 1) {
return Number(current.customerId || current.id || props.customerId || '') || undefined
}
current = findNodeById(current.parentId)
}
return Number(props.customerId || '') || undefined
}
const open = async (type: 'create' | 'update', node?: TreeNode, defaultParentId?: string) => {
formType.value = type
formRef.value?.resetFields()
if (type === 'create') {
currentParentNode.value = node
const nodeType = getDefaultNodeType(node)
const initialParentId = Number(node?.nodeType) === 1 ? '0' : defaultParentId || node?.id
formData.value = {
id: undefined,
customerId: getCustomerIdByNode(node),
parentId: initialParentId,
nodeType,
name: '',
deviceCode: '',
deviceName: '',
deviceModelId: undefined
}
if (
currentNodeTypeOptions.value.length &&
!currentNodeTypeOptions.value.find((item) => item.value === formData.value.nodeType)
) {
formData.value.nodeType = currentNodeTypeOptions.value[0].value
}
} else {
currentParentNode.value = findNodeById(node?.parentId)
const deviceId =
Number(node?.deviceId || '') ||
(Number(node?.nodeType) === 4 ? Number(node?.id || '') : undefined)
formData.value = {
id: deviceId || Number(node?.id),
customerId: getCustomerIdByNode(currentParentNode.value || node),
parentId: node?.parentId,
nodeType: Number(node?.nodeType || 2),
name: node?.name || '',
deviceCode: '',
deviceName: '',
deviceModelId: undefined
}
if (Number(node?.nodeType) === 4 && deviceId) {
const device = await DeviceApi.getDevice(deviceId)
formData.value.deviceCode = device?.deviceCode || ''
formData.value.deviceName = device?.deviceName || ''
formData.value.deviceModelId = device?.deviceModelId
formData.value.customerId =
Number(device?.customerId || formData.value.customerId || props.customerId || '') ||
undefined
}
}
if (formData.value.nodeType === 4) {
await loadModels()
}
dialogVisible.value = true
}
defineExpose({ open })
const submitForm = async () => {
await formRef.value.validate()
if (!formData.value.customerId) {
message.warning('未识别到客户ID请检查树节点数据')
return
}
const parentId =
formType.value === 'create' && Number(currentParentNode.value?.nodeType) === 1
? 0
: Number(formData.value.parentId)
const payload = {
customerId: Number(formData.value.customerId),
parentId,
nodeType: Number(formData.value.nodeType),
name: formData.value.name?.trim()
}
formLoading.value = true
try {
if (formData.value.nodeType === 4) {
const devicePayload: any = {
customerId: payload.customerId,
parentId: payload.parentId,
nodeType: payload.nodeType,
deviceCode: formData.value.deviceCode?.trim(),
deviceName: formData.value.deviceName?.trim(),
deviceModelId: formData.value.deviceModelId,
isEnable: false
}
if (formType.value === 'update' && formData.value.id) {
devicePayload.id = formData.value.id
await DeviceApi.updateDevice(devicePayload)
message.success(t('common.updateSuccess'))
} else {
await DeviceApi.createDevice(devicePayload)
message.success(t('common.createSuccess'))
}
} else if (formType.value === 'create') {
await OrgNodeApi.createOrgNode(payload as any)
message.success(t('common.createSuccess'))
} else {
await OrgNodeApi.updateOrgNode({ ...(payload as any), id: formData.value.id })
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
emit('success')
} finally {
formLoading.value = false
}
}
</script>

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save