Commit fe6adf693b94cfe6f3292f7e0396c7114e335b23

Authored by YunaiV
1 parent a3f57a44

bpm:完成流程表单

yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.service.definition;
3 3 import cn.hutool.core.lang.Assert;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
6   -import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
7 6 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO;
8 7 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO;
9 8 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO;
... ... @@ -107,17 +106,15 @@ public class BpmFormServiceImpl implements BpmFormService {
107 106 return null;
108 107 }
109 108  
110   - private void checkKeyNCName(String key) {
111   - if (!ValidationUtils.isXmlNCName(key)) {
112   - throw exception(MODEL_KEY_VALID);
113   - }
114   - }
115 109 /**
116 110 * 校验 Field,避免 field 重复
117 111 *
118 112 * @param fields field 数组
119 113 */
120 114 private void checkFields(List<String> fields) {
  115 + if (true) { // TODO 芋艿:兼容 Vue3 工作流:因为采用了新的表单设计器,所以暂时不校验
  116 + return;
  117 + }
121 118 Map<String, String> fieldMap = new HashMap<>(); // key 是 vModel,value 是 label
122 119 for (String field : fields) {
123 120 BpmFormFieldRespDTO fieldDTO = JsonUtils.parseObject(field, BpmFormFieldRespDTO.class);
... ...
yudao-ui-admin-vue3/src/api/bpm/form/index.ts
1 1 import request from '@/config/axios'
2   -import { FormVO } from './types'
  2 +
  3 +export type FormVO = {
  4 + id: number
  5 + name: string
  6 + conf: string
  7 + fields: string[]
  8 + status: number
  9 + remark: string
  10 + createTime: string
  11 +}
3 12  
4 13 // 创建工作流的表单定义
5 14 export const createFormApi = async (data: FormVO) => {
... ...
yudao-ui-admin-vue3/src/api/bpm/form/types.ts deleted
1   -export type FormVO = {
2   - id: number
3   - name: string
4   - conf: string
5   - fields: string[]
6   - status: number
7   - remark: string
8   - createTime: string
9   -}
yudao-ui-admin-vue3/src/router/modules/remaining.ts
... ... @@ -194,7 +194,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
194 194 noCache: true,
195 195 hidden: true,
196 196 canTo: true,
197   - title: '流程表单',
  197 + title: '设计流程表单',
198 198 activeMenu: 'bpm/manager/form/formEditor'
199 199 }
200 200 },
... ...
yudao-ui-admin-vue3/src/utils/formCreate.ts 0 → 100644
  1 +/**
  2 + * 针对 https://github.com/xaboy/form-create-designer 封装的工具类
  3 + */
  4 +
  5 +// 编码表单 Conf
  6 +export const encodeConf = (designerRef: object) => {
  7 + // @ts-ignore
  8 + return JSON.stringify(designerRef.value.getOption())
  9 +}
  10 +
  11 +// 编码表单 Fields
  12 +export const encodeFields = (designerRef: object) => {
  13 + // @ts-ignore
  14 + const rule = designerRef.value.getRule()
  15 + const fields: string[] = []
  16 + rule.forEach((item) => {
  17 + fields.push(JSON.stringify(item))
  18 + })
  19 + return fields
  20 +}
  21 +
  22 +// 解码表单 Fields
  23 +export const decodeFields = (fields: string[]) => {
  24 + const rule: object[] = []
  25 + fields.forEach((item) => {
  26 + rule.push(JSON.parse(item))
  27 + })
  28 + return rule
  29 +}
  30 +
  31 +// 设置表单的 Conf 和 Fields
  32 +export const setConfAndFields = (designerRef: object, conf: string, fields: string) => {
  33 + // @ts-ignore
  34 + designerRef.value.setOption(JSON.parse(conf))
  35 + // @ts-ignore
  36 + designerRef.value.setRule(decodeFields(fields))
  37 +}
  38 +
  39 +// 设置表单的 Conf 和 Fields
  40 +export const setConfAndFields2 = (detailPreview: object, conf: string, fields: string) => {
  41 + // @ts-ignore
  42 + detailPreview.value.option = JSON.parse(conf)
  43 + // @ts-ignore
  44 + detailPreview.value.rule = decodeFields(fields)
  45 +}
... ...
yudao-ui-admin-vue3/src/views/bpm/form/formEditor.vue
... ... @@ -8,7 +8,7 @@
8 8 </fc-designer>
9 9 <!-- 表单保存的弹窗 -->
10 10 <XModal v-model="dialogVisible" title="保存表单">
11   - <el-form :model="formValues" :rules="formRules" label-width="80px">
  11 + <el-form ref="formRef" :model="formValues" :rules="formRules" label-width="80px">
12 12 <el-form-item label="表单名" prop="name">
13 13 <el-input v-model="formValues.name" placeholder="请输入表单名" />
14 14 </el-form-item>
... ... @@ -43,22 +43,26 @@
43 43 </ContentWrap>
44 44 </template>
45 45 <script setup lang="ts" name="BpmFormEditor">
  46 +import { reactive } from 'vue'
  47 +import { FormInstance } from 'element-plus'
46 48 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
47 49 import { CommonStatusEnum } from '@/utils/constants'
48   -import { reactive } from 'vue'
49   -
  50 +import * as FormApi from '@/api/bpm/form'
  51 +import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate'
50 52 const { t } = useI18n() // 国际化
51   -// const message = useMessage() // 消息
  53 +const message = useMessage() // 消息
  54 +const { query } = useRoute() // 路由
52 55  
53 56 const designer = ref() // 表单设计器
54 57  
55   -const dialogVisible = ref(false)
56   -const dialogLoading = ref(false)
  58 +const dialogVisible = ref(false) // 弹窗是否展示
  59 +const dialogLoading = ref(false) // 弹窗的加载中
  60 +const formRef = ref<FormInstance>()
57 61 const formRules = reactive({
58 62 name: [{ required: true, message: '表单名不能为空', trigger: 'blur' }],
59 63 status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }]
60 64 })
61   -const formValues = reactive({
  65 +const formValues = ref({
62 66 name: '',
63 67 status: CommonStatusEnum.ENABLE,
64 68 remark: ''
... ... @@ -71,9 +75,42 @@ const handleSave = () =&gt; {
71 75  
72 76 // 提交保存表单
73 77 const submitForm = async () => {
74   - console.log('保存')
  78 + // 参数校验
  79 + const elForm = unref(formRef)
  80 + if (!elForm) return
  81 + const valid = await elForm.validate()
  82 + if (!valid) return
  83 +
  84 + // 提交请求
  85 + dialogLoading.value = true
  86 + try {
  87 + const data = formValues.value as FormApi.FormVO
  88 + data.conf = encodeConf(designer) // 表单配置
  89 + data.fields = encodeFields(designer) // 表单字段
  90 + if (!data.id) {
  91 + await FormApi.createFormApi(data)
  92 + message.success(t('common.createSuccess'))
  93 + } else {
  94 + await FormApi.updateFormApi(data)
  95 + message.success(t('common.updateSuccess'))
  96 + }
  97 + dialogVisible.value = false
  98 + } finally {
  99 + dialogLoading.value = false
  100 + }
75 101 }
76 102  
77   -// formValue.value = designer.value.getOption()
78   -// formValue.value = designer.value.getRule()
  103 +// ========== 初始化 ==========
  104 +onMounted(() => {
  105 + // 场景一:新增表单
  106 + const id = query.id as unknown as number
  107 + if (!id) {
  108 + return
  109 + }
  110 + // 场景二:修改表单
  111 + FormApi.getFormApi(id).then((data) => {
  112 + formValues.value = data
  113 + setConfAndFields(designer, data.conf, data.fields)
  114 + })
  115 +})
79 116 </script>
... ...
yudao-ui-admin-vue3/src/views/bpm/form/index.vue
... ... @@ -37,12 +37,9 @@
37 37 />
38 38 </template>
39 39 </XTable>
40   - <!-- TODO 芋艿:待完善 -->
41   - <XModal v-model="detailOpen" width="400" title="表单详情">
42   - <!-- <div class="test-form">
43   - <parser :key="new Date().getTime()" :form-conf="detailForm" />
44   - </div> -->
45   - 表单详情
  40 + <!-- 表单详情的弹窗 -->
  41 + <XModal v-model="detailOpen" width="800" title="表单详情">
  42 + <ViewForm :rule="detailPreview.rule" :option="detailPreview.option" v-if="detailOpen" />
46 43 </XModal>
47 44 </div>
48 45 </ContentWrap>
... ... @@ -50,21 +47,18 @@
50 47  
51 48 <script setup lang="ts" name="BpmForm">
52 49 // 全局相关的 import
53   -// import { ref } from 'vue'
54   -import { useI18n } from '@/hooks/web/useI18n'
55   -import { useMessage } from '@/hooks/web/useMessage'
56   -import { useXTable } from '@/hooks/web/useXTable'
57   -// import { FormExpose } from '@/components/Form'
58 50 // 业务相关的 import
59 51 import * as FormApi from '@/api/bpm/form'
60 52 import { allSchemas } from './form.data'
61   -import { useRouter } from 'vue-router'
62   -// import { decodeFields } from '@/utils/formGenerator' // TODO 芋艿:可能要清理下
63 53  
64 54 const { t } = useI18n() // 国际化
65   -const message = useMessage() // 消息弹窗
66 55 const router = useRouter() // 路由
67 56  
  57 +// 表单详情相关的变量和 import
  58 +import viewForm from '@form-create/element-ui'
  59 +const ViewForm = viewForm.$form()
  60 +import { setConfAndFields2 } from '@/utils/formCreate'
  61 +
68 62 // 列表相关的变量
69 63 const [registerTable, { deleteData }] = useXTable({
70 64 allSchemas: allSchemas,
... ... @@ -72,23 +66,6 @@ const [registerTable, { deleteData }] = useXTable({
72 66 deleteApi: FormApi.deleteFormApi
73 67 })
74 68  
75   -// 弹窗相关的变量
76   -// const modelVisible = ref(false) // 是否显示弹出层
77   -// const modelTitle = ref('edit') // 弹出层标题
78   -// const modelLoading = ref(false) // 弹出层loading
79   -// const actionType = ref('') // 操作按钮的类型
80   -// const actionLoading = ref(false) // 按钮 Loading
81   -// const formRef = ref<FormExpose>() // 表单 Ref
82   -// const detailData = ref() // 详情 Ref
83   -
84   -// 设置标题
85   -// const setDialogTile = (type: string) => {
86   -// modelLoading.value = true
87   -// modelTitle.value = t('action.' + type)
88   -// actionType.value = type
89   -// modelVisible.value = true
90   -// }
91   -
92 69 // 新增操作
93 70 const handleCreate = () => {
94 71 router.push({
... ... @@ -98,38 +75,25 @@ const handleCreate = () =&gt; {
98 75  
99 76 // 修改操作
100 77 const handleUpdate = async (rowId: number) => {
101   - console.log(rowId, '修改')
102   - if (true) {
103   - message.success('动态表单开发中,预计 2 月底完成')
104   - return
105   - }
106 78 await router.push({
107   - path: '/bpm/manager/form/edit',
  79 + name: 'bpmFormEditor',
108 80 query: {
109   - formId: rowId
  81 + id: rowId
110 82 }
111 83 })
112 84 }
113 85  
114   -// 详情操作 // TODO 芋艿:详情的实现
115   -// const detailForm = ref({
116   -// fields: []
117   -// })
118   -// 表单详情弹出窗显示隐藏
119   -// const detailOpen = ref(false)
120   -
  86 +// 详情操作
  87 +const detailOpen = ref(false)
  88 +const detailPreview = ref({
  89 + rule: [],
  90 + option: {}
  91 +})
121 92 const handleDetail = async (rowId: number) => {
122   - console.log(rowId, '详情')
123   - message.success('动态表单开发中,预计 2 月底完成')
124   - // FormApi.getFormApi(row.id).then((response) => {
125   - // // 设置值
126   - // const data = response.data
127   - // detailForm.value = {
128   - // ...JSON.parse(data.conf),
129   - // fields: decodeFields([], data.fields)
130   - // }
131   - // // 弹窗打开
132   - // detailOpen.value = true
133   - // })
  93 + // 设置表单
  94 + const data = await FormApi.getFormApi(rowId)
  95 + setConfAndFields2(detailPreview, data.conf, data.fields)
  96 + // 弹窗打开
  97 + detailOpen.value = true
134 98 }
135 99 </script>
... ...