feat: 流程模型新增: 表单设计
							parent
							
								
									43b7ac52b1
								
							
						
					
					
						commit
						da3a580711
					
				|  | @ -1,6 +1,7 @@ | |||
| <script setup lang="ts"> | ||||
| import type { BpmCategoryApi } from '#/api/bpm/category'; | ||||
| import type { BpmProcessDefinitionApi } from '#/api/bpm/definition'; | ||||
| import type { BpmFormApi } from '#/api/bpm/form'; | ||||
| import type { SystemDeptApi } from '#/api/system/dept'; | ||||
| import type { SystemUserApi } from '#/api/system/user'; | ||||
| 
 | ||||
|  | @ -16,6 +17,7 @@ import { Button, Card, message } from 'ant-design-vue'; | |||
| 
 | ||||
| import { getCategorySimpleList } from '#/api/bpm/category'; | ||||
| import { getProcessDefinition } from '#/api/bpm/definition'; | ||||
| import { getFormSimpleList } from '#/api/bpm/form'; | ||||
| import { | ||||
|   createModel, | ||||
|   deployModel, | ||||
|  | @ -26,6 +28,7 @@ import { getSimpleDeptList } from '#/api/system/dept'; | |||
| import { getSimpleUserList } from '#/api/system/user'; | ||||
| 
 | ||||
| import BasicInfo from './modules/basic-info.vue'; | ||||
| import FormDesign from './modules/form-design.vue'; | ||||
| 
 | ||||
| defineOptions({ name: 'BpmModelCreate' }); | ||||
| 
 | ||||
|  | @ -62,7 +65,9 @@ const route = useRoute(); | |||
| const userStore = useUserStore(); | ||||
| 
 | ||||
| // 基础信息组件引用 | ||||
| const basicInfoRef = ref(); | ||||
| const basicInfoRef = ref<InstanceType<typeof BasicInfo>>(); | ||||
| // 表单设计组件引用 | ||||
| const formDesignRef = ref<InstanceType<typeof FormDesign>>(); | ||||
| 
 | ||||
| /** 步骤校验函数 */ | ||||
| const validateBasic = async () => { | ||||
|  | @ -71,7 +76,7 @@ const validateBasic = async () => { | |||
| 
 | ||||
| /** 表单设计校验 */ | ||||
| const validateForm = async () => { | ||||
|   // TODO | ||||
|   await formDesignRef.value?.validate(); | ||||
| }; | ||||
| 
 | ||||
| /** 流程设计校验 */ | ||||
|  | @ -132,7 +137,7 @@ provide('processData', processData); | |||
| provide('modelData', formData); | ||||
| 
 | ||||
| // 数据列表 | ||||
| // const formList = ref([]) | ||||
| const formList = ref<BpmFormApi.FormVO[]>([]); | ||||
| const categoryList = ref<BpmCategoryApi.CategoryVO[]>([]); | ||||
| const userList = ref<SystemUserApi.User[]>([]); | ||||
| const deptList = ref<SystemDeptApi.Dept[]>([]); | ||||
|  | @ -187,8 +192,8 @@ const initData = async () => { | |||
|     formData.value.managerUserIds.push(userStore.userInfo?.userId); | ||||
|   } | ||||
| 
 | ||||
|   // TODO 获取表单列表 | ||||
|   // formList.value = await getFormSimpleList() | ||||
|   // 获取表单列表 | ||||
|   formList.value = await getFormSimpleList(); | ||||
|   categoryList.value = await getCategorySimpleList(); | ||||
|   // 获取用户列表 | ||||
|   userList.value = await getSimpleUserList(); | ||||
|  | @ -393,9 +398,8 @@ onMounted(async () => { | |||
| /** 添加组件卸载前的清理 */ | ||||
| onBeforeUnmount(() => { | ||||
|   // 清理所有的引用 | ||||
|   basicInfoRef.value = null; | ||||
|   // TODO 后续加 | ||||
|   // formDesignRef.value = null; | ||||
|   basicInfoRef.value = undefined; | ||||
|   formDesignRef.value = undefined; | ||||
|   // processDesignRef.value = null; | ||||
| }); | ||||
| </script> | ||||
|  | @ -471,7 +475,7 @@ onBeforeUnmount(() => { | |||
|       <Card :body-style="{ padding: '10px' }" class="mb-4"> | ||||
|         <div class="mt-[50px]"> | ||||
|           <!-- 第一步:基本信息 --> | ||||
|           <div v-if="currentStep === 0" class="mx-auto w-[560px]"> | ||||
|           <div v-if="currentStep === 0" class="mx-auto w-4/6"> | ||||
|             <BasicInfo | ||||
|               v-model="formData" | ||||
|               :category-list="categoryList" | ||||
|  | @ -480,13 +484,19 @@ onBeforeUnmount(() => { | |||
|               ref="basicInfoRef" | ||||
|             /> | ||||
|           </div> | ||||
| 
 | ||||
|           <!-- 第二步:表单设计 TODO --> | ||||
|           <!-- 第二步:表单设计  --> | ||||
|           <div v-show="currentStep === 1" class="mx-auto w-4/6"> | ||||
|             <FormDesign | ||||
|               v-model="formData" | ||||
|               :form-list="formList" | ||||
|               ref="formDesignRef" | ||||
|             /> | ||||
|           </div> | ||||
| 
 | ||||
|           <!-- 第三步:流程设计 TODO --> | ||||
| 
 | ||||
|           <!-- 第四步:更多设置 TODO --> | ||||
|           <div v-show="currentStep === 3" class="mx-auto w-[700px]"></div> | ||||
|           <div v-show="currentStep === 3" class="mx-auto w-4/6"></div> | ||||
|         </div> | ||||
|       </Card> | ||||
|     </div> | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ import type { SystemUserApi } from '#/api/system/user'; | |||
| 
 | ||||
| import { ref, watch } from 'vue'; | ||||
| 
 | ||||
| import { IconifyIcon, Plus, ShieldQuestion, X } from '@vben/icons'; | ||||
| import { CircleHelp, IconifyIcon, Plus, X } from '@vben/icons'; | ||||
| 
 | ||||
| import { | ||||
|   Avatar, | ||||
|  | @ -65,6 +65,7 @@ const rules: Record<string, Rule[]> = { | |||
|   category: [{ required: true, message: '流程分类不能为空', trigger: 'blur' }], | ||||
|   type: [{ required: true, message: '流程类型不能为空', trigger: 'blur' }], | ||||
|   visible: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }], | ||||
|   // TODO 这个的校验好像没有起作用 | ||||
|   managerUserIds: [ | ||||
|     { required: true, message: '流程管理员不能为空', trigger: 'blur' }, | ||||
|   ], | ||||
|  | @ -219,9 +220,7 @@ const validate = async () => { | |||
|   await formRef.value?.validate(); | ||||
| }; | ||||
| 
 | ||||
| defineExpose({ | ||||
|   validate, | ||||
| }); | ||||
| defineExpose({ validate }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|  | @ -229,8 +228,8 @@ defineExpose({ | |||
|     ref="formRef" | ||||
|     :model="modelData" | ||||
|     :rules="rules" | ||||
|     :label-col="{ span: 6 }" | ||||
|     :wrapper-col="{ span: 18 }" | ||||
|     :label-col="{ span: 4 }" | ||||
|     :wrapper-col="{ span: 20 }" | ||||
|     class="mt-5" | ||||
|   > | ||||
|     <Form.Item label="流程标识" name="key" class="mb-5"> | ||||
|  | @ -247,7 +246,7 @@ defineExpose({ | |||
|           " | ||||
|           placement="top" | ||||
|         > | ||||
|           <ShieldQuestion class="ml-1 text-gray-500" /> | ||||
|           <CircleHelp class="ml-1 size-5 text-gray-900" /> | ||||
|         </Tooltip> | ||||
|       </div> | ||||
|     </Form.Item> | ||||
|  |  | |||
|  | @ -0,0 +1,187 @@ | |||
| <script lang="ts" setup> | ||||
| import type { Rule } from 'ant-design-vue/es/form'; | ||||
| 
 | ||||
| import type { BpmFormApi } from '#/api/bpm/form'; | ||||
| 
 | ||||
| import { ref, watch } from 'vue'; | ||||
| 
 | ||||
| import { CircleHelp } from '@vben/icons'; | ||||
| 
 | ||||
| import FormCreate from '@form-create/ant-design-vue'; | ||||
| import { | ||||
|   Form, | ||||
|   FormItem, | ||||
|   Input, | ||||
|   Radio, | ||||
|   RadioGroup, | ||||
|   Select, | ||||
|   SelectOption, | ||||
|   Tooltip, | ||||
| } from 'ant-design-vue'; | ||||
| 
 | ||||
| import { getFormDetail } from '#/api/bpm/form'; | ||||
| import { | ||||
|   BpmModelFormType, | ||||
|   DICT_TYPE, | ||||
|   getDictOptions, | ||||
|   setConfAndFields2, | ||||
| } from '#/utils'; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   formList: { | ||||
|     type: Array<BpmFormApi.FormVO>, | ||||
|     required: true, | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| const formRef = ref(); | ||||
| 
 | ||||
| // 创建本地数据副本 | ||||
| const modelData = defineModel<any>(); | ||||
| 
 | ||||
| // 表单预览数据 | ||||
| const formPreview = ref({ | ||||
|   formData: {} as any, | ||||
|   rule: [], | ||||
|   option: { | ||||
|     submitBtn: false, | ||||
|     resetBtn: false, | ||||
|     formData: {}, | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| /** 监听表单ID变化,加载表单数据 */ | ||||
| watch( | ||||
|   () => modelData.value.formId, | ||||
|   async (newFormId) => { | ||||
|     if (newFormId && modelData.value.formType === BpmModelFormType.NORMAL) { | ||||
|       const data = await getFormDetail(newFormId); | ||||
|       setConfAndFields2(formPreview.value, data.conf, data.fields); | ||||
|       // 设置只读 | ||||
|       formPreview.value.rule.forEach((item: any) => { | ||||
|         item.props = { ...item.props, disabled: true }; | ||||
|       }); | ||||
|     } else { | ||||
|       formPreview.value.rule = []; | ||||
|     } | ||||
|   }, | ||||
|   { immediate: true }, | ||||
| ); | ||||
| 
 | ||||
| const rules: Record<string, Rule[]> = { | ||||
|   formType: [{ required: true, message: '表单类型不能为空', trigger: 'blur' }], | ||||
|   formId: [{ required: true, message: '流程表单不能为空', trigger: 'blur' }], | ||||
|   formCustomCreatePath: [ | ||||
|     { required: true, message: '表单提交路由不能为空', trigger: 'blur' }, | ||||
|   ], | ||||
|   formCustomViewPath: [ | ||||
|     { required: true, message: '表单查看地址不能为空', trigger: 'blur' }, | ||||
|   ], | ||||
| }; | ||||
| 
 | ||||
| /** 表单校验 */ | ||||
| const validate = async () => { | ||||
|   await formRef.value?.validate(); | ||||
| }; | ||||
| 
 | ||||
| defineExpose({ validate }); | ||||
| </script> | ||||
| <template> | ||||
|   <Form | ||||
|     ref="formRef" | ||||
|     :model="modelData" | ||||
|     :rules="rules" | ||||
|     :label-col="{ span: 4 }" | ||||
|     :wrapper-col="{ span: 20 }" | ||||
|     class="mt-5" | ||||
|   > | ||||
|     <FormItem label="表单类型" name="formType" class="mb-5"> | ||||
|       <RadioGroup v-model:value="modelData.formType"> | ||||
|         <Radio | ||||
|           v-for="dict in getDictOptions( | ||||
|             DICT_TYPE.BPM_MODEL_FORM_TYPE, | ||||
|             'number', | ||||
|           )" | ||||
|           :key="dict.value as string" | ||||
|           :value="dict.value" | ||||
|         > | ||||
|           {{ dict.label }} | ||||
|         </Radio> | ||||
|       </RadioGroup> | ||||
|     </FormItem> | ||||
|     <FormItem | ||||
|       v-if="modelData.formType === BpmModelFormType.NORMAL" | ||||
|       label="流程表单" | ||||
|       name="formId" | ||||
|       class="mb-5" | ||||
|     > | ||||
|       <Select v-model:value="modelData.formId" clearable> | ||||
|         <SelectOption | ||||
|           v-for="form in props.formList" | ||||
|           :key="form.id" | ||||
|           :value="form.id" | ||||
|         > | ||||
|           {{ form.name }} | ||||
|         </SelectOption> | ||||
|         > | ||||
|       </Select> | ||||
|     </FormItem> | ||||
|     <FormItem | ||||
|       v-if="modelData.formType === BpmModelFormType.CUSTOM" | ||||
|       label="表单提交路由" | ||||
|       name="formCustomCreatePath" | ||||
|       class="mb-5" | ||||
|     > | ||||
|       <div class="flex items-center"> | ||||
|         <Input | ||||
|           v-model:value="modelData.formCustomCreatePath" | ||||
|           placeholder="请输入表单提交路由" | ||||
|         /> | ||||
|         <Tooltip | ||||
|           title="自定义表单的提交路径,使用 Vue 的路由地址, 例如说: bpm/oa/leave/create.vue" | ||||
|           placement="top" | ||||
|         > | ||||
|           <CircleHelp class="ml-1 size-5 text-gray-900" /> | ||||
|         </Tooltip> | ||||
|       </div> | ||||
|     </FormItem> | ||||
|     <FormItem | ||||
|       v-if="modelData.formType === BpmModelFormType.CUSTOM" | ||||
|       label="表单查看地址" | ||||
|       name="formCustomViewPath" | ||||
|       class="mb-5" | ||||
|     > | ||||
|       <div class="flex items-center"> | ||||
|         <Input | ||||
|           v-model:value="modelData.formCustomViewPath" | ||||
|           placeholder="请输入表单查看的组件地址" | ||||
|         /> | ||||
|         <Tooltip | ||||
|           title="自定义表单的查看组件地址,使用 Vue 的组件地址,例如说:bpm/oa/leave/detail.vue" | ||||
|           placement="top" | ||||
|         > | ||||
|           <CircleHelp class="ml-1 size-5 text-gray-900" /> | ||||
|         </Tooltip> | ||||
|       </div> | ||||
|     </FormItem> | ||||
|     <!-- 表单预览 --> | ||||
|     <div | ||||
|       v-if=" | ||||
|         modelData.formType === BpmModelFormType.NORMAL && | ||||
|         modelData.formId && | ||||
|         formPreview.rule.length > 0 | ||||
|       " | ||||
|       class="mb-5 mt-7 rounded-sm border border-solid border-gray-200 p-5" | ||||
|     > | ||||
|       <div class="mb-[15px] flex items-center"> | ||||
|         <div class="mr-[10px] h-[15px] w-[4px] bg-[#1890ff]"></div> | ||||
|         <span class="text-[15px] font-bold">表单预览</span> | ||||
|       </div> | ||||
|       <FormCreate | ||||
|         v-model:api="formPreview.formData" | ||||
|         :rule="formPreview.rule" | ||||
|         :option="formPreview.option" | ||||
|       /> | ||||
|     </div> | ||||
|   </Form> | ||||
| </template> | ||||
		Loading…
	
		Reference in New Issue
	
	 jason
						jason