feat: improve approval (#820)

Co-authored-by: bai.zixv <bai.zixv@foxmail.com>
Reviewed-on: daoyoucloud/tachybase#820
This commit is contained in:
sealday 2024-04-24 11:58:14 +08:00
parent a30a214ac0
commit e9c4ade676
20 changed files with 60 additions and 161 deletions

View File

@ -4,7 +4,7 @@ import { APPROVAL_ACTION_STATUS } from '../../../constants';
import { ApprovalActionConfigComponent } from './VC.ApprovalActionConfig';
export const ApproverActionConfigInitializer = new SchemaInitializer({
name: 'ApprovalProcessAddActionButton',
name: 'ApproverActionConfigInitializer',
title: '{{t("Configure actions")}}',
items: [
{

View File

@ -10,7 +10,7 @@ import { ApproverAddBlockComponent } from './VC.ApproverAddBlock';
import { ApproverAddBlockKit } from './VC.ApproverAddBlockKit';
export const ApproverAddBlockInitializer = new SchemaInitializer({
name: 'ApprovalProcessAddBlockButton',
name: 'ApproverAddBlockInitializer',
wrap: gridRowColWrap,
title: "{{t('Add block')}}",
items: [

View File

@ -9,7 +9,7 @@ import { flatSchemaArray } from '../../../constants';
export const ApproverAddBlockKit = () => {
const itemConfig = useSchemaInitializerItem();
const formSchema = createFormBlockSchema({
actionInitializers: 'ApprovalProcessAddActionButton',
actionInitializers: 'ApproverActionConfigInitializer',
actions: {
approve: {
type: 'void',

View File

@ -54,7 +54,7 @@ export const ApproverBlock = ({ value: srcID, onChange }) => {
name: id,
'x-uid': id,
'x-component': 'Grid',
'x-initializer': 'ApprovalProcessAddBlockButton',
'x-initializer': 'ApproverAddBlockInitializer',
properties: {},
};

View File

@ -10,11 +10,8 @@ export default class PluginKitApprovalTrigger extends Plugin {
async load() {
const workflowPlugin = this.app.pm.get(PluginWorkflow);
workflowPlugin.registerTrigger('approval', ApprovalTrigger);
// workflowPlugin.registerInstruction('approval', ApprovalInstruction);
this.app.schemaInitializerManager.add(LauncherActionConfigInitializer);
this.app.schemaInitializerManager.add(LauncherAddBlockButtonIntializer);
// this.app.schemaInitializerManager.add(ApproverActionConfigInitializer);
// this.app.schemaInitializerManager.add(ApproverAddBlockInitializer);
}
}

View File

@ -3,7 +3,6 @@ import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem }
import { uid } from '@nocobase/utils/client';
import React from 'react';
import { NAMESPACE } from '../../locale';
import { PathNameMap_ApprovalBlock } from './map';
// 创建区块-审批(发起/待办)
export const ApprovalBlockComponent = () => {
@ -54,7 +53,7 @@ export const ApprovalBlockComponent = () => {
name: id,
'x-uid': id,
'x-component': 'CardItem',
'x-decorator': PathNameMap_ApprovalBlock.Decorator,
'x-decorator': 'ApprovalBlock.Decorator',
'x-decorator-props': {
collection: item.collection,
action: 'listCentralized',

View File

@ -1,5 +1,3 @@
// import { PathNameMap_ApprovalBlock } from '../map';
import { ApprovalBlock } from '../map';
import { NAMESPACE } from '../../../locale';
import { css } from '@nocobase/client';
@ -66,7 +64,6 @@ export const SchemaApprovalBlockLaunch = {
title: '{{t("Actions")}}',
properties: {
action: {
// 'x-component': PathNameMap_ApprovalBlock.ViewActionLaunch,
'x-component': 'ApprovalBlock.ViewActionLaunch',
},
},

View File

@ -24,7 +24,6 @@ import { ActionBarProvider } from './Pd.ActionBar';
import { WithdrawActionProvider } from './Pd.WithdrawAction';
import { SchemaComponentContextProvider } from '../common/Pd.SchemaComponent';
import { ApplyActionStatusProvider } from './Pd.ApplyActionStatus';
import { ApprovalCommon } from '../../approval-common/map';
import { FlowContextProvider } from '../common/Pd.FlowContext';
export const ViewActionLaunchContent = () => {
@ -136,7 +135,7 @@ export const ViewActionLaunchContent = () => {
process: {
type: 'void',
'x-decorator': 'CardItem',
'x-component': ApprovalCommon.PathNameMap.ViewComponent.ApprovalProcess,
'x-component': 'ApprovalCommon.ViewComponent.ApprovalProcess',
},
},
},

View File

@ -1,31 +0,0 @@
import { ViewActionTodos } from './todos/VC.ViewActionTodos';
import { ApprovalBlockComponent } from './VC.ApprovalBlock';
import { ApprovalBlockTodos } from './todos/VC.ApprovalBlockTodos';
import { ViewActionLaunch } from './launch/VC.ViewActionLaunch';
import { ApprovalBlockDecorator } from './Dt.ApprovalBlock';
import { ApprovalBlockLaunch } from './launch/VC.ApprovalBlockLaunch';
// 区块-审批
export const ApprovalBlock = () => null;
export const PathNameMap_ApprovalBlock = {
Decorator: 'ApprovalBlock.Decorator',
BlockInitializer: 'ApprovalBlock.BlockInitializer',
Launch: 'ApprovalBlock.Launch',
Todos: 'ApprovalBlock.Todos',
ViewActionLaunch: 'ApprovalBlock.ViewActionLaunch',
ViewActionTodos: 'ApprovalBlock.ViewActionTodos',
};
ApprovalBlock.Decorator = ApprovalBlockDecorator;
ApprovalBlock.BlockInitializer = ApprovalBlockComponent;
ApprovalBlock.Launch = ApprovalBlockLaunch;
ApprovalBlock.Todos = ApprovalBlockTodos;
ApprovalBlock.ViewActionLaunch = ViewActionLaunch;
ApprovalBlock.ViewActionTodos = ViewActionTodos;

View File

@ -5,7 +5,6 @@ import {
FormBlockContext,
FormV2,
RecordProvider,
SchemaComponent,
useAPIClient,
useAssociationNames,
useCurrentUserContext,
@ -23,36 +22,40 @@ export function ApprovalFormBlockDecorator(props) {
const omitApproval = _.omit(approvalExecutions, ['approval', 'job', 'node', 'snapshot']);
const { execution, workflow } = useFlowContext();
const fieldSchema = useFieldSchema();
const field = useField();
const ref = useRef(null);
const formBlockRef = useRef(null);
const { getAssociationAppends } = useAssociationNames();
const { appends, updateAssociationValues } = getAssociationAppends();
const { data } = useCurrentUserContext();
const { findComponent } = useDesignable();
const component = findComponent(field.component?.[0]) || Fragment;
const ContainerFormComp = findComponent(field.component?.[0]) || Fragment;
const form = useMemo(() => {
return createForm({
initialValues: omitApproval,
pattern:
!workflow.enabled || execution.status || job.status || omitApproval.status == null
!workflow?.enabled || execution?.status || job?.status || omitApproval?.status == null
? 'disabled'
: omitApproval.status || data.data?.id !== omitApproval.userId
? 'readPretty'
: 'editable',
});
}, [data.data?.id, omitApproval.status, workflow.enabled]);
}, [data.data?.id, omitApproval?.status, workflow?.enabled]);
const params = useMemo(() => ({ appends: appends, ...props.params }), [appends, props.params]);
const result = useMemo(() => ({ loading: false, data: { data: omitApproval } }), [omitApproval]);
const collectionApi = useAPIClient().resource(props.collection);
const blockRequestContext = useContext(BlockRequestContext_deprecated);
const request = useMemo(
const formValue = useMemo(
() => ({
params: params,
form: form,
field: field,
service: result,
updateAssociationValues: updateAssociationValues,
formBlockRef: ref,
formBlockRef: formBlockRef,
}),
[field, form, params, result, updateAssociationValues],
);
@ -76,13 +79,13 @@ export function ApprovalFormBlockDecorator(props) {
__parent: blockRequestContext,
}}
>
<FormBlockContext.Provider value={request}>
<SchemaComponent component={component} {...field.componentProps}>
<FormBlockContext.Provider value={formValue}>
<ContainerFormComp {...field.componentProps}>
<FormV2.Templates key={1} style={{ marginBottom: 18 }} form={form} />
<div key={2} ref={ref}>
<div key={2} ref={formBlockRef}>
<RecursionField schema={fieldSchema} onlyRenderProperties={true} />
</div>
</SchemaComponent>
</ContainerFormComp>
</FormBlockContext.Provider>
</BlockRequestContext_deprecated.Provider>
</FormActiveFieldsProvider>

View File

@ -13,11 +13,11 @@ export function useContextApprovalAction() {
}
export function ApprovalActionProvider({ children, ...props }) {
const context = useContextApprovalExecutions();
const { status } = useContextApprovalExecutions();
if (context && context.status !== props.status) {
return null;
if (!status || status === props.status) {
return <ContextApprovalAction.Provider value={props}>{children}</ContextApprovalAction.Provider>;
}
return <ContextApprovalAction.Provider value={props}>{children}</ContextApprovalAction.Provider>;
return null;
}

View File

@ -1,4 +1,3 @@
// @ts-nocheck
import {
RemoteSchemaComponent,
SchemaComponent,
@ -11,26 +10,26 @@ import { DetailsBlockProvider, ExecutionContextProvider } from '@nocobase/plugin
import { Result, Spin } from 'antd';
import _ from 'lodash';
import React, { useContext } from 'react';
import { FormBlockProvider } from '../../../common/Pd.FormBlock';
import { NAMESPACE, useTranslation } from '../../../locale';
import { ApprovalContext } from '../../approval-common/Pd.ApprovalData';
import { ContextWithActionEnabled } from '../../approval-common/Pd.WithActionEnabled';
import { ContextApprovalExecution } from '../common/Pd.ApprovalExecution';
import { ContextApprovalExecutions } from './Pd.ApprovalExecutions';
import { NAMESPACE, useTranslation } from '../../../locale';
import { FormBlockProvider } from '../../../common/Pd.FormBlock';
import { ApprovalContext } from '../../approval-common/Pd.ApprovalData';
import { ApprovalCommon } from '../../approval-common/map';
import { SchemaComponentContextProvider } from '../common/Pd.SchemaComponent';
import { useApprovalDetailBlockProps } from './hooks/useApprovalDetailBlockProps';
import { useApprovalFormBlockProps } from './hooks/useApprovalFormBlockProps';
import { useSubmit } from './hooks/useSubmit';
import { ApprovalFormBlockDecorator } from './Dt.ApprovalFormBlock';
import { ActionBarProvider } from './Pd.ActionBarProvider';
import { ApprovalActionProvider } from './Pd.ApprovalAction';
import { ContextApprovalExecutions } from './Pd.ApprovalExecutions';
import { useApprovalDetailBlockProps } from './hooks/useApprovalDetailBlockProps';
import { useApprovalFormBlockProps } from './hooks/useApprovalFormBlockProps';
import { useSubmit } from './hooks/useSubmit';
// 审批-待办-查看: 内容
export const ViewActionTodosContent = () => {
const { id } = useRecord();
const { t } = useTranslation();
const { actionEnabled } = useContext(ContextWithActionEnabled);
const { loading, data } = useRequest(
const { loading, data: data }: any = useRequest(
{
resource: 'approvalRecords',
action: 'get',
@ -68,15 +67,19 @@ export const ViewActionTodosContent = () => {
},
{ refreshDeps: [id] },
);
if (loading) return <Spin />;
if (!(data != null && data.data))
if (data == null || !data.data) {
return <Result status="error" title={t('Submission may be withdrawn, please try refresh the list.')} />;
}
const items = data.data;
const { approvalExecution, node, approval, workflow } = items;
const { approvalExecution, node, approval, workflow, execution } = items;
const { nodes } = workflow;
const omitWorkflow = _.omit(workflow, ['nodes']);
const { execution } = items;
// return null;
node?.config.applyDetail;
return (
<ExecutionContextProvider workflow={omitWorkflow} nodes={nodes} execution={execution}>
<ApprovalContext.Provider value={approval}>
@ -84,9 +87,9 @@ export const ViewActionTodosContent = () => {
<ContextApprovalExecutions.Provider value={data.data}>
<SchemaComponent
components={{
SchemaComponentProvider: SchemaComponentProvider,
RemoteSchemaComponent: RemoteSchemaComponent,
SchemaComponentContextProvider: SchemaComponentContextProvider,
SchemaComponentProvider,
RemoteSchemaComponent,
SchemaComponentContextProvider,
FormBlockProvider,
ActionBarProvider,
ApprovalActionProvider,
@ -113,7 +116,9 @@ export const ViewActionTodosContent = () => {
detail: {
type: 'void',
'x-decorator': 'SchemaComponentContextProvider',
'x-decorator-props': { designable: false },
'x-decorator-props': {
designable: false,
},
'x-component': 'RemoteSchemaComponent',
'x-component-props': {
uid: node?.config.applyDetail,
@ -134,7 +139,7 @@ export const ViewActionTodosContent = () => {
history: {
type: 'void',
'x-decorator': 'CardItem',
'x-component': ApprovalCommon.ViewComponent.ApprovalProcess,
'x-component': 'ApprovalCommon.ViewComponent.ApprovalProcess',
},
},
},

View File

@ -1,12 +1,15 @@
import { Plugin } from '@nocobase/client';
import { ApprovalCommon } from './map';
import { ApprovalDataProvider } from './Pd.ApprovalData';
import { ApprovalProcess } from './VC.ApprovalProcess';
export default class PluginKitApprovalCommon extends Plugin {
async afterAdd() {}
async beforeLoad() {}
async load() {
this.app.addComponents({
ApprovalCommon,
// ApprovalCommon,
'ApprovalCommon.Provider.ApprovalDataProvider': ApprovalDataProvider,
'ApprovalCommon.ViewComponent.ApprovalProcess': ApprovalProcess,
});
}
}

View File

@ -1,26 +0,0 @@
import { ApprovalDataProvider } from './Pd.ApprovalData';
import { ApprovalProcess } from './VC.ApprovalProcess';
// 通用,审批
export const ApprovalCommon = () => null;
ApprovalCommon.PathNameMap = {
Provider: {
ApprovalDataProvider: 'ApprovalCommon.Provider.ApprovalDataProvider',
},
ViewComponent: {
ApprovalProcess: 'ApprovalCommon.ViewComponent.ApprovalProcess',
},
};
ApprovalCommon.Decorator = null;
ApprovalCommon.Provider = {
ApprovalDataProvider,
};
ApprovalCommon.BlockInitializer = null;
ApprovalCommon.ViewComponent = {
ApprovalProcess,
};

View File

@ -2,7 +2,6 @@ import { AuditOutlined } from '@ant-design/icons';
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '@nocobase/client';
import { uid } from '@nocobase/utils/client';
import React from 'react';
import { ApprovalRecordBlock } from './map';
// 初始化器,创建区块-相关审批
export function RecordApprovalsInitializer() {
@ -18,13 +17,13 @@ export function RecordApprovalsInitializer() {
type: 'void',
name: id,
'x-uid': id,
'x-decorator': ApprovalRecordBlock.PathNameMap.Decorator,
'x-decorator': 'ApprovalRecordBlock.Decorator',
'x-component': 'CardItem',
'x-designer': 'List.Designer',
properties: {
block: {
type: 'void',
'x-component': ApprovalRecordBlock.PathNameMap.ViewComponent,
'x-component': 'ApprovalRecordBlock.ViewComponent',
},
},
});

View File

@ -1,5 +1,4 @@
import { NAMESPACE } from '../../locale';
import { ApprovalCommon } from '../approval-common/map';
export const SchemaRecordApprovals = {
type: 'void',
@ -86,9 +85,8 @@ export const SchemaRecordApprovals = {
},
processRow: {
type: 'void',
// 'x-decorator': 'ApprovalBlock.ApprovalDataProvider',
'x-decorator': ApprovalCommon.PathNameMap.Provider.ApprovalDataProvider,
'x-component': ApprovalCommon.PathNameMap.ViewComponent.ApprovalProcess,
'x-decorator': 'ApprovalCommon.Provider.ApprovalDataProvider',
'x-component': 'ApprovalCommon.ViewComponent.ApprovalProcess',
'x-component-props': {
actionEnabled: true,
},

View File

@ -1,44 +0,0 @@
import { RecordApprovalsDecorator } from './Dt.RecordApprovals';
import { RecordApprovalsInitializer } from './Iz.RecordApprovals';
import { RecordApprovals } from './VC.RecordApprovals';
// 区块-相关审批
export const ApprovalRecordBlock = () => null;
// Think: 这里其实可以从框架层面定义, 现在是取名字,
// 可以改为, name和component的对象.让开发体验更友好.
// 目前只是适应框架现在的定义,这样处理
// 名称映射,声明而不是生成,提供ts较好的路径提示信息,便于修改,以及避免遍历计算带来的性能损耗
ApprovalRecordBlock.PathNameMap = {
Decorator: 'ApprovalRecordBlock.Decorator',
BlockInitializer: 'ApprovalRecordBlock.BlockInitializer',
ViewComponent: 'ApprovalRecordBlock.ViewComponent',
};
ApprovalRecordBlock.Decorator = RecordApprovalsDecorator;
ApprovalRecordBlock.BlockInitializer = RecordApprovalsInitializer;
ApprovalRecordBlock.ViewComponent = RecordApprovals;
// ApprovalRecordBlock.PathNameMap = getPathNameMap(ApprovalRecordBlock);
// 改为如下形式, 需要改addComponent的机制, 以及加载组件的机制
// 以下代码为 demo
// export const ApprovalRecordBlock1 = {
// Decorator: {
// name: 'ApprovalRecordBlock.Decorator',
// component: RecordApprovalsDecorator,
// },
// Provider: {
// name: '',
// component: null,
// },
// BlockInitializer: {
// name: 'ApprovalRecordBlock.BlockInitializer',
// component: RecordApprovalsInitializer,
// },
// ViewComponent: {
// name: 'ApprovalRecordBlock.ViewComponent',
// component: RecordApprovals,
// },
// };

View File

@ -2,7 +2,7 @@ import { defineCollection } from '@nocobase/database';
export default defineCollection({
namespace: 'workflow.approvalExecutions',
duplicator: 'required',
dumpRules: 'required',
name: 'approvalExecutions',
fields: [
{

View File

@ -1,7 +1,7 @@
import { defineCollection } from '@nocobase/database';
export default defineCollection({
namespace: 'workflow.approvalRecords',
duplicator: 'required',
dumpRules: 'required',
name: 'approvalRecords',
fields: [
{

View File

@ -1,7 +1,7 @@
import { defineCollection } from '@nocobase/database';
export default defineCollection({
namespace: 'workflow.approvals',
duplicator: 'required',
dumpRules: 'required',
name: 'approvals',
createdBy: true,
updatedBy: true,