DeviceBindPanel.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <template>
  2. <div class="w-1/1">
  3. <el-button class="w-1/1" @click="openDrawer">点击配置</el-button>
  4. <el-drawer v-model="drawerVisible" title="配置设备绑定" direction="ltr" size="520px">
  5. <el-empty v-if="!devices.length" description="当前组态项目未绑定设备" />
  6. <template v-else>
  7. <el-form ref="formRef" :model="formModel" label-position="top" size="small">
  8. <div
  9. v-for="(bindItem, index) in formModel.deviceBinds"
  10. :key="bindItem.id"
  11. class="mb-12px">
  12. <el-form-item
  13. label="选择设备"
  14. :prop="`deviceBinds.${index}.deviceId`"
  15. :rules="rules.deviceId">
  16. <el-select
  17. v-model="bindItem.deviceId"
  18. filterable
  19. clearable
  20. class="w-1/1"
  21. placeholder="请选择设备"
  22. :disabled="!bindItem.editing"
  23. @change="onDeviceChange(bindItem)">
  24. <el-option
  25. v-for="device in devices"
  26. :key="device.id"
  27. :label="formatDeviceLabel(device)"
  28. :value="device.id" />
  29. </el-select>
  30. </el-form-item>
  31. <el-form-item
  32. label="设备属性"
  33. :prop="`deviceBinds.${index}.deviceProp`"
  34. :rules="rules.deviceProp">
  35. <el-select
  36. v-model="bindItem.deviceProp"
  37. filterable
  38. clearable
  39. class="w-1/1"
  40. placeholder="请选择设备属性"
  41. :disabled="!bindItem.editing || !bindItem.deviceId">
  42. <el-option
  43. v-for="deviceProp in getDeviceProps(bindItem.deviceId)"
  44. :key="deviceProp.value"
  45. :label="deviceProp.label"
  46. :value="deviceProp.value" />
  47. </el-select>
  48. </el-form-item>
  49. <el-form-item
  50. label="图形属性"
  51. :prop="`deviceBinds.${index}.nodeProp`"
  52. :rules="rules.nodeProp">
  53. <el-select
  54. v-model="bindItem.nodeProp"
  55. filterable
  56. clearable
  57. class="w-1/1"
  58. placeholder="请选择图形属性"
  59. :disabled="!bindItem.editing">
  60. <el-option
  61. v-for="nodeProp in nodePropOptions"
  62. :key="nodeProp.value"
  63. :label="nodeProp.label"
  64. :value="nodeProp.value" />
  65. </el-select>
  66. </el-form-item>
  67. <el-button
  68. v-if="bindItem.editing"
  69. type="success"
  70. size="small"
  71. class="w-1/1"
  72. @click="saveBind(index)">
  73. 绑定
  74. </el-button>
  75. <el-button v-else type="danger" size="small" class="w-1/1" @click="removeBind(index)">
  76. 解绑
  77. </el-button>
  78. <el-divider />
  79. </div>
  80. </el-form>
  81. <el-button type="primary" size="small" class="w-1/1" @click="addBind">新增</el-button>
  82. </template>
  83. </el-drawer>
  84. </div>
  85. </template>
  86. <script setup lang="ts">
  87. import type { WebtopoProjectLinkedDeviceVO } from '@/api/pms/maotu'
  88. import type { IDoneJson, IDoneJsonDeviceBind } from '@/components/mt-edit/store/types'
  89. import { ElMessage, type FormInstance, type FormItemRule } from 'element-plus'
  90. import { computed, reactive, ref } from 'vue'
  91. type DeviceBindRow = IDoneJsonDeviceBind & {
  92. editing?: boolean
  93. }
  94. type Props = {
  95. item: IDoneJson
  96. devices?: WebtopoProjectLinkedDeviceVO[]
  97. }
  98. const props = withDefaults(defineProps<Props>(), {
  99. devices: () => []
  100. })
  101. const drawerVisible = ref(false)
  102. const formRef = ref<FormInstance>()
  103. const formModel = reactive({
  104. deviceBinds: [] as DeviceBindRow[]
  105. })
  106. const rules: Record<string, FormItemRule | FormItemRule[]> = {
  107. deviceId: [{ required: true, message: '请选择设备', trigger: 'change' }],
  108. deviceProp: [{ required: true, message: '请选择设备属性', trigger: 'change' }],
  109. nodeProp: [{ required: true, message: '请选择图形属性', trigger: 'change' }]
  110. }
  111. const nodePropOptions = computed(() => {
  112. return Object.entries(props.item.props || {})
  113. .filter(([, prop]) => !prop.disabled)
  114. .map(([key, prop]) => ({
  115. label: prop.title,
  116. value: `props.${key}.val`
  117. }))
  118. })
  119. function randomId() {
  120. return `device-bind-${Date.now()}-${Math.random().toString(36).slice(2)}`
  121. }
  122. function getChineseName(value?: string) {
  123. return (value || '').split('~~')[0]
  124. }
  125. function formatDeviceLabel(device: WebtopoProjectLinkedDeviceVO) {
  126. return [device.deviceCode, getChineseName(device.deviceName)].filter(Boolean).join(' - ')
  127. }
  128. function updateItemDeviceBinds(item: IDoneJson, deviceBinds: IDoneJsonDeviceBind[]) {
  129. item.deviceBinds = deviceBinds
  130. }
  131. function syncDeviceBinds() {
  132. updateItemDeviceBinds(
  133. props.item,
  134. formModel.deviceBinds.map(({ editing, ...item }) => item)
  135. )
  136. }
  137. async function openDrawer() {
  138. formModel.deviceBinds = (props.item.deviceBinds || []).map((item) => ({
  139. ...item,
  140. editing: false
  141. }))
  142. drawerVisible.value = true
  143. }
  144. function addBind() {
  145. if (formModel.deviceBinds.some((item) => item.editing)) {
  146. ElMessage.error('请先完成当前绑定')
  147. return
  148. }
  149. formModel.deviceBinds.push({
  150. id: randomId(),
  151. deviceId: undefined,
  152. deviceProp: '',
  153. nodeProp: '',
  154. editing: true
  155. })
  156. }
  157. function onDeviceChange(bindItem: DeviceBindRow) {
  158. bindItem.deviceProp = ''
  159. }
  160. function getDeviceProps(deviceId?: number) {
  161. const device = props.devices.find((item) => item.id === deviceId)
  162. return (device?.pointParams || [])
  163. .filter((item) => item.paramCode)
  164. .map((item) => ({
  165. label: item.paramName || item.paramCode!,
  166. value: item.paramCode!
  167. }))
  168. }
  169. async function saveBind(index: number) {
  170. await formRef.value?.validateField([
  171. `deviceBinds.${index}.deviceId`,
  172. `deviceBinds.${index}.deviceProp`,
  173. `deviceBinds.${index}.nodeProp`
  174. ])
  175. formModel.deviceBinds[index].editing = false
  176. syncDeviceBinds()
  177. ElMessage.success('绑定成功')
  178. }
  179. function removeBind(index: number) {
  180. formModel.deviceBinds.splice(index, 1)
  181. syncDeviceBinds()
  182. ElMessage.success('解绑成功')
  183. }
  184. </script>