【功能完善】审批时,流程表单可编辑字段,可修改。

This commit is contained in:
jason
2024-12-08 11:58:46 +08:00
parent ee46a31a81
commit 0b6af855ac
5 changed files with 93 additions and 31 deletions

View File

@@ -15,7 +15,6 @@ import {
AssignStartUserHandlerType, AssignStartUserHandlerType,
AssignEmptyHandlerType, AssignEmptyHandlerType,
FieldPermissionType, FieldPermissionType,
ProcessVariableEnum
} from './consts' } from './consts'
import { parseFormFields } from '@/components/FormCreate/src/utils/index' import { parseFormFields } from '@/components/FormCreate/src/utils/index'
export function useWatchNode(props: { flowNode: SimpleFlowNode }): Ref<SimpleFlowNode> { export function useWatchNode(props: { flowNode: SimpleFlowNode }): Ref<SimpleFlowNode> {
@@ -37,13 +36,6 @@ const parseFormCreateFields = (formFields?: string[]) => {
parseFormFields(JSON.parse(fieldStr), result) parseFormFields(JSON.parse(fieldStr), result)
}) })
} }
// 固定添加发起人 ID 字段
result.unshift({
field: ProcessVariableEnum.START_USER_ID,
title: '发起人',
type: 'UserSelect',
required: true
})
return result return result
} }

View File

@@ -102,7 +102,7 @@
<div class="mr-2"> <div class="mr-2">
<el-select style="width: 160px" v-model="rule.leftSide"> <el-select style="width: 160px" v-model="rule.leftSide">
<el-option <el-option
v-for="(item, index) in fieldsInfo" v-for="(item, index) in fieldOptions"
:key="index" :key="index"
:label="item.title" :label="item.title"
:value="item.field" :value="item.field"
@@ -160,7 +160,8 @@ import {
COMPARISON_OPERATORS, COMPARISON_OPERATORS,
ConditionGroup, ConditionGroup,
Condition, Condition,
ConditionRule ConditionRule,
ProcessVariableEnum
} from '../consts' } from '../consts'
import { getDefaultConditionNodeName } from '../utils' import { getDefaultConditionNodeName } from '../utils'
import { useFormFields } from '../node' import { useFormFields } from '../node'
@@ -364,9 +365,21 @@ const addConditionRule = (condition: Condition, idx: number) => {
const deleteConditionRule = (condition: Condition, idx: number) => { const deleteConditionRule = (condition: Condition, idx: number) => {
condition.rules.splice(idx, 1) condition.rules.splice(idx, 1)
} }
const fieldsInfo = useFormFields() const fieldsInfo = useFormFields()
/** 条件规则可选择的表单字段 */
const fieldOptions = computed(() => {
const fieldsCopy = fieldsInfo.slice();
// 固定添加发起人 ID 字段
fieldsCopy.unshift({
field: ProcessVariableEnum.START_USER_ID,
title: '发起人',
required: true
})
return fieldsCopy
})
const getFieldTitle = (field: string) => { const getFieldTitle = (field: string) => {
const item = fieldsInfo.find((item) => item.field === field) const item = fieldsInfo.find((item) => item.field === field)
return item?.title return item?.title

View File

@@ -469,7 +469,8 @@ import {
TimeoutHandlerType, TimeoutHandlerType,
ASSIGN_EMPTY_HANDLER_TYPES, ASSIGN_EMPTY_HANDLER_TYPES,
AssignEmptyHandlerType, AssignEmptyHandlerType,
FieldPermissionType FieldPermissionType,
ProcessVariableEnum
} from '../consts' } from '../consts'
import { import {
@@ -519,6 +520,13 @@ const { formType, fieldsPermissionConfig, formFieldOptions, getNodeConfigFormFie
useFormFieldsPermission(FieldPermissionType.READ) useFormFieldsPermission(FieldPermissionType.READ)
// 表单内用户字段选项, 必须是必填和用户选择器 // 表单内用户字段选项, 必须是必填和用户选择器
const userFieldOnFormOptions = computed(() => { const userFieldOnFormOptions = computed(() => {
// 固定添加发起人 ID 字段
formFieldOptions.unshift({
field: ProcessVariableEnum.START_USER_ID,
title: '发起人',
type: 'UserSelect',
required: true
})
return formFieldOptions.filter((item) => item.type === 'UserSelect') return formFieldOptions.filter((item) => item.type === 'UserSelect')
}) })
// 表单内部门字段选项, 必须是必填和部门选择器 // 表单内部门字段选项, 必须是必填和部门选择器

View File

@@ -477,13 +477,12 @@ import { useUserStoreWithOut } from '@/store/modules/user'
import { setConfAndFields2 } from '@/utils/formCreate' import { setConfAndFields2 } from '@/utils/formCreate'
import * as TaskApi from '@/api/bpm/task' import * as TaskApi from '@/api/bpm/task'
import * as ProcessInstanceApi from '@/api/bpm/processInstance' import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import { propTypes } from '@/utils/propTypes' import * as UserApi from '@/api/system/user'
import { import {
OperationButtonType, OperationButtonType,
OPERATION_BUTTON_NAME OPERATION_BUTTON_NAME
} from '@/components/SimpleProcessDesignerV2/src/consts' } from '@/components/SimpleProcessDesignerV2/src/consts'
import { BpmProcessInstanceStatus } from '@/utils/constants' import { BpmProcessInstanceStatus, BpmModelFormType } from '@/utils/constants'
defineOptions({ name: 'ProcessInstanceBtnContainer' }) defineOptions({ name: 'ProcessInstanceBtnContainer' })
const router = useRouter() // 路由 const router = useRouter() // 路由
@@ -492,11 +491,15 @@ const { proxy } = getCurrentInstance() as any
const userId = useUserStoreWithOut().getUser.id // 当前登录的编号 const userId = useUserStoreWithOut().getUser.id // 当前登录的编号
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const props = defineProps({
processInstance: propTypes.object, // 流程实例信息 const props = defineProps< {
processDefinition: propTypes.object, // 流程定义信息 processInstance: any, // 流程实例信息
userOptions: propTypes.any processDefinition: any, // 流程定义信息
}) userOptions: UserApi.UserVO[],
normalForm: any, // 流程表单 formCreate
normalFormApi: any, // 流程表单 formCreate Api
writableFields: string[] // 流程表单可以编辑的字段
}>()
const formLoading = ref(false) // 表单加载中 const formLoading = ref(false) // 表单加载中
const popOverVisible = ref({ const popOverVisible = ref({
@@ -554,6 +557,14 @@ const openReturnPopover = async () => {
/** 弹出气泡卡 */ /** 弹出气泡卡 */
const openPopover = async (type: string) => { const openPopover = async (type: string) => {
if (type === 'approve') {
// 校验流程表单
const valid = await validateNormalForm();
if (!valid) {
message.error('表单校验不通过,请先完善表单!!')
return;
}
}
Object.keys(popOverVisible.value).forEach((item) => { Object.keys(popOverVisible.value).forEach((item) => {
popOverVisible.value[item] = item === type popOverVisible.value[item] = item === type
}) })
@@ -565,24 +576,29 @@ const openPopover = async (type: string) => {
const handleAudit = async (pass: boolean) => { const handleAudit = async (pass: boolean) => {
formLoading.value = true formLoading.value = true
try { try {
// 校验审批表单
const genericFormRef = proxy.$refs['formRef'] const genericFormRef = proxy.$refs['formRef']
// 1.2 校验表单
const elForm = unref(genericFormRef) const elForm = unref(genericFormRef)
if (!elForm) return if (!elForm) return
const valid = await elForm.validate() const valid = await elForm.validate()
if (!valid) return if (!valid) return
// 提交审批
// 2.1 提交审批
const data = { const data = {
id: runningTask.value.id, id: runningTask.value.id,
reason: genericForm.value.reason reason: genericForm.value.reason,
} }
if (pass) { if (pass) {
// 获取修改的流程变量, 暂时只支持流程表单
const variables = getUpdatedProcessInstanceVaiables();
// 审批通过, 把修改的字段值赋于流程实例变量
// @ts-ignore
data.variables = variables
// 审批通过,并且有额外的 approveForm 表单,需要校验 + 拼接到 data 表单里提交 // 审批通过,并且有额外的 approveForm 表单,需要校验 + 拼接到 data 表单里提交
const formCreateApi = approveFormFApi.value const formCreateApi = approveFormFApi.value
if (Object.keys(formCreateApi)?.length > 0) { if (Object.keys(formCreateApi)?.length > 0) {
await formCreateApi.validate() await formCreateApi.validate()
// @ts-ignore // @ts-ignore
// TODO 芋艿 任务有多表单这里要如何处理,会和可编辑的字段冲突
data.variables = approveForm.value.value data.variables = approveForm.value.value
} }
await TaskApi.approveTask(data) await TaskApi.approveTask(data)
@@ -855,6 +871,30 @@ const loadTodoTask = (task: any) => {
} }
} }
/** 校验流程表单 */
const validateNormalForm = async () => {
if (props.processDefinition?.formType === BpmModelFormType.NORMAL) {
let valid = true
try {
await props.normalFormApi?.validate()
} catch {
valid = false;
}
return valid;
} else {
return true;
}
}
/** 从可以编辑的流程表单字段,获取需要修改的流程实例的变量 */
const getUpdatedProcessInstanceVaiables = ()=> {
const variables = {}
props.writableFields.forEach( (field) => {
const fieldValue = props.normalFormApi.getValue(field)
variables[field] = fieldValue;
})
return variables
}
defineExpose({ loadTodoTask }) defineExpose({ loadTodoTask })
</script> </script>

View File

@@ -49,7 +49,7 @@
class="form-box flex flex-col mb-30px flex-1" class="form-box flex flex-col mb-30px flex-1"
> >
<!-- 情况一流程表单 --> <!-- 情况一流程表单 -->
<el-col v-if="processDefinition?.formType === 10"> <el-col v-if="processDefinition?.formType === BpmModelFormType.NORMAL">
<form-create <form-create
v-model="detailForm.value" v-model="detailForm.value"
v-model:api="fApi" v-model:api="fApi"
@@ -58,7 +58,7 @@
/> />
</el-col> </el-col>
<!-- 情况二业务表单 --> <!-- 情况二业务表单 -->
<div v-if="processDefinition?.formType === 20"> <div v-if="processDefinition?.formType === BpmModelFormType.CUSTOM">
<BusinessFormComponent :id="processInstance.businessKey" /> <BusinessFormComponent :id="processInstance.businessKey" />
</div> </div>
</div> </div>
@@ -116,6 +116,9 @@
:process-instance="processInstance" :process-instance="processInstance"
:process-definition="processDefinition" :process-definition="processDefinition"
:userOptions="userOptions" :userOptions="userOptions"
:normal-form ="detailForm"
:normal-form-api="fApi"
:writable-fields="writableFields"
@success="refresh" @success="refresh"
/> />
</div> </div>
@@ -126,7 +129,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { formatDate } from '@/utils/formatTime' import { formatDate } from '@/utils/formatTime'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { BpmModelType } from '@/utils/constants' import { BpmModelType,BpmModelFormType } from '@/utils/constants'
import { setConfAndFields2 } from '@/utils/formCreate' import { setConfAndFields2 } from '@/utils/formCreate'
import { registerComponent } from '@/utils/routerHelper' import { registerComponent } from '@/utils/routerHelper'
import type { ApiAttrs } from '@form-create/element-ui/types/config' import type { ApiAttrs } from '@form-create/element-ui/types/config'
@@ -171,6 +174,9 @@ const detailForm = ref({
value: {} value: {}
}) // 流程实例的表单详情 }) // 流程实例的表单详情
// 表单可以编辑的字段
const writableFields : Array<string> = [];
/** 获得详情 */ /** 获得详情 */
const getDetail = () => { const getDetail = () => {
getApprovalDetail() getApprovalDetail()
@@ -202,11 +208,12 @@ const getApprovalDetail = async () => {
processDefinition.value = data.processDefinition processDefinition.value = data.processDefinition
// 设置表单信息 // 设置表单信息
if (processDefinition.value.formType === 10) { if (processDefinition.value.formType === BpmModelFormType.NORMAL) {
// 获取表单字段权限 // 获取表单字段权限
const formFieldsPermission = data.formFieldsPermission const formFieldsPermission = data.formFieldsPermission
// 清空可编辑字段为空
if (detailForm.value.rule.length > 0) { writableFields.splice(0)
if (detailForm.value.rule?.length > 0) {
// 避免刷新 form-create 显示不了 // 避免刷新 form-create 显示不了
detailForm.value.value = processInstance.value.formVariables detailForm.value.value = processInstance.value.formVariables
} else { } else {
@@ -271,6 +278,8 @@ const setFieldPermission = (field: string, permission: string) => {
if (permission === FieldPermissionType.WRITE) { if (permission === FieldPermissionType.WRITE) {
//@ts-ignore //@ts-ignore
fApi.value?.disabled(false, field) fApi.value?.disabled(false, field)
// 加入可以编辑的字段
writableFields.push(field);
} }
if (permission === FieldPermissionType.NONE) { if (permission === FieldPermissionType.NONE) {
//@ts-ignore //@ts-ignore
@@ -314,6 +323,7 @@ $process-header-height: 194px;
overflow: auto; overflow: auto;
.form-scroll-area { .form-scroll-area {
display: flex;
height: calc( height: calc(
100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px - 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px -
$process-header-height - 40px $process-header-height - 40px
@@ -323,7 +333,6 @@ $process-header-height: 194px;
$process-header-height - 40px $process-header-height - 40px
); );
overflow: auto; overflow: auto;
display: flex;
flex-direction: column; flex-direction: column;
:deep(.box-card) { :deep(.box-card) {