ThinkModelFunctionForm.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <template>
  2. <Dialog :title="dialogTitle" v-model="dialogVisible">
  3. <el-form
  4. ref="formRef"
  5. :model="formData"
  6. :rules="formRules"
  7. label-width="100px"
  8. v-loading="formLoading"
  9. >
  10. <el-form-item label="功能类型" prop="type">
  11. <el-radio-group v-model="formData.type">
  12. <el-radio-button value="1"> 属性 </el-radio-button>
  13. <el-radio-button value="2"> 服务 </el-radio-button>
  14. <el-radio-button value="3"> 事件 </el-radio-button>
  15. </el-radio-group>
  16. </el-form-item>
  17. <el-form-item label="功能名称" prop="name">
  18. <el-input v-model="formData.name" placeholder="请输入功能名称" />
  19. </el-form-item>
  20. <el-form-item label="标识符" prop="identifier">
  21. <el-input
  22. v-model="formData.identifier"
  23. placeholder="请输入标识符"
  24. :disabled="formType === 'update'"
  25. />
  26. </el-form-item>
  27. <el-form-item label="数据类型" prop="type">
  28. <el-select
  29. v-model="formData.property.dataType.type"
  30. placeholder="请选择数据类型"
  31. :disabled="formType === 'update'"
  32. >
  33. <el-option key="int" label="int32 (整数型)" value="int" />
  34. <el-option key="float" label="float (单精度浮点型)" value="float" />
  35. <el-option key="double" label="double (双精度浮点型)" value="double" />
  36. <!-- <el-option key="text" label="text (文本型)" value="text" />-->
  37. <!-- <el-option key="date" label="date (日期型)" value="date" />-->
  38. <!-- <el-option key="bool" label="bool (布尔型)" value="bool" />-->
  39. <!-- <el-option key="enum" label="enum (枚举型)" value="enum" />-->
  40. <!-- <el-option key="struct" label="struct (结构体)" value="struct" />-->
  41. <!-- <el-option key="array" label="array (数组)" value="array" />-->
  42. </el-select>
  43. </el-form-item>
  44. <el-form-item label="取值范围" prop="max">
  45. <el-input v-model="formData.property.dataType.specs.min" placeholder="请输入最小值" />
  46. <span class="mx-2">~</span>
  47. <el-input v-model="formData.property.dataType.specs.max" placeholder="请输入最大值" />
  48. </el-form-item>
  49. <el-form-item label="步长" prop="step">
  50. <el-input v-model="formData.property.dataType.specs.step" placeholder="请输入步长" />
  51. </el-form-item>
  52. <el-form-item label="单位" prop="unit">
  53. <el-input v-model="formData.property.dataType.specs.unit" placeholder="请输入单位" />
  54. </el-form-item>
  55. <el-form-item label="读写类型" prop="accessMode">
  56. <el-radio-group v-model="formData.property.accessMode">
  57. <el-radio label="rw">读写</el-radio>
  58. <el-radio label="r">只读</el-radio>
  59. </el-radio-group>
  60. </el-form-item>
  61. <el-form-item label="属性描述" prop="property.description">
  62. <el-input
  63. type="textarea"
  64. v-model="formData.property.description"
  65. placeholder="请输入属性描述"
  66. />
  67. </el-form-item>
  68. </el-form>
  69. <template #footer>
  70. <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  71. <el-button @click="dialogVisible = false">取 消</el-button>
  72. </template>
  73. </Dialog>
  74. </template>
  75. <script setup lang="ts">
  76. import { ProductVO } from '@/api/iot/product'
  77. import { ThinkModelFunctionApi, ThinkModelFunctionVO } from '@/api/iot/thinkmodelfunction'
  78. const props = defineProps<{ product: ProductVO }>()
  79. defineOptions({ name: 'ThinkModelFunctionForm' })
  80. const { t } = useI18n()
  81. const message = useMessage()
  82. const dialogVisible = ref(false)
  83. const dialogTitle = ref('')
  84. const formLoading = ref(false)
  85. const formType = ref('')
  86. const formData = ref({
  87. id: undefined,
  88. productId: undefined,
  89. productKey: undefined,
  90. identifier: undefined,
  91. name: undefined,
  92. description: undefined,
  93. type: '1',
  94. property: {
  95. identifier: undefined,
  96. name: undefined,
  97. accessMode: 'rw',
  98. required: true,
  99. dataType: {
  100. type: undefined,
  101. specs: {
  102. min: undefined,
  103. max: undefined,
  104. step: undefined,
  105. unit: undefined
  106. }
  107. },
  108. description: undefined // 添加这一行
  109. }
  110. })
  111. const formRules = reactive({
  112. name: [
  113. { required: true, message: '功能名称不能为空', trigger: 'blur' },
  114. {
  115. pattern: /^[\u4e00-\u9fa5a-zA-Z0-9][\u4e00-\u9fa5a-zA-Z0-9\-_/\.]{0,29}$/,
  116. message:
  117. '支持中文、大小写字母、日文、数字、短划线、下划线、斜杠和小数点,必须以中文、英文或数字开头,不超过 30 个字符',
  118. trigger: 'blur'
  119. }
  120. ],
  121. type: [{ required: true, message: '功能类型不能为空', trigger: 'blur' }],
  122. identifier: [
  123. { required: true, message: '标识符不能为空', trigger: 'blur' },
  124. {
  125. pattern: /^[a-zA-Z0-9_]{1,50}$/,
  126. message: '支持大小写字母、数字和下划线,不超过 50 个字符',
  127. trigger: 'blur'
  128. },
  129. {
  130. validator: (rule, value, callback) => {
  131. const reservedKeywords = ['set', 'get', 'post', 'property', 'event', 'time', 'value']
  132. if (reservedKeywords.includes(value)) {
  133. callback(
  134. new Error(
  135. 'set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义'
  136. )
  137. )
  138. } else {
  139. callback()
  140. }
  141. },
  142. trigger: 'blur'
  143. }
  144. ],
  145. property: {
  146. dataType: {
  147. type: [{ required: true, message: '数据类型不能为空', trigger: 'blur' }]
  148. },
  149. accessMode: [{ required: true, message: '读写类型不能为空', trigger: 'blur' }]
  150. }
  151. })
  152. const formRef = ref()
  153. /** 打开弹窗 */
  154. const open = async (type: string, id?: number) => {
  155. dialogVisible.value = true
  156. dialogTitle.value = t('action.' + type)
  157. formType.value = type
  158. resetForm()
  159. if (id) {
  160. formLoading.value = true
  161. try {
  162. formData.value = await ThinkModelFunctionApi.getThinkModelFunction(id)
  163. } finally {
  164. formLoading.value = false
  165. }
  166. }
  167. }
  168. defineExpose({ open, close: () => (dialogVisible.value = false) })
  169. /** 提交表单 */
  170. const emit = defineEmits(['success'])
  171. const submitForm = async () => {
  172. await formRef.value.validate()
  173. formLoading.value = true
  174. try {
  175. const data = formData.value as unknown as ThinkModelFunctionVO
  176. data.productId = props.product.id
  177. data.productKey = props.product.productKey
  178. if (formType.value === 'create') {
  179. await ThinkModelFunctionApi.createThinkModelFunction(data)
  180. message.success(t('common.createSuccess'))
  181. } else {
  182. await ThinkModelFunctionApi.updateThinkModelFunction(data)
  183. message.success(t('common.updateSuccess'))
  184. }
  185. dialogVisible.value = false // 确保关闭弹框
  186. emit('success')
  187. } finally {
  188. formLoading.value = false
  189. }
  190. }
  191. /** 重置表单 */
  192. const resetForm = () => {
  193. formData.value = {
  194. id: undefined,
  195. productId: undefined,
  196. productKey: undefined,
  197. identifier: undefined,
  198. name: undefined,
  199. description: undefined,
  200. type: '1', // todo @HAOHAO:看看枚举下
  201. property: {
  202. identifier: undefined,
  203. name: undefined,
  204. accessMode: 'rw',
  205. required: true,
  206. dataType: {
  207. type: undefined,
  208. specs: {
  209. min: undefined,
  210. max: undefined,
  211. step: undefined,
  212. unit: undefined
  213. }
  214. },
  215. description: undefined // 确保重置 description 字段
  216. }
  217. }
  218. formRef.value?.resetFields()
  219. }
  220. </script>