From 86cc441465215a751105c87e36f821b523d4822f Mon Sep 17 00:00:00 2001 From: "bai.zixv" Date: Thu, 4 Jul 2024 14:04:26 +0800 Subject: [PATCH] feat: approval, resubmit approval (#1270) Reviewed-on: https://git.daoyoucloud.com/daoyoucloud/tachybase/pulls/1270 Reviewed-by: sealday Co-authored-by: bai.zixv Co-committed-by: bai.zixv --- ...Todos.tsx => ApprovalTodos.collection.tsx} | 0 ...d.FormBlock.tsx => FormBlock.provider.tsx} | 0 .../approver-interface/ApproverBlock.view.tsx | 2 +- .../ApproverInterface.schema.tsx | 2 +- .../Pd.ApprovalActionProvider.tsx | 1 - .../LauncherActionConfig.component.tsx | 28 +++++++++ .../LauncherActionConfig.initializer.tsx | 11 +++- .../LauncherBlockButton.component.tsx | 12 +++- .../SchemaAddBlock.component.tsx | 9 +++ .../src/client/features/approval/constants.ts | 37 ++++++++++-- .../approval-block/ApprovalBlock.provider.tsx | 2 +- .../launch/ActionResubmit.provider.tsx | 21 +++++++ .../approval-block/launch/Pd.ActionBar.tsx | 7 ++- .../launch/Pd.ApplyActionStatus.tsx | 2 +- .../launch/VC.ViewActionLaunchContent.tsx | 15 ++++- .../launch/hooks/useActionResubmit.ts | 59 +++++++++++++++++++ .../todos/VC.ViewActionTodosContent.tsx | 2 +- .../approval-common/ApprovalsSummary.view.tsx | 28 ++++++++- .../RecordApprovals.decorator.tsx | 2 +- .../plugin-workflow/src/locale/en-US.json | 3 +- .../plugin-workflow/src/locale/zh-CN.json | 3 +- .../features/approval/ApprovalTrigger.ts | 4 +- .../src/server/features/approval/actions.ts | 58 +++++++++++++++++- .../src/server/features/approval/constants.ts | 1 + .../src/server/features/approval/tools.ts | 3 +- 25 files changed, 284 insertions(+), 28 deletions(-) rename packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/{Cn.ApprovalTodos.tsx => ApprovalTodos.collection.tsx} (100%) rename packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/{Pd.FormBlock.tsx => FormBlock.provider.tsx} (100%) create mode 100644 packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/ActionResubmit.provider.tsx create mode 100644 packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/hooks/useActionResubmit.ts diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/Cn.ApprovalTodos.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/ApprovalTodos.collection.tsx similarity index 100% rename from packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/Cn.ApprovalTodos.tsx rename to packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/ApprovalTodos.collection.tsx diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/Pd.FormBlock.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/FormBlock.provider.tsx similarity index 100% rename from packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/Pd.FormBlock.tsx rename to packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/common/FormBlock.provider.tsx diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/ApproverBlock.view.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/ApproverBlock.view.tsx index aa835f190..cb6b185ba 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/ApproverBlock.view.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/ApproverBlock.view.tsx @@ -6,7 +6,7 @@ import { uid } from '@tachybase/utils/client'; import { Spin } from 'antd'; import { DetailsBlockProvider, SimpleDesigner } from '../../../../../components'; -import { FormBlockProvider } from '../../../common/Pd.FormBlock'; +import { FormBlockProvider } from '../../../common/FormBlock.provider'; import { flatSchemaArray } from '../../../constants'; import { ContextApproverConfig } from '../ApproverConfig.context'; import { ActionBarProvider } from './Pd.ActionBarProvider'; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/ApproverInterface.schema.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/ApproverInterface.schema.tsx index cda8e9694..0da458ac9 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/ApproverInterface.schema.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/ApproverInterface.schema.tsx @@ -11,7 +11,7 @@ import { useForm } from '@tachybase/schema'; import { uid } from '@tachybase/utils/client'; import { useFlowContext } from '../../../../../FlowContext'; -import { CollectionApprovalTodos } from '../../../common/Cn.ApprovalTodos'; +import { CollectionApprovalTodos } from '../../../common/ApprovalTodos.collection'; import { NAMESPACE } from '../../../locale'; import { SchemaAddBlock } from '../../trigger/launcher-interface/SchemaAddBlock.component'; import { ApproverBlock } from './ApproverBlock.view'; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/Pd.ApprovalActionProvider.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/Pd.ApprovalActionProvider.tsx index 378a8634d..dcf362b53 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/Pd.ApprovalActionProvider.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/instruction/approver-interface/Pd.ApprovalActionProvider.tsx @@ -1,4 +1,3 @@ export const ApprovalActionProvider = (props) => { - console.log('%c Line:2 🍰 props', 'font-size:18px;color:#4fff4B;background:#7f2b82', props); return props.children; }; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherActionConfig.component.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherActionConfig.component.tsx index 680f6736d..86ac9fef1 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherActionConfig.component.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherActionConfig.component.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { ActionInitializer, useSchemaInitializerItem } from '@tachybase/client'; +import { NAMESPACE } from '../../../locale'; + // 区块-配置操作 export const LauncherActionConfigComponent = () => { const itemConfig = useSchemaInitializerItem(); @@ -29,3 +31,29 @@ export const LauncherActionConfigComponent = () => { /> ); }; + +// setup-action-resubmit +export const LauncherActionConfigReSubmit = () => { + const itemConfig = useSchemaInitializerItem(); + const { action, actionProps = {}, ...restItemConfig } = itemConfig; + return ( + + ); +}; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherActionConfig.initializer.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherActionConfig.initializer.tsx index ddaf99463..f8cb0f3f7 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherActionConfig.initializer.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherActionConfig.initializer.tsx @@ -2,11 +2,11 @@ import { SchemaInitializer } from '@tachybase/client'; import { APPROVAL_STATUS } from '../../../constants'; import { NAMESPACE } from '../../../locale'; -import { LauncherActionConfigComponent } from './LauncherActionConfig.component'; +import { LauncherActionConfigComponent, LauncherActionConfigReSubmit } from './LauncherActionConfig.component'; // 区块-配置操作 export const LauncherActionConfigInitializer = new SchemaInitializer({ - name: 'ApprovalApplyAddActionButton', + name: 'LauncherActionConfigInitializer', title: '{{t("Configure actions")}}', items: [ { @@ -25,5 +25,12 @@ export const LauncherActionConfigInitializer = new SchemaInitializer({ Component: LauncherActionConfigComponent, action: APPROVAL_STATUS.DRAFT, }, + { + name: 'reSubmit', + type: 'item', + title: `{{t("resubmit", { ns: "${NAMESPACE}" })}}`, + action: APPROVAL_STATUS.RESUBMIT, + Component: LauncherActionConfigReSubmit, + }, ], }); diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherBlockButton.component.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherBlockButton.component.tsx index 84aafd6d4..4f957816c 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherBlockButton.component.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/LauncherBlockButton.component.tsx @@ -27,15 +27,21 @@ export const LauncherAddBlockButtonComponent = () => { ['x-acl-action']: deleteB, ...formSchema } = createFormBlockSchema({ - actionInitializers: 'ApprovalApplyAddActionButton', + actionInitializers: 'LauncherActionConfigInitializer', actions: { submit: { type: 'void', title: '{{t("Submit")}}', 'x-decorator': 'ApplyActionStatusProvider', - 'x-decorator-props': { value: APPROVAL_STATUS.SUBMITTED }, + 'x-decorator-props': { + value: APPROVAL_STATUS.SUBMITTED, + }, 'x-component': 'Action', - 'x-component-props': { type: 'primary', htmlType: 'submit', useAction: '{{ useSubmit }}' }, + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useAction: '{{ useSubmit }}', + }, 'x-designer': 'Action.Designer', 'x-designer-props': {}, 'x-action': `${APPROVAL_STATUS.SUBMITTED}`, diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/SchemaAddBlock.component.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/SchemaAddBlock.component.tsx index 0d6cf7fed..5cca15777 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/SchemaAddBlock.component.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/configuration/trigger/launcher-interface/SchemaAddBlock.component.tsx @@ -53,11 +53,13 @@ export const SchemaAddBlock = ({ value, onChange }) => { ActionBarProvider, ApplyActionStatusProvider, WithdrawActionProvider, + ProviderActionResubmit, }} scope={{ useSubmit, useWithdrawAction, useFormBlockProps, + useActionResubmit, }} // @ts-ignore ugly schema={data} @@ -80,6 +82,13 @@ function ApplyActionStatusProvider(props) { function WithdrawActionProvider(props) { return null; } + +function useActionResubmit() { + return { run() {} }; +} +function ProviderActionResubmit(props) { + return props.children; +} // TODO: const E = (f, o, p) => // eslint-disable-next-line promise/param-names diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/constants.ts b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/constants.ts index 523ac9c98..10b6d02f5 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/constants.ts +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/constants.ts @@ -8,6 +8,7 @@ export const APPROVAL_STATUS = { SUBMITTED: 2, PROCESSING: 3, APPROVED: 4, + RESUBMIT: 5, REJECTED: -1, }; @@ -37,17 +38,43 @@ export const approvalStatusConfigObj = approvalStatusOptions.reduce( {}, ); export const ApprovalStatusEnums = [ - { value: APPROVAL_STATUS.DRAFT, label: `{{t("Draft", { ns: "${NAMESPACE}" })}}`, editable: true }, + { + value: APPROVAL_STATUS.DRAFT, + label: `{{t("Draft", { ns: "${NAMESPACE}" })}}`, + editable: true, + }, { value: APPROVAL_STATUS.RETURNED, label: `{{t("Returned", { ns: "${NAMESPACE}" })}}`, color: 'purple', editable: true, }, - { value: APPROVAL_STATUS.SUBMITTED, label: `{{t("Submitted", { ns: "${NAMESPACE}" })}}`, color: 'cyan' }, - { value: APPROVAL_STATUS.PROCESSING, label: `{{t("Processing", { ns: "${NAMESPACE}" })}}`, color: 'gold' }, - { value: APPROVAL_STATUS.APPROVED, label: `{{t("Approved", { ns: "${NAMESPACE}" })}}`, color: 'green' }, - { value: APPROVAL_STATUS.REJECTED, label: `{{t("Rejected", { ns: "${NAMESPACE}" })}}`, color: 'red' }, + { + value: APPROVAL_STATUS.SUBMITTED, + label: `{{t("Submitted", { ns: "${NAMESPACE}" })}}`, + color: 'cyan', + }, + { + value: APPROVAL_STATUS.PROCESSING, + label: `{{t("Processing", { ns: "${NAMESPACE}" })}}`, + color: 'gold', + }, + { + value: APPROVAL_STATUS.APPROVED, + label: `{{t("Approved", { ns: "${NAMESPACE}" })}}`, + color: 'green', + }, + { + value: APPROVAL_STATUS.RESUBMIT, + label: `{{t("reSubmit", { ns: "${NAMESPACE}" })}}`, + color: 'blue', + editable: true, + }, + { + value: APPROVAL_STATUS.REJECTED, + label: `{{t("Rejected", { ns: "${NAMESPACE}" })}}`, + color: 'red', + }, ]; export const ApprovalStatusEnumDict = ApprovalStatusEnums.reduce((e, t) => Object.assign(e, { [t.value]: t }), {}); export const JobStatusEnums = { diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/ApprovalBlock.provider.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/ApprovalBlock.provider.tsx index 3504618da..63bc22e2b 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/ApprovalBlock.provider.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/ApprovalBlock.provider.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { ExtendCollectionsProvider, TableBlockProvider, useRecord } from '@tachybase/client'; -import { CollectionApprovalTodos } from '../../common/Cn.ApprovalTodos'; +import { CollectionApprovalTodos } from '../../common/ApprovalTodos.collection'; import { CollectionApprovals } from '../approval-common/Approvals.collection'; import { CollectionFlowNodes } from '../approval-common/FlowNodes.collection'; import { CollectionWorkflows } from '../approval-common/Workflows.collection'; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/ActionResubmit.provider.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/ActionResubmit.provider.tsx new file mode 100644 index 000000000..1a7e9b88e --- /dev/null +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/ActionResubmit.provider.tsx @@ -0,0 +1,21 @@ +import { useCurrentUserContext } from '@tachybase/client'; + +import { useFlowContext } from '../../../../../FlowContext'; +import { APPROVAL_STATUS } from '../../../constants'; +import { useApproval } from '../../approval-common/ApprovalData.provider'; + +export function ProviderActionResubmit(props) { + const { data } = useCurrentUserContext(); + const { status, createdById } = useApproval(); + const { workflow } = useFlowContext(); + + const isSameId = data.data.id === createdById; + // const isEnabledWithdraw = workflow.enabled && workflow.config.withdrawable; + // const isNotDraft = status !== APPROVAL_STATUS.DRAFT; + + if (isSameId) { + return props.children; + } + + return null; +} diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Pd.ActionBar.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Pd.ActionBar.tsx index a7a1a8632..3da567ac8 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Pd.ActionBar.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Pd.ActionBar.tsx @@ -11,7 +11,12 @@ export function ActionBarProvider(props) { const isSameId = data.data.id === createdById; const isSameExcutionId = latestExecutionId === approvalExecution.id; - const isExcutionDid = [APPROVAL_STATUS.DRAFT, APPROVAL_STATUS.RETURNED, APPROVAL_STATUS.SUBMITTED].includes(status); + const isExcutionDid = [ + APPROVAL_STATUS.DRAFT, + APPROVAL_STATUS.RETURNED, + APPROVAL_STATUS.SUBMITTED, + APPROVAL_STATUS.RESUBMIT, + ].includes(status); if (!isSameId || !isSameExcutionId || !isExcutionDid) { return null; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Pd.ApplyActionStatus.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Pd.ApplyActionStatus.tsx index 542251bec..6427d8e7e 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Pd.ApplyActionStatus.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Pd.ApplyActionStatus.tsx @@ -18,7 +18,7 @@ export function ApplyActionStatusProvider(props) { const { data } = useCurrentUserContext(); const isSameId = data.data.id === createdById; const isEnbled = workflow.enabled; - const isStatusDid = [APPROVAL_STATUS.DRAFT, APPROVAL_STATUS.RETURNED].includes(status); + const isStatusDid = [APPROVAL_STATUS.RESUBMIT, APPROVAL_STATUS.DRAFT, APPROVAL_STATUS.RETURNED].includes(status); if (isSameId && isEnbled && isStatusDid) { return {children}; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/VC.ViewActionLaunchContent.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/VC.ViewActionLaunchContent.tsx index f08927540..15f4c08e1 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/VC.ViewActionLaunchContent.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/VC.ViewActionLaunchContent.tsx @@ -12,13 +12,16 @@ import { useForm } from '@tachybase/schema'; import { Result, Spin } from 'antd'; import { DetailsBlockProvider } from '../../../../../components'; -import { FormBlockProvider } from '../../../common/Pd.FormBlock'; +import { FormBlockProvider } from '../../../common/FormBlock.provider'; +import { APPROVAL_STATUS } from '../../../constants'; import { NAMESPACE } from '../../../locale'; import { ApprovalContext } from '../../approval-common/ApprovalData.provider'; import { ContextWithActionEnabled } from '../../approval-common/WithActionEnabled.provider'; import { ContextApprovalExecution } from '../common/ApprovalExecution.provider'; import { FlowContextProvider } from '../common/FlowContext.provider'; import { SchemaComponentContextProvider } from '../common/SchemaComponent.provider'; +import { ProviderActionResubmit } from './ActionResubmit.provider'; +import { useActionResubmit } from './hooks/useActionResubmit'; import { useDestroyAction } from './hooks/useDestroyAction'; import { useFormBlockProps } from './hooks/useFormBlockProps'; import { useSubmit } from './hooks/useSubmit'; @@ -59,6 +62,8 @@ export const ViewActionLaunchContent = () => { // @ts-ignore const approvalData = data?.data; + const needHideProcess = actionEnabled || approvalData?.status !== APPROVAL_STATUS.RESUBMIT; + if (loading) { return ; } @@ -90,6 +95,7 @@ export const ViewActionLaunchContent = () => { ApplyActionStatusProvider, WithdrawActionProvider, DetailsBlockProvider, + ProviderActionResubmit, }} scope={{ useForm, @@ -98,6 +104,7 @@ export const ViewActionLaunchContent = () => { useDetailsBlockProps: useFormBlockContext, useWithdrawAction, useDestroyAction, + useActionResubmit, }} schema={{ name: `view-${approval == null ? void 0 : approval.id}`, @@ -116,7 +123,9 @@ export const ViewActionLaunchContent = () => { detail: { type: 'void', 'x-decorator': 'SchemaComponentContextProvider', - 'x-decorator-props': { designable: false }, + 'x-decorator-props': { + designable: true, + }, 'x-component': 'RemoteSchemaComponent', 'x-component-props': { uid: workflow?.config.applyForm, @@ -126,7 +135,7 @@ export const ViewActionLaunchContent = () => { }, }, }, - actionEnabled + needHideProcess ? {} : { process: { diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/hooks/useActionResubmit.ts b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/hooks/useActionResubmit.ts new file mode 100644 index 000000000..e34825438 --- /dev/null +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/hooks/useActionResubmit.ts @@ -0,0 +1,59 @@ +import { useAPIClient } from '@tachybase/client'; +import { useFlowContext } from '@tachybase/plugin-workflow/client'; +import { useField } from '@tachybase/schema'; + +import _ from 'lodash'; + +import { APPROVAL_STATUS } from '../../../../constants'; +import { useApproval } from '../../../approval-common/ApprovalData.provider'; +import { useHandleRefresh } from '../../common/useHandleRefresh'; + +// 重新发起 +export function useActionResubmit() { + const { refreshTable } = useHandleRefresh(); + + const field = useField(); + const approval = useApproval(); + const api = useAPIClient(); + + const { workflow } = useFlowContext(); + + return { + async run() { + try { + field.data = field.data ?? {}; + + field.data.loading = true; + + const appendsConfigs = [...workflow.config.appends]; + const summaryConfigs = [...workflow.config.summary]; + const appends = _.intersection(appendsConfigs, summaryConfigs); + + const { data: approvalData } = await api.resource('approvals').get({ + filterByTk: approval.id, + }); + + const { collectionName, data, workflowId } = approvalData.data; + + const newData = _.omit(data, ['id', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy']); + + await api.resource('approvals').reSubmit({ + values: { + collectionName: collectionName, + data: newData, + status: APPROVAL_STATUS.RESUBMIT, + workflowId: workflowId, + collectionAppends: appends, + }, + }); + + field.data.loading = false; + refreshTable(); + } catch (v) { + if (field.data) { + field.data.loading = false; + } + } + }, + }; +} diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/todos/VC.ViewActionTodosContent.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/todos/VC.ViewActionTodosContent.tsx index 797e4ae6b..b1d091032 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/todos/VC.ViewActionTodosContent.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/todos/VC.ViewActionTodosContent.tsx @@ -13,7 +13,7 @@ import _ from 'lodash'; import { DetailsBlockProvider } from '../../../../../components'; import { ExecutionContextProvider } from '../../../../../ExecutionContextProvider'; -import { FormBlockProvider } from '../../../common/Pd.FormBlock'; +import { FormBlockProvider } from '../../../common/FormBlock.provider'; import { NAMESPACE, useTranslation } from '../../../locale'; import { ApprovalContext } from '../../approval-common/ApprovalData.provider'; import { ContextWithActionEnabled } from '../../approval-common/WithActionEnabled.provider'; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/ApprovalsSummary.view.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/ApprovalsSummary.view.tsx index 8f60bf014..1d041dcff 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/ApprovalsSummary.view.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/ApprovalsSummary.view.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { useCollectionManager, useCollectionRecordData, useCompile } from '@tachybase/client'; +import { dayjs } from '@tachybase/utils/client'; import useStyles from './style'; @@ -13,12 +14,19 @@ export const ApprovalsSummary = (props) => { const { collectionName } = record; const results = Object.entries(value).map(([key, objValue]) => { const field = cm.getCollectionField(`${collectionName}.${key}`); + const realValue = Object.prototype.toString.call(objValue) === '[object Object]' ? objValue?.['name'] : objValue; + // 如果是UTC时间字符串, 则转换为本地时区时间 + if (isUTCString(realValue)) { + return { + label: compile(field?.uiSchema?.title || key), + value: convertUTCToLocal(realValue), + }; + } return { label: compile(field?.uiSchema?.title || key), - value: Object.prototype.toString.call(objValue) === '[object Object]' ? objValue?.['name'] : objValue, + value: realValue, }; }); - // 展示结果要展示一个数组对象, 是 label 和 value 的形式 // label 放中文, value 放值 return ( @@ -32,3 +40,19 @@ export const ApprovalsSummary = (props) => { ); }; + +// TODO: 将下边的函数转移至 core 库中 +// 定义正则表达式, 检测形如 2024-07-04T04:46:27.166Z 的UTC时间字符串 +const utcRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/; + +// 测试函数 +function isUTCString(str = '') { + return utcRegex.test(str); +} + +// 将UTC时间字符串转换为本地时区时间 +function convertUTCToLocal(utcString) { + // 使用dayjs解析UTC时间,并转换为本地时区时间 + const localDate = dayjs.utc(utcString).local().format('YYYY-MM-DD HH:mm:ss'); + return localDate; +} diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-record-block/RecordApprovals.decorator.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-record-block/RecordApprovals.decorator.tsx index 5aa6ed50a..bbd962869 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-record-block/RecordApprovals.decorator.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-record-block/RecordApprovals.decorator.tsx @@ -8,7 +8,7 @@ import { useRecord, } from '@tachybase/client'; -import { CollectionApprovalTodos } from '../../common/Cn.ApprovalTodos'; +import { CollectionApprovalTodos } from '../../common/ApprovalTodos.collection'; import { CollectionApprovals } from '../approval-common/Approvals.collection'; import { CollectionFlowNodes } from '../approval-common/FlowNodes.collection'; import { CollectionWorkflows } from '../approval-common/Workflows.collection'; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/locale/en-US.json b/packages/plugins/@tachybase/plugin-workflow/src/locale/en-US.json index 646bcf023..8a33f58d0 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/locale/en-US.json +++ b/packages/plugins/@tachybase/plugin-workflow/src/locale/en-US.json @@ -275,5 +275,6 @@ "Workflow": "Workflow", "\"Content-Type\" only support \"application/json\", and no need to specify": "\"Content-Type\" only support \"application/json\", and no need to specify", "concat": "concat", - "ms": "ms" + "ms": "ms", + "reSubmit": "reSubmit" } diff --git a/packages/plugins/@tachybase/plugin-workflow/src/locale/zh-CN.json b/packages/plugins/@tachybase/plugin-workflow/src/locale/zh-CN.json index 456fa2d62..301175c83 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/locale/zh-CN.json +++ b/packages/plugins/@tachybase/plugin-workflow/src/locale/zh-CN.json @@ -355,5 +355,6 @@ "Workflow": "工作流", "\"Content-Type\" only support \"application/json\", and no need to specify": "\"Content-Type\" 请求头仅支持 \"application/json\",无需填写", "concat": "连接", - "ms": "毫秒" + "ms": "毫秒", + "reSubmit": "重新提交" } diff --git a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/ApprovalTrigger.ts b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/ApprovalTrigger.ts index 509dfd509..d7b1292a5 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/ApprovalTrigger.ts +++ b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/ApprovalTrigger.ts @@ -38,7 +38,9 @@ export default class ApprovalTrigger extends Trigger { }, transaction, }); - if (!workflow || !approval.changed('status') || approval.status !== APPROVAL_STATUS.SUBMITTED) { + const isChangedStatus = approval.changed('status'); + const isAllowStatusList = [APPROVAL_STATUS.SUBMITTED, APPROVAL_STATUS.RESUBMIT].includes(approval.status); + if (!workflow || !isChangedStatus || !isAllowStatusList) { return; } const [dataSourceName, collectionName] = parseCollectionName(approval.collectionName); diff --git a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/actions.ts b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/actions.ts index b54519dcc..5d65b6069 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/actions.ts +++ b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/actions.ts @@ -2,6 +2,7 @@ import actions, { utils } from '@tachybase/actions'; import { parseCollectionName } from '@tachybase/data-source-manager'; import { EXECUTION_STATUS, JOB_STATUS, PluginWorkflow } from '../..'; +import { appends } from '../../../client/schemas/collection'; import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS } from './constants'; import { getSummary } from './tools'; import { getAssociationName, jsonParse } from './utils'; @@ -84,7 +85,7 @@ const approvals = { /** 以下为,处理子表单子表格等关联字段的更新逻辑 */ const schemaOfForm = await context.db.getRepository('uiSchemas').getJsonSchema(schemaFormId); const itemsOfSchema = await jsonParse(`**["x-component-props".mode]`, schemaOfForm); - const fieldAssociationName = itemsOfSchema + const fieldAssociationName = (itemsOfSchema || []) .filter((item) => { return ['Nester', 'SubTable', 'PopoverNester'].includes(item?.['x-component-props']?.mode); }) @@ -113,6 +114,61 @@ const approvals = { }); return actions.update(context, next); }, + + // NOTE: 和 create 逻辑雷同, 但是 因为原本的 create 并非纯操作, 因此拷贝一份以便方便改动 + async reSubmit(context, next) { + const { status, collectionName, data, workflowId, collectionAppends } = context.action.params.values ?? {}; + const [dataSourceName, cName] = parseCollectionName(collectionName); + const dataSource = context.app.dataSourceManager.dataSources.get(dataSourceName); + if (!dataSource) { + return context.throw(400, `Data source "${dataSourceName}" not found`); + } + const collection = dataSource.collectionManager.getCollection(cName); + if (!collection) { + return context.throw(400, `Collection "${cName}" not found`); + } + const workflow = await context.db.getRepository('workflows').findOne({ + filterByTk: workflowId, + }); + if (!workflow?.enabled) { + return context.throw(400, 'Current workflow not found or disabled, please refresh and try again'); + } + const { repository, model } = collection; + const values = await repository.create({ + values: { + ...data, + createdBy: context.state.currentUser.id, + updatedBy: context.state.currentUser.id, + }, + context, + }); + const instance = values.get(); + + // NOTE: 这里需要取出关联字段, 用于摘要的构造; + // 有点奇怪的方式, 但是没想到更好的处理方式, 也许应该改造摘要的构造方式, 存储关联字段的id, 在前端请求具体数据. + const valuesWithAppends = await repository.findOne({ + filterByTk: values.id, + appends: [...collectionAppends], + }); + const summary = getSummary({ + summaryConfig: workflow.config.summary, + data: valuesWithAppends, + }); + Object.keys(model.associations).forEach((key) => { + delete instance[key]; + }); + context.action.mergeParams({ + values: { + collectionName, + data: instance, + dataKey: values[collection.filterTargetKey], + workflowKey: workflow.key, + applicantRoleName: context.state.currentRole, + summary, + }, + }); + return actions.create(context, next); + }, async destroy(context, next) { const { filterByTk, diff --git a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/constants.ts b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/constants.ts index 1012f9516..c999e91e2 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/constants.ts +++ b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/constants.ts @@ -4,6 +4,7 @@ export const APPROVAL_STATUS = { SUBMITTED: 2, PROCESSING: 3, APPROVED: 4, + RESUBMIT: 5, REJECTED: -1, }; export const APPROVAL_ACTION_STATUS = { diff --git a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/tools.ts b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/tools.ts index 4e6df35de..0596a3f42 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/tools.ts +++ b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/tools.ts @@ -10,9 +10,10 @@ export function getSummary(params: ParamsType): object { const result = summaryConfig.reduce((summary, key) => { const value = _.get(data, key); + const realValue = Object.prototype.toString.call(value) === '[object Object]' ? value?.['name'] : value; return { ...summary, - [key]: value, + [key]: realValue, }; }, {});