ElementForm.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. <template>
  2. <div class="panel-tab__content">
  3. <el-form label-width="80px">
  4. <el-form-item label="流程表单">
  5. <!-- <el-input v-model="formKey" clearable @change="updateElementFormKey" />-->
  6. <el-select v-model="formKey" clearable @change="updateElementFormKey">
  7. <el-option v-for="form in formList" :key="form.id" :label="form.name" :value="form.id" />
  8. </el-select>
  9. </el-form-item>
  10. <!-- <el-form-item label="业务标识">-->
  11. <!-- <el-select v-model="businessKey" @change="updateElementBusinessKey">-->
  12. <!-- <el-option v-for="i in fieldList" :key="i.id" :value="i.id" :label="i.label" />-->
  13. <!-- <el-option label="无" value="" />-->
  14. <!-- </el-select>-->
  15. <!-- </el-form-item>-->
  16. </el-form>
  17. <!--字段列表-->
  18. <!-- <div class="element-property list-property">-->
  19. <!-- <el-divider><Icon icon="ep:coin" /> 表单字段</el-divider>-->
  20. <!-- <el-table :data="fieldList" max-height="240" fit border>-->
  21. <!-- <el-table-column label="序号" type="index" width="50px" />-->
  22. <!-- <el-table-column label="字段名称" prop="label" min-width="80px" show-overflow-tooltip />-->
  23. <!-- <el-table-column-->
  24. <!-- label="字段类型"-->
  25. <!-- prop="type"-->
  26. <!-- min-width="80px"-->
  27. <!-- :formatter="(row) => fieldType[row.type] || row.type"-->
  28. <!-- show-overflow-tooltip-->
  29. <!-- />-->
  30. <!-- <el-table-column-->
  31. <!-- label="默认值"-->
  32. <!-- prop="defaultValue"-->
  33. <!-- min-width="80px"-->
  34. <!-- show-overflow-tooltip-->
  35. <!-- />-->
  36. <!-- <el-table-column label="操作" width="90px">-->
  37. <!-- <template #default="scope">-->
  38. <!-- <el-button type="primary" link @click="openFieldForm(scope, scope.$index)"-->
  39. <!-- >编辑</el-button-->
  40. <!-- >-->
  41. <!-- <el-divider direction="vertical" />-->
  42. <!-- <el-button-->
  43. <!-- type="primary"-->
  44. <!-- link-->
  45. <!-- style="color: #ff4d4f"-->
  46. <!-- @click="removeField(scope, scope.$index)"-->
  47. <!-- >移除</el-button-->
  48. <!-- >-->
  49. <!-- </template>-->
  50. <!-- </el-table-column>-->
  51. <!-- </el-table>-->
  52. <!-- </div>-->
  53. <!-- <div class="element-drawer__button">-->
  54. <!-- <XButton type="primary" proIcon="ep:plus" title="添加字段" @click="openFieldForm(null, -1)" />-->
  55. <!-- </div>-->
  56. <!--字段配置侧边栏-->
  57. <!-- <el-drawer-->
  58. <!-- v-model="fieldModelVisible"-->
  59. <!-- title="字段配置"-->
  60. <!-- :size="`${width}px`"-->
  61. <!-- append-to-body-->
  62. <!-- destroy-on-close-->
  63. <!-- >-->
  64. <!-- <el-form :model="formFieldForm" label-width="90px">-->
  65. <!-- <el-form-item label="字段ID">-->
  66. <!-- <el-input v-model="formFieldForm.id" clearable />-->
  67. <!-- </el-form-item>-->
  68. <!-- <el-form-item label="类型">-->
  69. <!-- <el-select-->
  70. <!-- v-model="formFieldForm.typeType"-->
  71. <!-- placeholder="请选择字段类型"-->
  72. <!-- clearable-->
  73. <!-- @change="changeFieldTypeType"-->
  74. <!-- >-->
  75. <!-- <el-option v-for="(value, key) of fieldType" :label="value" :value="key" :key="key" />-->
  76. <!-- </el-select>-->
  77. <!-- </el-form-item>-->
  78. <!-- <el-form-item label="类型名称" v-if="formFieldForm.typeType === 'custom'">-->
  79. <!-- <el-input v-model="formFieldForm.type" clearable />-->
  80. <!-- </el-form-item>-->
  81. <!-- <el-form-item label="名称">-->
  82. <!-- <el-input v-model="formFieldForm.label" clearable />-->
  83. <!-- </el-form-item>-->
  84. <!-- <el-form-item label="时间格式" v-if="formFieldForm.typeType === 'date'">-->
  85. <!-- <el-input v-model="formFieldForm.datePattern" clearable />-->
  86. <!-- </el-form-item>-->
  87. <!-- <el-form-item label="默认值">-->
  88. <!-- <el-input v-model="formFieldForm.defaultValue" clearable />-->
  89. <!-- </el-form-item>-->
  90. <!-- </el-form>-->
  91. <!-- &lt;!&ndash; 枚举值设置 &ndash;&gt;-->
  92. <!-- <template v-if="formFieldForm.type === 'enum'">-->
  93. <!-- <el-divider key="enum-divider" />-->
  94. <!-- <p class="listener-filed__title" key="enum-title">-->
  95. <!-- <span><Icon icon="ep:menu" />枚举值列表:</span>-->
  96. <!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'enum')"-->
  97. <!-- >添加枚举值</el-button-->
  98. <!-- >-->
  99. <!-- </p>-->
  100. <!-- <el-table :data="fieldEnumList" key="enum-table" max-height="240" fit border>-->
  101. <!-- <el-table-column label="序号" width="50px" type="index" />-->
  102. <!-- <el-table-column label="枚举值编号" prop="id" min-width="100px" show-overflow-tooltip />-->
  103. <!-- <el-table-column label="枚举值名称" prop="name" min-width="100px" show-overflow-tooltip />-->
  104. <!-- <el-table-column label="操作" width="90px">-->
  105. <!-- <template #default="scope">-->
  106. <!-- <el-button-->
  107. <!-- type="primary"-->
  108. <!-- link-->
  109. <!-- @click="openFieldOptionForm(scope, scope.$index, 'enum')"-->
  110. <!-- >编辑</el-button-->
  111. <!-- >-->
  112. <!-- <el-divider direction="vertical" />-->
  113. <!-- <el-button-->
  114. <!-- type="primary"-->
  115. <!-- link-->
  116. <!-- style="color: #ff4d4f"-->
  117. <!-- @click="removeFieldOptionItem(scope, scope.$index, 'enum')"-->
  118. <!-- >移除</el-button-->
  119. <!-- >-->
  120. <!-- </template>-->
  121. <!-- </el-table-column>-->
  122. <!-- </el-table>-->
  123. <!-- </template>-->
  124. <!-- &lt;!&ndash; 校验规则 &ndash;&gt;-->
  125. <!-- <el-divider key="validation-divider" />-->
  126. <!-- <p class="listener-filed__title" key="validation-title">-->
  127. <!-- <span><Icon icon="ep:menu" />约束条件列表:</span>-->
  128. <!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'constraint')"-->
  129. <!-- >添加约束</el-button-->
  130. <!-- >-->
  131. <!-- </p>-->
  132. <!-- <el-table :data="fieldConstraintsList" key="validation-table" max-height="240" fit border>-->
  133. <!-- <el-table-column label="序号" width="50px" type="index" />-->
  134. <!-- <el-table-column label="约束名称" prop="name" min-width="100px" show-overflow-tooltip />-->
  135. <!-- <el-table-column label="约束配置" prop="config" min-width="100px" show-overflow-tooltip />-->
  136. <!-- <el-table-column label="操作" width="90px">-->
  137. <!-- <template #default="scope">-->
  138. <!-- <el-button-->
  139. <!-- type="primary"-->
  140. <!-- link-->
  141. <!-- @click="openFieldOptionForm(scope, scope.$index, 'constraint')"-->
  142. <!-- >编辑</el-button-->
  143. <!-- >-->
  144. <!-- <el-divider direction="vertical" />-->
  145. <!-- <el-button-->
  146. <!-- type="primary"-->
  147. <!-- link-->
  148. <!-- style="color: #ff4d4f"-->
  149. <!-- @click="removeFieldOptionItem(scope, scope.$index, 'constraint')"-->
  150. <!-- >移除</el-button-->
  151. <!-- >-->
  152. <!-- </template>-->
  153. <!-- </el-table-column>-->
  154. <!-- </el-table>-->
  155. <!-- &lt;!&ndash; 表单属性 &ndash;&gt;-->
  156. <!-- <el-divider key="property-divider" />-->
  157. <!-- <p class="listener-filed__title" key="property-title">-->
  158. <!-- <span><Icon icon="ep:menu" />字段属性列表:</span>-->
  159. <!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'property')"-->
  160. <!-- >添加属性</el-button-->
  161. <!-- >-->
  162. <!-- </p>-->
  163. <!-- <el-table :data="fieldPropertiesList" key="property-table" max-height="240" fit border>-->
  164. <!-- <el-table-column label="序号" width="50px" type="index" />-->
  165. <!-- <el-table-column label="属性编号" prop="id" min-width="100px" show-overflow-tooltip />-->
  166. <!-- <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip />-->
  167. <!-- <el-table-column label="操作" width="90px">-->
  168. <!-- <template #default="scope">-->
  169. <!-- <el-button-->
  170. <!-- type="primary"-->
  171. <!-- link-->
  172. <!-- @click="openFieldOptionForm(scope, scope.$index, 'property')"-->
  173. <!-- >编辑</el-button-->
  174. <!-- >-->
  175. <!-- <el-divider direction="vertical" />-->
  176. <!-- <el-button-->
  177. <!-- type="primary"-->
  178. <!-- link-->
  179. <!-- style="color: #ff4d4f"-->
  180. <!-- @click="removeFieldOptionItem(scope, scope.$index, 'property')"-->
  181. <!-- >移除</el-button-->
  182. <!-- >-->
  183. <!-- </template>-->
  184. <!-- </el-table-column>-->
  185. <!-- </el-table>-->
  186. <!-- &lt;!&ndash; 底部按钮 &ndash;&gt;-->
  187. <!-- <div class="element-drawer__button">-->
  188. <!-- <el-button>取 消</el-button>-->
  189. <!-- <el-button type="primary" @click="saveField">保 存</el-button>-->
  190. <!-- </div>-->
  191. <!-- </el-drawer>-->
  192. <!-- <el-dialog-->
  193. <!-- v-model="fieldOptionModelVisible"-->
  194. <!-- :title="optionModelTitle"-->
  195. <!-- width="600px"-->
  196. <!-- append-to-body-->
  197. <!-- destroy-on-close-->
  198. <!-- >-->
  199. <!-- <el-form :model="fieldOptionForm" label-width="96px">-->
  200. <!-- <el-form-item label="编号/ID" v-if="fieldOptionType !== 'constraint'" key="option-id">-->
  201. <!-- <el-input v-model="fieldOptionForm.id" clearable />-->
  202. <!-- </el-form-item>-->
  203. <!-- <el-form-item label="名称" v-if="fieldOptionType !== 'property'" key="option-name">-->
  204. <!-- <el-input v-model="fieldOptionForm.name" clearable />-->
  205. <!-- </el-form-item>-->
  206. <!-- <el-form-item label="配置" v-if="fieldOptionType === 'constraint'" key="option-config">-->
  207. <!-- <el-input v-model="fieldOptionForm.config" clearable />-->
  208. <!-- </el-form-item>-->
  209. <!-- <el-form-item label="值" v-if="fieldOptionType === 'property'" key="option-value">-->
  210. <!-- <el-input v-model="fieldOptionForm.value" clearable />-->
  211. <!-- </el-form-item>-->
  212. <!-- </el-form>-->
  213. <!-- <template #footer>-->
  214. <!-- <el-button @click="fieldOptionModelVisible = false">取 消</el-button>-->
  215. <!-- <el-button type="primary" @click="saveFieldOption">确 定</el-button>-->
  216. <!-- </template>-->
  217. <!-- </el-dialog>-->
  218. </div>
  219. </template>
  220. <script lang="ts" setup>
  221. import * as FormApi from '@/api/bpm/form'
  222. defineOptions({ name: 'ElementForm' })
  223. const props = defineProps({
  224. id: String,
  225. type: String
  226. })
  227. const prefix = inject('prefix')
  228. const width = inject('width')
  229. const formKey = ref('')
  230. const businessKey = ref('')
  231. const optionModelTitle = ref('')
  232. const fieldList = ref<any[]>([])
  233. const formFieldForm = ref<any>({})
  234. const fieldType = ref({
  235. long: '长整型',
  236. string: '字符串',
  237. boolean: '布尔类',
  238. date: '日期类',
  239. enum: '枚举类',
  240. custom: '自定义类型'
  241. })
  242. const formFieldIndex = ref(-1) // 编辑中的字段, -1 为新增
  243. const formFieldOptionIndex = ref(-1) // 编辑中的字段配置项, -1 为新增
  244. const fieldModelVisible = ref(false)
  245. const fieldOptionModelVisible = ref(false)
  246. const fieldOptionForm = ref<any>({}) // 当前激活的字段配置项数据
  247. const fieldOptionType = ref('') // 当前激活的字段配置项弹窗 类型
  248. const fieldEnumList = ref<any[]>([]) // 枚举值列表
  249. const fieldConstraintsList = ref<any[]>([]) // 约束条件列表
  250. const fieldPropertiesList = ref<any[]>([]) // 绑定属性列表
  251. const bpmnELement = ref()
  252. const elExtensionElements = ref()
  253. const formData = ref()
  254. const otherExtensions = ref()
  255. const bpmnInstances = () => (window as any)?.bpmnInstances
  256. const resetFormList = () => {
  257. bpmnELement.value = bpmnInstances().bpmnElement
  258. formKey.value = bpmnELement.value.businessObject.formKey
  259. if (formKey.value?.length > 0) {
  260. formKey.value = parseInt(formKey.value)
  261. }
  262. // 获取元素扩展属性 或者 创建扩展属性
  263. elExtensionElements.value =
  264. bpmnELement.value.businessObject.get('extensionElements') ||
  265. bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
  266. // 获取元素表单配置 或者 创建新的表单配置
  267. formData.value =
  268. elExtensionElements.value.values.filter((ex) => ex.$type === `${prefix}:FormData`)?.[0] ||
  269. bpmnInstances().moddle.create(`${prefix}:FormData`, { fields: [] })
  270. // 业务标识 businessKey, 绑定在 formData 中
  271. businessKey.value = formData.value.businessKey
  272. // 保留剩余扩展元素,便于后面更新该元素对应属性
  273. otherExtensions.value = elExtensionElements.value.values.filter(
  274. (ex) => ex.$type !== `${prefix}:FormData`
  275. )
  276. // 复制原始值,填充表格
  277. fieldList.value = JSON.parse(JSON.stringify(formData.value.fields || []))
  278. // 更新元素扩展属性,避免后续报错
  279. updateElementExtensions()
  280. }
  281. const updateElementFormKey = () => {
  282. bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
  283. formKey: formKey.value
  284. })
  285. }
  286. const updateElementBusinessKey = () => {
  287. bpmnInstances().modeling.updateModdleProperties(toRaw(bpmnELement.value), formData.value, {
  288. businessKey: businessKey.value
  289. })
  290. }
  291. // 根据类型调整字段type
  292. const changeFieldTypeType = (type) => {
  293. // this.$set(this.formFieldForm, "type", type === "custom" ? "" : type);
  294. formFieldForm.value['type'] = type === 'custom' ? '' : type
  295. }
  296. // 打开字段详情侧边栏
  297. const openFieldForm = (field, index) => {
  298. formFieldIndex.value = index
  299. if (index !== -1) {
  300. const FieldObject = formData.value.fields[index]
  301. formFieldForm.value = JSON.parse(JSON.stringify(field))
  302. // 设置自定义类型
  303. // this.$set(this.formFieldForm, "typeType", !this.fieldType[field.type] ? "custom" : field.type);
  304. formFieldForm.value['typeType'] = !fieldType.value[field.type] ? 'custom' : field.type
  305. // 初始化枚举值列表
  306. field.type === 'enum' &&
  307. (fieldEnumList.value = JSON.parse(JSON.stringify(FieldObject?.values || [])))
  308. // 初始化约束条件列表
  309. fieldConstraintsList.value = JSON.parse(
  310. JSON.stringify(FieldObject?.validation?.constraints || [])
  311. )
  312. // 初始化自定义属性列表
  313. fieldPropertiesList.value = JSON.parse(JSON.stringify(FieldObject?.properties?.values || []))
  314. } else {
  315. formFieldForm.value = {}
  316. // 初始化枚举值列表
  317. fieldEnumList.value = []
  318. // 初始化约束条件列表
  319. fieldConstraintsList.value = []
  320. // 初始化自定义属性列表
  321. fieldPropertiesList.value = []
  322. }
  323. fieldModelVisible.value = true
  324. }
  325. // 打开字段 某个 配置项 弹窗
  326. const openFieldOptionForm = (option, index, type) => {
  327. fieldOptionModelVisible.value = true
  328. fieldOptionType.value = type
  329. formFieldOptionIndex.value = index
  330. if (type === 'property') {
  331. fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
  332. return (optionModelTitle.value = '属性配置')
  333. }
  334. if (type === 'enum') {
  335. fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
  336. return (optionModelTitle.value = '枚举值配置')
  337. }
  338. fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
  339. return (optionModelTitle.value = '约束条件配置')
  340. }
  341. // 保存字段 某个 配置项
  342. const saveFieldOption = () => {
  343. if (formFieldOptionIndex.value === -1) {
  344. if (fieldOptionType.value === 'property') {
  345. fieldPropertiesList.value.push(fieldOptionForm.value)
  346. }
  347. if (fieldOptionType.value === 'constraint') {
  348. fieldConstraintsList.value.push(fieldOptionForm.value)
  349. }
  350. if (fieldOptionType.value === 'enum') {
  351. fieldEnumList.value.push(fieldOptionForm.value)
  352. }
  353. } else {
  354. fieldOptionType.value === 'property' &&
  355. fieldPropertiesList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
  356. fieldOptionType.value === 'constraint' &&
  357. fieldConstraintsList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
  358. fieldOptionType.value === 'enum' &&
  359. fieldEnumList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
  360. }
  361. fieldOptionModelVisible.value = false
  362. fieldOptionForm.value = {}
  363. }
  364. // 保存字段配置
  365. const saveField = () => {
  366. const { id, type, label, defaultValue, datePattern } = formFieldForm.value
  367. const Field = bpmnInstances().moddle.create(`${prefix}:FormField`, { id, type, label })
  368. defaultValue && (Field.defaultValue = defaultValue)
  369. datePattern && (Field.datePattern = datePattern)
  370. // 构建属性
  371. if (fieldPropertiesList.value && fieldPropertiesList.value.length) {
  372. const fieldPropertyList = fieldPropertiesList.value.map((fp) => {
  373. return bpmnInstances().moddle.create(`${prefix}:Property`, {
  374. id: fp.id,
  375. value: fp.value
  376. })
  377. })
  378. Field.properties = bpmnInstances().moddle.create(`${prefix}:Properties`, {
  379. values: fieldPropertyList
  380. })
  381. }
  382. // 构建校验规则
  383. if (fieldConstraintsList.value && fieldConstraintsList.value.length) {
  384. const fieldConstraintList = fieldConstraintsList.value.map((fc) => {
  385. return bpmnInstances().moddle.create(`${prefix}:Constraint`, {
  386. name: fc.name,
  387. config: fc.config
  388. })
  389. })
  390. Field.validation = bpmnInstances().moddle.create(`${prefix}:Validation`, {
  391. constraints: fieldConstraintList
  392. })
  393. }
  394. // 构建枚举值
  395. if (fieldEnumList.value && fieldEnumList.value.length) {
  396. Field.values = fieldEnumList.value.map((fe) => {
  397. return bpmnInstances().moddle.create(`${prefix}:Value`, { name: fe.name, id: fe.id })
  398. })
  399. }
  400. // 更新数组 与 表单配置实例
  401. if (formFieldIndex.value === -1) {
  402. fieldList.value.push(formFieldForm.value)
  403. formData.value.fields.push(Field)
  404. } else {
  405. fieldList.value.splice(formFieldIndex.value, 1, formFieldForm.value)
  406. formData.value.fields.splice(formFieldIndex.value, 1, Field)
  407. }
  408. updateElementExtensions()
  409. fieldModelVisible.value = false
  410. }
  411. // 移除某个 字段的 配置项
  412. const removeFieldOptionItem = (option, index, type) => {
  413. console.log(option, 'option')
  414. if (type === 'property') {
  415. fieldPropertiesList.value.splice(index, 1)
  416. return
  417. }
  418. if (type === 'enum') {
  419. fieldEnumList.value.splice(index, 1)
  420. return
  421. }
  422. fieldConstraintsList.value.splice(index, 1)
  423. }
  424. // 移除 字段
  425. const removeField = (field, index) => {
  426. console.log(field, 'field')
  427. fieldList.value.splice(index, 1)
  428. formData.value.fields.splice(index, 1)
  429. updateElementExtensions()
  430. }
  431. const updateElementExtensions = () => {
  432. // 更新回扩展元素
  433. const newElExtensionElements = bpmnInstances().moddle.create(`bpmn:ExtensionElements`, {
  434. values: otherExtensions.value.concat(formData.value)
  435. })
  436. // 更新到元素上
  437. bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
  438. extensionElements: newElExtensionElements
  439. })
  440. }
  441. const formList = ref([]) // 流程表单的下拉框的数据
  442. onMounted(async () => {
  443. formList.value = await FormApi.getSimpleFormList()
  444. })
  445. watch(
  446. () => props.id,
  447. (val) => {
  448. val &&
  449. val.length &&
  450. nextTick(() => {
  451. resetFormList()
  452. })
  453. },
  454. { immediate: true }
  455. )
  456. </script>