|
|
|
|
@ -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>
|