From 220bf172fcb8ea16766fdba84c44a18c9cbb3132 Mon Sep 17 00:00:00 2001 From: "bai.zixv" Date: Thu, 18 Jul 2024 17:18:13 +0800 Subject: [PATCH] fix: approval, show process & feat: approval, lastNode (#1343) Reviewed-on: https://git.daoyoucloud.com/daoyoucloud/tachybase/pulls/1343 Co-authored-by: bai.zixv Co-committed-by: bai.zixv --- .../approvalRecords.collection.tsx | 5 +- .../approval-block/ApprovalBlock.schema.tsx | 9 +- .../launch/Sm.ApprovalBlockLaunch.tsx | 15 +++ .../launch/VC.ViewActionLaunchContent.tsx | 2 +- .../approval-common/ApprovalProcess.view.tsx | 107 +++--------------- .../approval-columns/lastNode.column.tsx | 24 ++++ .../summary.column.tsx} | 2 +- .../approval/usage/approval-common/plugin.ts | 6 +- .../process-columns/{columns.ts => index.ts} | 1 + .../process-columns/render.taskNode.tsx | 1 - .../approval/usage/approval-common/tools.ts | 73 ++++++++++++ .../ApprovalCarbonCopy.instruction.ts | 43 +++---- .../src/server/features/approval/actions.ts | 1 + 13 files changed, 172 insertions(+), 117 deletions(-) create mode 100644 packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/approval-columns/lastNode.column.tsx rename packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/{ApprovalsSummary.view.tsx => approval-columns/summary.column.tsx} (98%) rename packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/{columns.ts => index.ts} (98%) create mode 100644 packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/tools.ts diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/collections/approvalRecords.collection.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/collections/approvalRecords.collection.tsx index f37ef5171..59b398b93 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/collections/approvalRecords.collection.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/collections/approvalRecords.collection.tsx @@ -60,7 +60,10 @@ export const CollectionApprovalTodos = { type: 'number', title: `{{t("Task node", { ns: "${NAMESPACE}" })}}`, 'x-component': 'RemoteSelect', - 'x-component-props': { fieldNames: { label: 'title', value: 'id' }, service: { resource: 'flow_nodes' } }, + 'x-component-props': { + fieldNames: { label: 'title', value: 'id' }, + service: { resource: 'flow_nodes' }, + }, }, }, { diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/ApprovalBlock.schema.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/ApprovalBlock.schema.tsx index 5b5b224bc..2a2000b17 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/ApprovalBlock.schema.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/ApprovalBlock.schema.tsx @@ -45,7 +45,14 @@ const schemaItems = [ 'x-component': 'ApprovalBlock.Launch', collection: 'approvals', params: { - appends: ['createdBy.nickname', 'workflow.title', 'workflow.enabled'], + appends: [ + 'createdBy.nickname', + 'workflow.title', + 'workflow.enabled', + 'records.id', + 'records.status', + 'records.node.title', + ], except: ['data'], }, }, diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Sm.ApprovalBlockLaunch.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Sm.ApprovalBlockLaunch.tsx index c83a5e9f3..41673d6f5 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Sm.ApprovalBlockLaunch.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-block/launch/Sm.ApprovalBlockLaunch.tsx @@ -156,6 +156,21 @@ export const SchemaApprovalBlockLaunch = { }, }, }, + lastNode: { + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-component': 'TableV2.Column', + 'x-component-props': { + width: 200, + }, + title: `{{t("Task node", { ns: "${NAMESPACE}" })}}`, + properties: { + lastNode: { + 'x-component': 'ApprovalLastNodeColumn', + 'x-read-pretty': true, + }, + }, + }, }, }, }, 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 621436488..7e1fa8efe 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 @@ -63,7 +63,7 @@ export const ViewActionLaunchContent = () => { // @ts-ignore const approvalData = data?.data; - const needHideProcess = actionEnabled || approvalData?.status !== APPROVAL_STATUS.RESUBMIT; + const needHideProcess = actionEnabled; if (loading) { return ; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/ApprovalProcess.view.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/ApprovalProcess.view.tsx index 03227afbe..3c39db1a2 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/ApprovalProcess.view.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/ApprovalProcess.view.tsx @@ -4,13 +4,27 @@ import { createStyles, useCurrentUserContext } from '@tachybase/client'; import { Space, Table } from 'antd'; import _ from 'lodash'; -import { EXECUTION_STATUS } from '../../../../constants'; -import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS } from '../../constants'; -import { lang, usePluginTranslation } from '../../locale'; +import { usePluginTranslation } from '../../locale'; import { useApproval } from './ApprovalData.provider'; -import { getAntdTableColumns } from './process-columns/columns'; +import { getAntdTableColumns } from './process-columns'; +import { getResults } from './tools'; import { ContextWithActionEnabled } from './WithActionEnabled.provider'; +const getStyles = createStyles(({ css, token }) => ({ + layout: css` + display: flex; + `, + columnDetail: css` + .ant-description-textarea { + margin-bottom: 0.5em; + } + time { + display: block; + color: ${token.colorTextTertiary}; + } + `, +})); + // 审批(发起/待办)区块-查看-审批处理 export const ApprovalProcess = (props) => { const { t } = usePluginTranslation(); @@ -32,88 +46,3 @@ export const ApprovalProcess = (props) => { ); }; - -const getStyles = createStyles(({ css, token }) => ({ - layout: css` - display: flex; - `, - columnDetail: css` - .ant-description-textarea { - margin-bottom: 0.5em; - } - time { - display: block; - color: ${token.colorTextTertiary}; - } - `, -})); - -function getResults({ approval, currentUser }) { - const { workflow, approvalExecutions, records } = approval; - - approvalExecutions.sort((a, b) => Date.parse(a.createdAt) - Date.parse(b.createdAt)); - - const approvalExecution = approvalExecutions.reduce( - (newObj, curr) => - Object.assign(newObj, { - [curr.id]: Object.assign(curr, { - records: [ - { - groupCount: 1, - node: { - title: lang('Apply'), - }, - user: { - ...approval.createdBy, - id: approval.createdById, - }, - status: curr.status ? APPROVAL_STATUS.SUBMITTED : approval.status, - updatedAt: curr.createdAt, - execution: { ...curr }, - }, - ], - }), - }), - {}, - ); - records - .sort((prevRecord, nextRecord) => { - const prev = new Date(prevRecord.job?.createdAt); - const next = new Date(nextRecord.job?.createdAt); - return prev < next ? -1 : prev > next ? 1 : prevRecord.id - nextRecord.id; - }) - .forEach((record) => { - const approvalExecutionId = approvalExecution[record.approvalExecutionId]; - const omitApprovalExecutionId = _.omit(approvalExecutionId, ['records']); - (record.workflow = workflow), - (record.execution = { ...omitApprovalExecutionId }), - approvalExecutionId.records.push(record), - approvalExecutionId.jobs || (approvalExecutionId.jobs = {}), - approvalExecutionId.jobs[record.jobId] - ? (approvalExecutionId.jobs[record.jobId].first.groupCount += 1) - : ((approvalExecutionId.jobs[record.jobId] = { first: record }), - (record.groupCount = 1), - (record.statusCount = { [APPROVAL_ACTION_STATUS.APPROVED]: 0, [APPROVAL_ACTION_STATUS.REJECTED]: 0 })), - [APPROVAL_ACTION_STATUS.APPROVED, APPROVAL_ACTION_STATUS.REJECTED].includes(record.status) && - (approvalExecutionId.jobs[record.jobId].first.statusCount[record.status] += 1); - }), - approval.createdById === (currentUser == null ? void 0 : currentUser.data.id) && - approvalExecutions.forEach((approvalExecution) => { - approvalExecution.status === EXECUTION_STATUS.CANCELED && - approvalExecution.records.length === 1 && - ((approvalExecution.records[0].groupCount = 2), - approvalExecution.records.push({ - user: { nickname: approval.createdBy.nickname }, - status: APPROVAL_ACTION_STATUS.WITHDRAWN, - updatedAt: approvalExecution.updatedAt, - })); - }); - const aELength = approvalExecutions.length; - - return approvalExecutions.filter( - (approvalExecution, index) => - (aELength - 1 === index && - (!approvalExecution.status || approvalExecution.status === EXECUTION_STATUS.CANCELED)) || - approvalExecution.records.length > 1, - ); -} diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/approval-columns/lastNode.column.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/approval-columns/lastNode.column.tsx new file mode 100644 index 000000000..29f6ef851 --- /dev/null +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/approval-columns/lastNode.column.tsx @@ -0,0 +1,24 @@ +import React, { useMemo } from 'react'; +import { useCollectionRecordData } from '@tachybase/client'; + +import { APPROVAL_ACTION_STATUS } from '../../../constants'; + +export const ApprovalLastNodeColumn = () => { + const approvalContext = useCollectionRecordData(); + + const lastNodeTitle = useMemo(() => getLastNodeTitle(approvalContext), [approvalContext]); + + return
{lastNodeTitle}
; +}; + +function getLastNodeTitle(approvalContext) { + const { records } = approvalContext; + let targetRecord = records.find(({ status }) => status !== APPROVAL_ACTION_STATUS.APPROVED); + if (!targetRecord) { + targetRecord = records.pop() || {}; + } + + const lastNodeTitle = targetRecord.node?.title; + + return lastNodeTitle; +} 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/approval-columns/summary.column.tsx similarity index 98% rename from packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/ApprovalsSummary.view.tsx rename to packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/approval-columns/summary.column.tsx index 1d041dcff..bbe68a037 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/approval-columns/summary.column.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useCollectionManager, useCollectionRecordData, useCompile } from '@tachybase/client'; import { dayjs } from '@tachybase/utils/client'; -import useStyles from './style'; +import useStyles from '../style'; export const ApprovalsSummary = (props) => { const { value = '' } = props; diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/plugin.ts b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/plugin.ts index 64db48512..9a960540c 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/plugin.ts +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/plugin.ts @@ -1,17 +1,17 @@ import { Plugin } from '@tachybase/client'; +import { ApprovalLastNodeColumn } from './approval-columns/lastNode.column'; +import { ApprovalsSummary } from './approval-columns/summary.column'; import { ApprovalDataProvider } from './ApprovalData.provider'; import { ApprovalProcess } from './ApprovalProcess.view'; -import { ApprovalsSummary } from './ApprovalsSummary.view'; export class KitApprovalCommon extends Plugin { async load() { this.app.addComponents({ - // ApprovalCommon, - 'ApprovalCommon.Provider.ApprovalDataProvider': ApprovalDataProvider, 'ApprovalCommon.ViewComponent.ApprovalProcess': ApprovalProcess, ApprovalsSummary: ApprovalsSummary, + ApprovalLastNodeColumn: ApprovalLastNodeColumn, }); } } diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/columns.ts b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/index.ts similarity index 98% rename from packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/columns.ts rename to packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/index.ts index b9a411ea7..c1bd0d54a 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/columns.ts +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/index.ts @@ -14,6 +14,7 @@ export const getAntdTableColumns = ({ t, styles }) => { }; }, render: renderColumnTaskNode, + width: 120, }, { title: t('User'), diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/render.taskNode.tsx b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/render.taskNode.tsx index cc08c8d4a..e12ae7247 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/render.taskNode.tsx +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/process-columns/render.taskNode.tsx @@ -28,7 +28,6 @@ export function renderColumnTaskNode(text, { node, job, groupCount, statusCount display: flex; align-items: center; gap: 0.5em; - .ant-tag { margin-right: 0; } diff --git a/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/tools.ts b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/tools.ts new file mode 100644 index 000000000..528f28a71 --- /dev/null +++ b/packages/plugins/@tachybase/plugin-workflow/src/client/features/approval/usage/approval-common/tools.ts @@ -0,0 +1,73 @@ +import _ from 'lodash'; + +import { EXECUTION_STATUS } from '../../../../constants'; +import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS } from '../../constants'; +import { lang } from '../../locale'; + +export function getResults({ approval, currentUser }) { + const { workflow, approvalExecutions, records } = approval; + approvalExecutions.sort((a, b) => Date.parse(a.createdAt) - Date.parse(b.createdAt)); + + const approvalExecution = approvalExecutions.reduce( + (newObj, curr) => + Object.assign(newObj, { + [curr.id]: Object.assign(curr, { + records: [ + { + groupCount: 1, + node: { + title: lang('Apply'), + }, + user: { + ...approval.createdBy, + id: approval.createdById, + }, + status: curr.status ? APPROVAL_STATUS.SUBMITTED : approval.status, + updatedAt: curr.createdAt, + execution: { ...curr }, + }, + ], + }), + }), + {}, + ); + records + .sort((prevRecord, nextRecord) => { + const prev = new Date(prevRecord.job?.createdAt); + const next = new Date(nextRecord.job?.createdAt); + return prev < next ? -1 : prev > next ? 1 : prevRecord.id - nextRecord.id; + }) + .forEach((record) => { + const approvalExecutionId = approvalExecution[record.approvalExecutionId]; + const omitApprovalExecutionId = _.omit(approvalExecutionId, ['records']); + (record.workflow = workflow), + (record.execution = { ...omitApprovalExecutionId }), + approvalExecutionId.records.push(record), + approvalExecutionId.jobs || (approvalExecutionId.jobs = {}), + approvalExecutionId.jobs[record.jobId] + ? (approvalExecutionId.jobs[record.jobId].first.groupCount += 1) + : ((approvalExecutionId.jobs[record.jobId] = { first: record }), + (record.groupCount = 1), + (record.statusCount = { [APPROVAL_ACTION_STATUS.APPROVED]: 0, [APPROVAL_ACTION_STATUS.REJECTED]: 0 })), + [APPROVAL_ACTION_STATUS.APPROVED, APPROVAL_ACTION_STATUS.REJECTED].includes(record.status) && + (approvalExecutionId.jobs[record.jobId].first.statusCount[record.status] += 1); + }), + approval.createdById === (currentUser == null ? void 0 : currentUser.data.id) && + approvalExecutions.forEach((approvalExecution) => { + approvalExecution.status === EXECUTION_STATUS.CANCELED && + approvalExecution.records.length === 1 && + ((approvalExecution.records[0].groupCount = 2), + approvalExecution.records.push({ + user: { nickname: approval.createdBy.nickname }, + status: APPROVAL_ACTION_STATUS.WITHDRAWN, + updatedAt: approvalExecution.updatedAt, + })); + }); + const aELength = approvalExecutions.length; + return approvalExecutions.filter( + (approvalExecution, index) => + (aELength - 1 === index && + (!approvalExecution.status || approvalExecution.status === EXECUTION_STATUS.CANCELED)) || + approvalExecution.records.length > 1, + ); +} diff --git a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/ApprovalCarbonCopy.instruction.ts b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/ApprovalCarbonCopy.instruction.ts index 37e12cb51..9995c144e 100644 --- a/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/ApprovalCarbonCopy.instruction.ts +++ b/packages/plugins/@tachybase/plugin-workflow/src/server/features/approval/ApprovalCarbonCopy.instruction.ts @@ -3,6 +3,7 @@ import { UiSchemaRepository } from '@tachybase/plugin-ui-schema-storage'; import { JOB_STATUS } from '../../constants'; import Instruction from '../../instructions'; import { COLLECTION_NAME_APPROVAL_CARBON_COPY } from '../common/constants'; +import { APPROVAL_STATUS } from './constants'; import { parsePerson } from './tools'; export default class ApprovalCarbonCopyInstruction extends Instruction { @@ -25,27 +26,29 @@ export default class ApprovalCarbonCopyInstruction extends Instruction { appends: ['approvalExecutions', 'createdBy'], except: ['data'], }); - const CarbonCopyModel = db.getModel(COLLECTION_NAME_APPROVAL_CARBON_COPY); - const notifiedPersonDataMap = targetPersonList.map((userId, index) => ({ - userId, - jobId: job.id, - nodeId: node.id, - executionId: job.executionId, - workflowId: node.workflowId, - index, - // TODO: 怎么做到状态实时更新, 观察下审批发起的表的状态是怎么做的... - createdById: approval.createdBy?.id, - approvalId: approval.id, - status: approval.status, - snapshot: approval.data, - summary: approval.summary, - collectionName: approval.collectionName, - dataKey: approval.dataKey, - })); + // NOTE: 只有新发起审批的时候, 才生成抄送副本. 否则, 会生成不必要的重复副本 + if ([APPROVAL_STATUS.SUBMITTED].includes(approval.status)) { + const CarbonCopyModel = db.getModel(COLLECTION_NAME_APPROVAL_CARBON_COPY); + const notifiedPersonDataMap = targetPersonList.map((userId, index) => ({ + userId, + jobId: job.id, + nodeId: node.id, + executionId: job.executionId, + workflowId: node.workflowId, + index, + createdById: approval.createdBy?.id, + approvalId: approval.id, + status: approval.status, + snapshot: approval.data, + summary: approval.summary, + collectionName: approval.collectionName, + dataKey: approval.dataKey, + })); - await CarbonCopyModel.bulkCreate(notifiedPersonDataMap, { - transaction: processor.transaction, - }); + await CarbonCopyModel.bulkCreate(notifiedPersonDataMap, { + transaction: processor.transaction, + }); + } } return job; 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 99b1b4442..62eddc575 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 @@ -370,6 +370,7 @@ const approvalCarbonCopy = { context.action.mergeParams({ filter: { workflowId: centralizedApprovalFlow.map((item) => item.id), + // approval.status: APPROVAL_STATUS.DRAFT, }, }); return actions.list(context, next);