ThingModelStructDataSpecs.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <!-- dataType:struct 数组类型 -->
  2. <template>
  3. <!-- struct 数据展示 -->
  4. <el-form-item
  5. :rules="[{ required: true, validator: validateList, trigger: 'change' }]"
  6. label="JSON 对象"
  7. >
  8. <div
  9. v-for="(item, index) in dataSpecsList"
  10. :key="index"
  11. class="w-1/1 struct-item flex justify-between px-10px mb-10px"
  12. >
  13. <span>参数名称:{{ item.name }}</span>
  14. <div class="btn">
  15. <el-button link type="primary" @click="openStructForm(item)">编辑</el-button>
  16. <el-divider direction="vertical" />
  17. <el-button link type="danger" @click="deleteStructItem(index)">删除</el-button>
  18. </div>
  19. </div>
  20. <el-button link type="primary" @click="openStructForm(null)">+新增参数</el-button>
  21. </el-form-item>
  22. <!-- struct 表单 -->
  23. <Dialog v-model="dialogVisible" :title="dialogTitle" append-to-body>
  24. <el-form
  25. ref="structFormRef"
  26. v-loading="formLoading"
  27. :model="formData"
  28. :rules="ThingModelFormRules"
  29. label-width="100px"
  30. >
  31. <el-form-item label="参数名称" prop="name">
  32. <el-input v-model="formData.name" placeholder="请输入功能名称" />
  33. </el-form-item>
  34. <el-form-item label="标识符" prop="identifier">
  35. <el-input v-model="formData.identifier" placeholder="请输入标识符" />
  36. </el-form-item>
  37. <!-- 属性配置 -->
  38. <ThingModelProperty v-model="formData.property" is-struct-data-specs />
  39. </el-form>
  40. <template #footer>
  41. <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
  42. <el-button @click="dialogVisible = false">取 消</el-button>
  43. </template>
  44. </Dialog>
  45. </template>
  46. <script lang="ts" setup>
  47. import { useVModel } from '@vueuse/core'
  48. import ThingModelProperty from '../ThingModelProperty.vue'
  49. import { DataSpecsDataType, ThingModelFormRules } from '../config'
  50. import { isEmpty } from '@/utils/is'
  51. /** Struct 型的 dataSpecs 配置组件 */
  52. defineOptions({ name: 'ThingModelStructDataSpecs' })
  53. const props = defineProps<{ modelValue: any }>()
  54. const emits = defineEmits(['update:modelValue'])
  55. const dataSpecsList = useVModel(props, 'modelValue', emits) as Ref<any[]>
  56. const dialogVisible = ref(false) // 弹窗的是否展示
  57. const dialogTitle = ref('新增参数') // 弹窗的标题
  58. const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  59. const structFormRef = ref() // 表单 ref
  60. const formData = ref<any>({
  61. property: {
  62. dataType: DataSpecsDataType.INT,
  63. dataSpecs: {
  64. dataType: DataSpecsDataType.INT
  65. }
  66. }
  67. })
  68. /** 打开 struct 表单 */
  69. const openStructForm = (val: any) => {
  70. dialogVisible.value = true
  71. resetForm()
  72. if (isEmpty(val)) {
  73. return
  74. }
  75. // 编辑时回显数据
  76. formData.value = {
  77. identifier: val.identifier,
  78. name: val.name,
  79. description: val.description,
  80. property: {
  81. dataType: val.childDataType,
  82. dataSpecs: val.dataSpecs,
  83. dataSpecsList: val.dataSpecsList
  84. }
  85. }
  86. }
  87. /** 删除 struct 项 */
  88. const deleteStructItem = (index: number) => {
  89. dataSpecsList.value.splice(index, 1)
  90. }
  91. /** 添加参数 */
  92. const submitForm = async () => {
  93. await structFormRef.value.validate()
  94. try {
  95. const data = unref(formData)
  96. // 构建数据对象
  97. const item = {
  98. identifier: data.identifier,
  99. name: data.name,
  100. description: data.description,
  101. dataType: DataSpecsDataType.STRUCT,
  102. childDataType: data.property.dataType,
  103. dataSpecs:
  104. !!data.property.dataSpecs && Object.keys(data.property.dataSpecs).length > 1
  105. ? data.property.dataSpecs
  106. : undefined,
  107. dataSpecsList: isEmpty(data.property.dataSpecsList) ? undefined : data.property.dataSpecsList
  108. }
  109. // 查找是否已有相同 identifier 的项
  110. const existingIndex = dataSpecsList.value.findIndex(
  111. (spec) => spec.identifier === data.identifier
  112. )
  113. if (existingIndex > -1) {
  114. // 更新已有项
  115. dataSpecsList.value[existingIndex] = item
  116. } else {
  117. // 添加新项
  118. dataSpecsList.value.push(item)
  119. }
  120. } finally {
  121. // 隐藏对话框
  122. dialogVisible.value = false
  123. }
  124. }
  125. /** 重置表单 */
  126. const resetForm = () => {
  127. formData.value = {
  128. property: {
  129. dataType: DataSpecsDataType.INT,
  130. dataSpecs: {
  131. dataType: DataSpecsDataType.INT
  132. }
  133. }
  134. }
  135. structFormRef.value?.resetFields()
  136. }
  137. /** 校验 struct 不能为空 */
  138. const validateList = (_: any, __: any, callback: any) => {
  139. if (isEmpty(dataSpecsList.value)) {
  140. callback(new Error('struct 不能为空'))
  141. return
  142. }
  143. callback()
  144. }
  145. /** 组件初始化 */
  146. onMounted(async () => {
  147. await nextTick()
  148. // 预防 dataSpecsList 空指针
  149. isEmpty(dataSpecsList.value) && (dataSpecsList.value = [])
  150. })
  151. </script>
  152. <style lang="scss" scoped>
  153. .struct-item {
  154. background-color: #e4f2fd;
  155. }
  156. </style>