ThingModelStructDataSpecs.vue 4.5 KB

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