feat/approval-summary (#1015)
Reviewed-on: daoyoucloud/tachybase#1015 Co-authored-by: bai.zixv <bai.zixv@foxmail.com> Co-committed-by: bai.zixv <bai.zixv@foxmail.com>
This commit is contained in:
parent
b338c51923
commit
cfa95bfe1e
@ -17,6 +17,7 @@ export type AppendsTreeSelectProps = {
|
|||||||
multiple?: boolean;
|
multiple?: boolean;
|
||||||
filter?(field): boolean;
|
filter?(field): boolean;
|
||||||
collection?: string;
|
collection?: string;
|
||||||
|
needLeaf?: boolean;
|
||||||
useCollection?(props: Pick<AppendsTreeSelectProps, 'collection'>): string;
|
useCollection?(props: Pick<AppendsTreeSelectProps, 'collection'>): string;
|
||||||
rootOption?: {
|
rootOption?: {
|
||||||
label: string;
|
label: string;
|
||||||
@ -56,9 +57,16 @@ function trueFilter(field) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCollectionFieldOptions(this: CallScope, collection, parentNode?): TreeOptionType[] {
|
function getCollectionFieldOptions(
|
||||||
|
this: CallScope,
|
||||||
|
collection,
|
||||||
|
parentNode?,
|
||||||
|
options = { needLeaf: false },
|
||||||
|
): TreeOptionType[] {
|
||||||
|
const { needLeaf } = options;
|
||||||
const [dataSourceName, collectionName] = parseCollectionName(collection);
|
const [dataSourceName, collectionName] = parseCollectionName(collection);
|
||||||
const fields = this.getCollectionFields(collectionName, dataSourceName).filter(isAssociation);
|
const rawFields = this.getCollectionFields(collectionName, dataSourceName);
|
||||||
|
const fields = needLeaf ? rawFields : rawFields.filter(isAssociation);
|
||||||
const boundLoadChildren = loadChildren.bind(this);
|
const boundLoadChildren = loadChildren.bind(this);
|
||||||
return fields.filter(this.filter).map((field) => {
|
return fields.filter(this.filter).map((field) => {
|
||||||
const key = parentNode ? `${parentNode.value ? `${parentNode.value}.` : ''}${field.name}` : field.name;
|
const key = parentNode ? `${parentNode.value ? `${parentNode.value}.` : ''}${field.name}` : field.name;
|
||||||
@ -88,6 +96,7 @@ export const AppendsTreeSelect: React.FC<TreeSelectProps & AppendsTreeSelectProp
|
|||||||
filter = trueFilter,
|
filter = trueFilter,
|
||||||
rootOption,
|
rootOption,
|
||||||
loadData: propsLoadData,
|
loadData: propsLoadData,
|
||||||
|
needLeaf = false,
|
||||||
...restProps
|
...restProps
|
||||||
} = props;
|
} = props;
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
@ -133,7 +142,9 @@ export const AppendsTreeSelect: React.FC<TreeSelectProps & AppendsTreeSelectProp
|
|||||||
const tData =
|
const tData =
|
||||||
propsLoadData === null
|
propsLoadData === null
|
||||||
? []
|
? []
|
||||||
: getCollectionFieldOptions.call({ compile, getCollectionFields, filter }, collectionString, parentNode);
|
: getCollectionFieldOptions.call({ compile, getCollectionFields, filter }, collectionString, parentNode, {
|
||||||
|
needLeaf,
|
||||||
|
});
|
||||||
|
|
||||||
const map = tData.reduce((result, item) => Object.assign(result, { [item.value]: item }), {});
|
const map = tData.reduce((result, item) => Object.assign(result, { [item.value]: item }), {});
|
||||||
if (parentNode) {
|
if (parentNode) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { approvalStatusOptions } from '../constants';
|
import { approvalStatusOptions } from '../constants';
|
||||||
import { NAMESPACE } from '../locale';
|
import { NAMESPACE, tval } from '../locale';
|
||||||
|
|
||||||
export const CollectionApprovalTodos = {
|
export const CollectionApprovalTodos = {
|
||||||
title: `{{t("Approval todos", { ns: "${NAMESPACE}" })}}`,
|
title: `{{t("Approval todos", { ns: "${NAMESPACE}" })}}`,
|
||||||
@ -9,7 +9,11 @@ export const CollectionApprovalTodos = {
|
|||||||
type: 'bigInt',
|
type: 'bigInt',
|
||||||
name: 'approvalId',
|
name: 'approvalId',
|
||||||
interface: 'number',
|
interface: 'number',
|
||||||
uiSchema: { type: 'number', title: 'ID', 'x-component': 'InputNumber' },
|
uiSchema: {
|
||||||
|
type: 'number',
|
||||||
|
title: 'ID',
|
||||||
|
'x-component': 'InputNumber',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'belongsTo',
|
type: 'belongsTo',
|
||||||
@ -90,5 +94,22 @@ export const CollectionApprovalTodos = {
|
|||||||
'x-component-props': { showTime: true },
|
'x-component-props': { showTime: true },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'summaryString',
|
||||||
|
interface: 'input',
|
||||||
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
title: tval('Summary'),
|
||||||
|
'x-component': 'ApprovalsSummary',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useActionContext } from '@tachybase/client';
|
import { useActionContext } from '@tachybase/client';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SchemaConfigButton } from '../../trigger/VC.ConfigButton';
|
import { ConfigButtonView } from '../../trigger/ConfigButton.view';
|
||||||
import { ContextApproverConfig } from '../Pd.ContextApproverConfig';
|
import { ContextApproverConfig } from '../Pd.ContextApproverConfig';
|
||||||
|
|
||||||
// 审批人操作界面->进入配置按钮
|
// 审批人操作界面->进入配置按钮
|
||||||
@ -8,7 +8,7 @@ export const SchemaConfigButtonApprover = (props) => {
|
|||||||
const { setFormValueChanged } = useActionContext();
|
const { setFormValueChanged } = useActionContext();
|
||||||
return (
|
return (
|
||||||
<ContextApproverConfig.Provider value={{ setFormValueChanged }}>
|
<ContextApproverConfig.Provider value={{ setFormValueChanged }}>
|
||||||
<SchemaConfigButton {...props} />
|
<ConfigButtonView {...props} />
|
||||||
</ContextApproverConfig.Provider>
|
</ContextApproverConfig.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,12 +4,10 @@ import { ApprovalInstruction } from './node.ApprovalInstruction';
|
|||||||
import { ApproverActionConfigInitializer } from './approver-interface/Iz.ApproverActionConfig';
|
import { ApproverActionConfigInitializer } from './approver-interface/Iz.ApproverActionConfig';
|
||||||
import { ApproverAddBlockInitializer } from './approver-interface/Iz.ApproverAddBlock';
|
import { ApproverAddBlockInitializer } from './approver-interface/Iz.ApproverAddBlock';
|
||||||
|
|
||||||
export default class PluginKitApprovalInstruction extends Plugin {
|
export class KitApprovalInstruction extends Plugin {
|
||||||
async afterAdd() {}
|
|
||||||
async beforeLoad() {}
|
|
||||||
async load() {
|
async load() {
|
||||||
const workflowPlugin = this.app.pm.get(PluginWorkflow);
|
const pluginWorkflow = this.app.pm.get(PluginWorkflow);
|
||||||
workflowPlugin.registerInstruction('approval', ApprovalInstruction);
|
pluginWorkflow.registerInstruction('approval', ApprovalInstruction);
|
||||||
|
|
||||||
this.app.schemaInitializerManager.add(ApproverActionConfigInitializer);
|
this.app.schemaInitializerManager.add(ApproverActionConfigInitializer);
|
||||||
this.app.schemaInitializerManager.add(ApproverAddBlockInitializer);
|
this.app.schemaInitializerManager.add(ApproverAddBlockInitializer);
|
@ -0,0 +1,10 @@
|
|||||||
|
import { Plugin } from '@tachybase/client';
|
||||||
|
import { KitApprovalInstruction } from './instruction/plugin';
|
||||||
|
import { KitApprovalTrigger } from './trigger/plugin';
|
||||||
|
|
||||||
|
export default class KitApprovalConfiguration extends Plugin {
|
||||||
|
async afterAdd() {
|
||||||
|
this.pm.add(KitApprovalTrigger);
|
||||||
|
this.pm.add(KitApprovalInstruction);
|
||||||
|
}
|
||||||
|
}
|
@ -3,13 +3,14 @@ import {
|
|||||||
CollectionBlockInitializer,
|
CollectionBlockInitializer,
|
||||||
RadioWithTooltip,
|
RadioWithTooltip,
|
||||||
Trigger,
|
Trigger,
|
||||||
|
UseVariableOptions,
|
||||||
getCollectionFieldOptions,
|
getCollectionFieldOptions,
|
||||||
useWorkflowAnyExecuted,
|
useWorkflowAnyExecuted,
|
||||||
} from '@tachybase/plugin-workflow/client';
|
} from '@tachybase/plugin-workflow/client';
|
||||||
import { useForm } from '@tachybase/schema';
|
import { useForm } from '@tachybase/schema';
|
||||||
import { SchemaConfigButton } from './VC.ConfigButton';
|
import { ConfigButtonView } from './ConfigButton.view';
|
||||||
import { NAMESPACE, tval, usePluginTranslation } from '../../locale';
|
import { NAMESPACE, tval, usePluginTranslation } from '../../locale';
|
||||||
import { LauncherInterface } from './launcher-interface/VC.LauncherInterface';
|
import { LauncherInterface } from './launcher-interface/LauncherInterface.schema';
|
||||||
|
|
||||||
// 工作流节点-审批触发器节点
|
// 工作流节点-审批触发器节点
|
||||||
export class ApprovalTrigger extends Trigger {
|
export class ApprovalTrigger extends Trigger {
|
||||||
@ -17,6 +18,13 @@ export class ApprovalTrigger extends Trigger {
|
|||||||
title = `{{t('Approval event', { ns: "${NAMESPACE}" })}}`;
|
title = `{{t('Approval event', { ns: "${NAMESPACE}" })}}`;
|
||||||
description = `{{t("Triggered when an approval request is initiated through an action button or API. Dedicated to the approval process, with exclusive approval node and block for managing documents and tracking processing processes.", { ns: "${NAMESPACE}" })}}`;
|
description = `{{t("Triggered when an approval request is initiated through an action button or API. Dedicated to the approval process, with exclusive approval node and block for managing documents and tracking processing processes.", { ns: "${NAMESPACE}" })}}`;
|
||||||
|
|
||||||
|
scope = { useWorkflowAnyExecuted };
|
||||||
|
|
||||||
|
components = {
|
||||||
|
ConfigButtonView,
|
||||||
|
LauncherInterface,
|
||||||
|
RadioWithTooltip,
|
||||||
|
};
|
||||||
// 触发器配置表
|
// 触发器配置表
|
||||||
fieldset = {
|
fieldset = {
|
||||||
collection: {
|
collection: {
|
||||||
@ -61,7 +69,7 @@ export class ApprovalTrigger extends Trigger {
|
|||||||
title: `{{t("Initiator's interface", { ns: "${NAMESPACE}" })}}`,
|
title: `{{t("Initiator's interface", { ns: "${NAMESPACE}" })}}`,
|
||||||
description: `{{t("For initiating approvals, or viewing and manipulating initiated approvals.", { ns: "${NAMESPACE}" })}}`,
|
description: `{{t("For initiating approvals, or viewing and manipulating initiated approvals.", { ns: "${NAMESPACE}" })}}`,
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'SchemaConfigButton',
|
'x-component': 'ConfigButtonView',
|
||||||
'x-reactions': [
|
'x-reactions': [
|
||||||
{
|
{
|
||||||
dependencies: ['collection'],
|
dependencies: ['collection'],
|
||||||
@ -75,7 +83,7 @@ export class ApprovalTrigger extends Trigger {
|
|||||||
properties: {
|
properties: {
|
||||||
applyForm: {
|
applyForm: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'SchemaInitiatorForm',
|
'x-component': 'LauncherInterface',
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -106,20 +114,39 @@ export class ApprovalTrigger extends Trigger {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
summary: {
|
||||||
|
type: 'array',
|
||||||
|
title: '{{t("Select fields to display in the approval summary", { ns: "workflow" })}}',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
// TODO: 需要更换为能支持同时选择普通字段和关联字段的组件.目前只能选择关联字段.走通业务逻辑为先
|
||||||
|
'x-component': 'AppendsTreeSelect',
|
||||||
|
'x-component-props': {
|
||||||
|
title: 'Preload associations',
|
||||||
|
multiple: true,
|
||||||
|
needLeaf: true,
|
||||||
|
useCollection() {
|
||||||
|
const { values } = useForm();
|
||||||
|
return values?.collection;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-reactions': [
|
||||||
|
{
|
||||||
|
dependencies: ['collection'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
visible: '{{!!$deps[0]}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
scope = { useWorkflowAnyExecuted };
|
isActionTriggerable = (config: any, context: { action: string; direct: any }) => {
|
||||||
components = {
|
|
||||||
SchemaConfigButton,
|
|
||||||
SchemaInitiatorForm: LauncherInterface,
|
|
||||||
RadioWithTooltip,
|
|
||||||
};
|
|
||||||
|
|
||||||
isActionTriggerable = (config, context) => {
|
|
||||||
return ['create', 'update'].includes(context.action) && !context.direct;
|
return ['create', 'update'].includes(context.action) && !context.direct;
|
||||||
};
|
};
|
||||||
|
|
||||||
useVariables(config, options) {
|
useVariables(config: { collection: any; appends: any[]; summary: any[] }, options: UseVariableOptions) {
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
@ -135,17 +162,25 @@ export class ApprovalTrigger extends Trigger {
|
|||||||
uiSchema: { title: t('Trigger data', { ns: 'workflow' }) },
|
uiSchema: { title: t('Trigger data', { ns: 'workflow' }) },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
return getCollectionFieldOptions({
|
|
||||||
|
const configAppends = config.appends?.map((item: any) => `data.${item}`) || [];
|
||||||
|
const collectionFieldOptions = getCollectionFieldOptions({
|
||||||
// depth,
|
// depth,
|
||||||
appends: ['data', ...(config.appends?.map((item) => `data.${item}`) || [])],
|
appends: ['data', ...configAppends],
|
||||||
...options,
|
...options,
|
||||||
fields: rootFields,
|
fields: rootFields,
|
||||||
compile,
|
compile,
|
||||||
getCollectionFields,
|
getCollectionFields,
|
||||||
});
|
});
|
||||||
|
console.log(
|
||||||
|
'%c Line:176 🍷 collectionFieldOptions',
|
||||||
|
'font-size:18px;color:#33a5ff;background:#3f7cff',
|
||||||
|
collectionFieldOptions,
|
||||||
|
);
|
||||||
|
return collectionFieldOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
useInitializers(config): SchemaInitializerItemType | null {
|
useInitializers(config: { collection: any }): SchemaInitializerItemType | null {
|
||||||
if (!config.collection) {
|
if (!config.collection) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ import React, { useState } from 'react';
|
|||||||
import { useTranslation } from '../../locale';
|
import { useTranslation } from '../../locale';
|
||||||
|
|
||||||
// 发起人操作界面->进入配置按钮
|
// 发起人操作界面->进入配置按钮
|
||||||
export function SchemaConfigButton(props) {
|
export const ConfigButtonView = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
return (
|
return (
|
||||||
@ -17,4 +17,4 @@ export function SchemaConfigButton(props) {
|
|||||||
</ActionContextProvider>
|
</ActionContextProvider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
@ -1,7 +1,7 @@
|
|||||||
import { SchemaInitializer } from '@tachybase/client';
|
import { SchemaInitializer } from '@tachybase/client';
|
||||||
import { NAMESPACE } from '../../../locale';
|
import { NAMESPACE } from '../../../locale';
|
||||||
import { APPROVAL_STATUS } from '../../../constants';
|
import { APPROVAL_STATUS } from '../../../constants';
|
||||||
import { LauncherActionConfigComponent } from './VC.LauncherActionConfig';
|
import { LauncherActionConfigComponent } from './LauncherActionConfig.component';
|
||||||
|
|
||||||
// 区块-配置操作
|
// 区块-配置操作
|
||||||
export const LauncherActionConfigInitializer = new SchemaInitializer({
|
export const LauncherActionConfigInitializer = new SchemaInitializer({
|
@ -1,6 +1,6 @@
|
|||||||
import { SchemaInitializer, gridRowColWrap } from '@tachybase/client';
|
import { SchemaInitializer, gridRowColWrap } from '@tachybase/client';
|
||||||
import { NAMESPACE } from '../../../locale';
|
import { NAMESPACE } from '../../../locale';
|
||||||
import { LauncherAddBlockButtonComponent } from './VC.LauncherBlockButton';
|
import { LauncherAddBlockButtonComponent } from './LauncherBlockButton.component';
|
||||||
|
|
||||||
// 创建区块
|
// 创建区块
|
||||||
export const LauncherAddBlockButtonIntializer = new SchemaInitializer({
|
export const LauncherAddBlockButtonIntializer = new SchemaInitializer({
|
@ -1,8 +1,11 @@
|
|||||||
import { css } from '@tachybase/client';
|
import { SchemaComponent, css, parseCollectionName } from '@tachybase/client';
|
||||||
|
import { useForm } from '@tachybase/schema';
|
||||||
|
import React from 'react';
|
||||||
import { NAMESPACE } from '../../../locale';
|
import { NAMESPACE } from '../../../locale';
|
||||||
|
import { SchemaAddBlock } from './SchemaAddBlock.component';
|
||||||
|
|
||||||
// 发起人操作界面
|
// 发起人操作界面
|
||||||
export const getSchemaLauncherInterface = ({ values, dataSource, name }) => ({
|
const getSchemaLauncherInterface = ({ values, dataSource, name }) => ({
|
||||||
name: values.collection,
|
name: values.collection,
|
||||||
type: 'void',
|
type: 'void',
|
||||||
properties: {
|
properties: {
|
||||||
@ -30,4 +33,19 @@ export const getSchemaLauncherInterface = ({ values, dataSource, name }) => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
}); // 触发器-发起人的操作界面
|
||||||
|
|
||||||
|
export const LauncherInterface = () => {
|
||||||
|
const { values } = useForm();
|
||||||
|
const [dataSource, name] = parseCollectionName(values.collection);
|
||||||
|
const schema = getSchemaLauncherInterface({ values, dataSource, name });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SchemaComponent
|
||||||
|
components={{
|
||||||
|
SchemaAddBlock,
|
||||||
|
}}
|
||||||
|
schema={schema}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -1,21 +0,0 @@
|
|||||||
import { SchemaComponent, parseCollectionName } from '@tachybase/client';
|
|
||||||
import { useForm } from '@tachybase/schema';
|
|
||||||
import React from 'react';
|
|
||||||
import { SchemaAddBlock } from './VC.SchemaAddBlock';
|
|
||||||
import { getSchemaLauncherInterface } from './Sm.LauncherInterface';
|
|
||||||
|
|
||||||
// 触发器-发起人的操作界面
|
|
||||||
export const LauncherInterface = () => {
|
|
||||||
const { values } = useForm();
|
|
||||||
const [dataSource, name] = parseCollectionName(values.collection);
|
|
||||||
const schema = getSchemaLauncherInterface({ values, dataSource, name });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SchemaComponent
|
|
||||||
components={{
|
|
||||||
SchemaAddBlock,
|
|
||||||
}}
|
|
||||||
schema={schema}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,15 +1,15 @@
|
|||||||
import { Plugin } from '@tachybase/client';
|
import { Plugin } from '@tachybase/client';
|
||||||
import PluginWorkflow from '@tachybase/plugin-workflow/client';
|
import PluginWorkflow from '@tachybase/plugin-workflow/client';
|
||||||
import { ApprovalTrigger } from './node.ApprovalTrigger';
|
import { ApprovalTrigger } from './Approval.trigger';
|
||||||
import { LauncherActionConfigInitializer } from './launcher-interface/Iz.LauncherActionConfig';
|
import { LauncherActionConfigInitializer } from './launcher-interface/LauncherActionConfig.initializer';
|
||||||
import { LauncherAddBlockButtonIntializer } from './launcher-interface/Iz.LauncherAddBlockButton';
|
import { LauncherAddBlockButtonIntializer } from './launcher-interface/LauncherAddBlockButton.initializer';
|
||||||
|
|
||||||
export class PluginKitApprovalTrigger extends Plugin {
|
export class KitApprovalTrigger extends Plugin {
|
||||||
async afterAdd() {}
|
async afterAdd() {}
|
||||||
async beforeLoad() {}
|
async beforeLoad() {}
|
||||||
async load() {
|
async load() {
|
||||||
const workflowPlugin = this.app.pm.get(PluginWorkflow);
|
const pluginWorkflow = this.app.pm.get(PluginWorkflow);
|
||||||
workflowPlugin.registerTrigger('approval', ApprovalTrigger);
|
pluginWorkflow.registerTrigger('approval', ApprovalTrigger);
|
||||||
|
|
||||||
this.app.schemaInitializerManager.add(LauncherActionConfigInitializer);
|
this.app.schemaInitializerManager.add(LauncherActionConfigInitializer);
|
||||||
this.app.schemaInitializerManager.add(LauncherAddBlockButtonIntializer);
|
this.app.schemaInitializerManager.add(LauncherAddBlockButtonIntializer);
|
@ -1,12 +1,12 @@
|
|||||||
import { Plugin } from '@tachybase/client';
|
import { Plugin } from '@tachybase/client';
|
||||||
|
|
||||||
import { PluginKitApprovalConfiguration } from './configuration';
|
import KitApprovalConfiguration from './configuration/plugin';
|
||||||
import { PluginKitApprovalUsage } from './usage';
|
import { KitApprovalUsage } from './usage/plugin';
|
||||||
|
|
||||||
export default class PluginApproval extends Plugin {
|
export default class PluginApproval extends Plugin {
|
||||||
async afterAdd() {
|
async afterAdd() {
|
||||||
this.pm.add(PluginKitApprovalConfiguration);
|
this.pm.add(KitApprovalConfiguration);
|
||||||
this.pm.add(PluginKitApprovalUsage);
|
this.pm.add(KitApprovalUsage);
|
||||||
}
|
}
|
||||||
async beforeLoad() {}
|
async beforeLoad() {}
|
||||||
async load() {}
|
async load() {}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import React from 'react';
|
|
||||||
import { ExtendCollectionsProvider, TableBlockProvider, useRecord } from '@tachybase/client';
|
import { ExtendCollectionsProvider, TableBlockProvider, useRecord } from '@tachybase/client';
|
||||||
|
import React from 'react';
|
||||||
import { CollectionApprovalTodos } from '../../common/Cn.ApprovalTodos';
|
import { CollectionApprovalTodos } from '../../common/Cn.ApprovalTodos';
|
||||||
import { CollectionApprovals } from '../approval-common/Approvals.collection';
|
import { CollectionApprovals } from '../approval-common/Approvals.collection';
|
||||||
import { CollectionFlowNodes } from '../approval-common/FlowNodes.collection';
|
import { CollectionFlowNodes } from '../approval-common/FlowNodes.collection';
|
||||||
import { CollectionWorkflows } from '../approval-common/Workflows.collection';
|
import { CollectionWorkflows } from '../approval-common/Workflows.collection';
|
||||||
|
|
||||||
export function ApprovalBlockDecorator({ children, ...props }) {
|
export const ApprovalBlockProvider = ({ children, ...props }) => {
|
||||||
const {
|
const {
|
||||||
collection,
|
collection,
|
||||||
action = 'list',
|
|
||||||
params = {
|
params = {
|
||||||
filter: {},
|
filter: {},
|
||||||
},
|
},
|
||||||
|
action = 'list',
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
@ -23,7 +23,12 @@ export function ApprovalBlockDecorator({ children, ...props }) {
|
|||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
sort: ['-createdAt'],
|
sort: ['-createdAt'],
|
||||||
...params,
|
...params,
|
||||||
filter: record?.id ? { dataKey: `${record.id}`, ...params.filter } : { ...params.filter },
|
filter: record?.id
|
||||||
|
? {
|
||||||
|
dataKey: `${record.id}`,
|
||||||
|
...params.filter,
|
||||||
|
}
|
||||||
|
: { ...params.filter },
|
||||||
},
|
},
|
||||||
rowKey: 'id',
|
rowKey: 'id',
|
||||||
showIndex: true,
|
showIndex: true,
|
||||||
@ -39,4 +44,4 @@ export function ApprovalBlockDecorator({ children, ...props }) {
|
|||||||
</TableBlockProvider>
|
</TableBlockProvider>
|
||||||
</ExtendCollectionsProvider>
|
</ExtendCollectionsProvider>
|
||||||
);
|
);
|
||||||
}
|
};
|
@ -0,0 +1,93 @@
|
|||||||
|
import { Plugin } from '@tachybase/client';
|
||||||
|
import { TableOutlined } from '@ant-design/icons';
|
||||||
|
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '@tachybase/client';
|
||||||
|
import { uid } from '@tachybase/utils/client';
|
||||||
|
import React from 'react';
|
||||||
|
import { NAMESPACE } from '../../locale';
|
||||||
|
import { ApprovalBlockLaunch } from './launch/VC.ApprovalBlockLaunch';
|
||||||
|
import { ApprovalBlockProvider } from './ApprovalBlock.provider';
|
||||||
|
import { ApprovalBlockTodos } from './todos/VC.ApprovalBlockTodos';
|
||||||
|
|
||||||
|
export class SCApprovalBlock extends Plugin {
|
||||||
|
async load() {
|
||||||
|
this.app.addComponents({
|
||||||
|
'ApprovalBlock.Decorator': ApprovalBlockProvider,
|
||||||
|
'ApprovalBlock.Launch': ApprovalBlockLaunch,
|
||||||
|
'ApprovalBlock.Todos': ApprovalBlockTodos,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const schemaItems = [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: `{{t("Launch", { ns: "${NAMESPACE}" })}}`,
|
||||||
|
'x-component': 'ApprovalBlock.Launch',
|
||||||
|
collection: 'approvals',
|
||||||
|
params: {
|
||||||
|
appends: ['createdBy.nickname', 'workflow.title', 'workflow.enabled'],
|
||||||
|
except: ['data'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: `{{t("Todos", { ns: "${NAMESPACE}" })}}`,
|
||||||
|
'x-component': 'ApprovalBlock.Todos',
|
||||||
|
collection: 'approvalRecords',
|
||||||
|
params: {
|
||||||
|
appends: [
|
||||||
|
'user.id',
|
||||||
|
'user.nickname',
|
||||||
|
'node.id',
|
||||||
|
'node.title',
|
||||||
|
'job.id',
|
||||||
|
'job.status',
|
||||||
|
'job.result',
|
||||||
|
'workflow.id',
|
||||||
|
'workflow.title',
|
||||||
|
'workflow.enabled',
|
||||||
|
'execution.id',
|
||||||
|
'execution.status',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const getSchemaInsert = ({ item }) => {
|
||||||
|
const id = uid();
|
||||||
|
const { collection, params, ['x-component']: xcomponent } = item;
|
||||||
|
return {
|
||||||
|
type: 'void',
|
||||||
|
name: id,
|
||||||
|
'x-uid': id,
|
||||||
|
'x-designer': 'TableBlockDesigner',
|
||||||
|
'x-decorator': 'ApprovalBlock.Decorator',
|
||||||
|
'x-decorator-props': {
|
||||||
|
collection,
|
||||||
|
params,
|
||||||
|
action: 'listCentralized',
|
||||||
|
},
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
properties: {
|
||||||
|
block: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': xcomponent,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建区块-审批(发起/待办)
|
||||||
|
export const ApprovalBlockComponent = () => {
|
||||||
|
const schemaInitializerItem = useSchemaInitializerItem();
|
||||||
|
const { insert } = useSchemaInitializer();
|
||||||
|
|
||||||
|
const onClick = ({ item }) => {
|
||||||
|
const schema = getSchemaInsert({ item });
|
||||||
|
insert(schema);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SchemaInitializerItem icon={<TableOutlined />} {...schemaInitializerItem} items={schemaItems} onClick={onClick} />
|
||||||
|
);
|
||||||
|
};
|
@ -1,73 +0,0 @@
|
|||||||
import { TableOutlined } from '@ant-design/icons';
|
|
||||||
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '@tachybase/client';
|
|
||||||
import { uid } from '@tachybase/utils/client';
|
|
||||||
import React from 'react';
|
|
||||||
import { NAMESPACE } from '../../locale';
|
|
||||||
|
|
||||||
// 创建区块-审批(发起/待办)
|
|
||||||
export const ApprovalBlockComponent = () => {
|
|
||||||
const schemaInitializerItem = useSchemaInitializerItem();
|
|
||||||
const { insert } = useSchemaInitializer();
|
|
||||||
return (
|
|
||||||
<SchemaInitializerItem
|
|
||||||
icon={<TableOutlined />}
|
|
||||||
{...schemaInitializerItem}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
type: 'item',
|
|
||||||
title: `{{t("Launch", { ns: "${NAMESPACE}" })}}`,
|
|
||||||
'x-component': 'ApprovalBlock.Launch',
|
|
||||||
collection: 'approvals',
|
|
||||||
params: {
|
|
||||||
appends: ['createdBy.nickname', 'workflow.title', 'workflow.enabled'],
|
|
||||||
except: ['data'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'item',
|
|
||||||
title: `{{t("Todos", { ns: "${NAMESPACE}" })}}`,
|
|
||||||
'x-component': 'ApprovalBlock.Todos',
|
|
||||||
collection: 'approvalRecords',
|
|
||||||
params: {
|
|
||||||
appends: [
|
|
||||||
'user.id',
|
|
||||||
'user.nickname',
|
|
||||||
'node.id',
|
|
||||||
'node.title',
|
|
||||||
'job.id',
|
|
||||||
'job.status',
|
|
||||||
'job.result',
|
|
||||||
'workflow.id',
|
|
||||||
'workflow.title',
|
|
||||||
'workflow.enabled',
|
|
||||||
'execution.id',
|
|
||||||
'execution.status',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onClick={({ item }) => {
|
|
||||||
const id = uid();
|
|
||||||
insert({
|
|
||||||
type: 'void',
|
|
||||||
name: id,
|
|
||||||
'x-uid': id,
|
|
||||||
'x-component': 'CardItem',
|
|
||||||
'x-decorator': 'ApprovalBlock.Decorator',
|
|
||||||
'x-decorator-props': {
|
|
||||||
collection: item.collection,
|
|
||||||
action: 'listCentralized',
|
|
||||||
params: item.params,
|
|
||||||
},
|
|
||||||
'x-designer': 'TableBlockDesigner',
|
|
||||||
properties: {
|
|
||||||
block: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': item['x-component'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
export interface Approval {
|
|
||||||
id: number;
|
|
||||||
collectionName: string;
|
|
||||||
dataKey: string;
|
|
||||||
workflow: any;
|
|
||||||
executions: any[];
|
|
||||||
approvalExecutions: any[];
|
|
||||||
latestApprovalExecution: any;
|
|
||||||
records: any[];
|
|
||||||
createdById: number;
|
|
||||||
status: number;
|
|
||||||
data: any;
|
|
||||||
applicantRole: any;
|
|
||||||
latestExecutionId?: any;
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import { NAMESPACE } from '../../../locale';
|
import { NAMESPACE, tval } from '../../../locale';
|
||||||
import { css } from '@tachybase/client';
|
import { css } from '@tachybase/client';
|
||||||
|
|
||||||
export const SchemaApprovalBlockLaunch = {
|
export const SchemaApprovalBlockLaunch = {
|
||||||
@ -142,6 +142,19 @@ export const SchemaApprovalBlockLaunch = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
summaryString: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'TableV2.Column.Decorator',
|
||||||
|
'x-component': 'TableV2.Column',
|
||||||
|
title: tval('Approval Summary'),
|
||||||
|
properties: {
|
||||||
|
summaryString: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,26 +1,21 @@
|
|||||||
import { Plugin } from '@tachybase/client';
|
import { Plugin } from '@tachybase/client';
|
||||||
import { PluginKitApprovalCommon } from '../approval-common/plugin';
|
|
||||||
import { tval } from '../../locale';
|
import { tval } from '../../locale';
|
||||||
import { ViewActionTodos } from './todos/VC.ViewActionTodos';
|
import { PluginKitApprovalCommon } from '../approval-common/plugin';
|
||||||
import { ApprovalBlockComponent } from './VC.ApprovalBlock';
|
import { ApprovalBlockComponent, SCApprovalBlock } from './ApprovalBlock.schema';
|
||||||
import { ApprovalBlockTodos } from './todos/VC.ApprovalBlockTodos';
|
|
||||||
import { ViewActionLaunch } from './launch/VC.ViewActionLaunch';
|
import { ViewActionLaunch } from './launch/VC.ViewActionLaunch';
|
||||||
import { ApprovalBlockDecorator } from './Dt.ApprovalBlock';
|
import { ViewActionTodos } from './todos/VC.ViewActionTodos';
|
||||||
import { ApprovalBlockLaunch } from './launch/VC.ApprovalBlockLaunch';
|
|
||||||
|
|
||||||
export class PluginKitApprovalBlock extends Plugin {
|
export class KitApprovalBlock extends Plugin {
|
||||||
async afterAdd() {
|
async afterAdd() {
|
||||||
this.pm.add(PluginKitApprovalCommon);
|
this.pm.add(PluginKitApprovalCommon);
|
||||||
|
this.pm.add(SCApprovalBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
async beforeLoad() {}
|
async beforeLoad() {}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
this.app.addComponents({
|
this.app.addComponents({
|
||||||
'ApprovalBlock.Decorator': ApprovalBlockDecorator,
|
|
||||||
'ApprovalBlock.BlockInitializer': ApprovalBlockComponent,
|
'ApprovalBlock.BlockInitializer': ApprovalBlockComponent,
|
||||||
'ApprovalBlock.Launch': ApprovalBlockLaunch,
|
|
||||||
'ApprovalBlock.Todos': ApprovalBlockTodos,
|
|
||||||
'ApprovalBlock.ViewActionLaunch': ViewActionLaunch,
|
'ApprovalBlock.ViewActionLaunch': ViewActionLaunch,
|
||||||
'ApprovalBlock.ViewActionTodos': ViewActionTodos,
|
'ApprovalBlock.ViewActionTodos': ViewActionTodos,
|
||||||
});
|
});
|
@ -1,5 +1,19 @@
|
|||||||
import { createContext, useContext } from 'react';
|
import { createContext, useContext } from 'react';
|
||||||
import { Approval } from '../interface';
|
export interface Approval {
|
||||||
|
id: number;
|
||||||
|
collectionName: string;
|
||||||
|
dataKey: string;
|
||||||
|
workflow: any;
|
||||||
|
executions: any[];
|
||||||
|
approvalExecutions: any[];
|
||||||
|
latestApprovalExecution: any;
|
||||||
|
records: any[];
|
||||||
|
createdById: number;
|
||||||
|
status: number;
|
||||||
|
data: any;
|
||||||
|
applicantRole: any;
|
||||||
|
latestExecutionId?: any;
|
||||||
|
}
|
||||||
|
|
||||||
interface ApprovalExecutions {
|
interface ApprovalExecutions {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { css } from '@tachybase/client';
|
import { css } from '@tachybase/client';
|
||||||
import { NAMESPACE } from '../../../locale';
|
import { NAMESPACE, tval } from '../../../locale';
|
||||||
|
|
||||||
export const SchemaApprovalBlockTodos = {
|
export const SchemaApprovalBlockTodos = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -143,6 +143,19 @@ export const SchemaApprovalBlockTodos = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
summaryString: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'TableV2.Column.Decorator',
|
||||||
|
'x-component': 'TableV2.Column',
|
||||||
|
title: tval('Approval Summary'),
|
||||||
|
properties: {
|
||||||
|
summaryString: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useRecord } from '@tachybase/client';
|
import { useRecord } from '@tachybase/client';
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext } from 'react';
|
||||||
import { Approval } from '../approval-block/interface';
|
import { Approval } from '../approval-block/todos/Pd.ApprovalExecutions';
|
||||||
|
|
||||||
export const ApprovalContext = createContext<Partial<Approval>>({});
|
export const ApprovalContext = createContext<Partial<Approval>>({});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { NAMESPACE } from '../../locale';
|
import { NAMESPACE, tval } from '../../locale';
|
||||||
import { ApprovalStatusEnums } from '../../constants';
|
import { ApprovalStatusEnums } from '../../constants';
|
||||||
|
|
||||||
export const CollectionApprovals = {
|
export const CollectionApprovals = {
|
||||||
@ -9,7 +9,11 @@ export const CollectionApprovals = {
|
|||||||
type: 'bigInt',
|
type: 'bigInt',
|
||||||
name: 'id',
|
name: 'id',
|
||||||
interface: 'number',
|
interface: 'number',
|
||||||
uiSchema: { type: 'number', title: 'ID', 'x-component': 'InputNumber' },
|
uiSchema: {
|
||||||
|
type: 'number',
|
||||||
|
title: 'ID',
|
||||||
|
'x-component': 'InputNumber',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'belongsTo',
|
type: 'belongsTo',
|
||||||
@ -34,7 +38,15 @@ export const CollectionApprovals = {
|
|||||||
type: 'number',
|
type: 'number',
|
||||||
title: `{{t("Initiator", { ns: "${NAMESPACE}" })}}`,
|
title: `{{t("Initiator", { ns: "${NAMESPACE}" })}}`,
|
||||||
'x-component': 'RemoteSelect',
|
'x-component': 'RemoteSelect',
|
||||||
'x-component-props': { fieldNames: { label: 'nickname', value: 'id' }, service: { resource: 'users' } },
|
'x-component-props': {
|
||||||
|
fieldNames: {
|
||||||
|
label: 'nickname',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
service: {
|
||||||
|
resource: 'users',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -59,5 +71,22 @@ export const CollectionApprovals = {
|
|||||||
'x-component-props': { showTime: true },
|
'x-component-props': { showTime: true },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'summaryString',
|
||||||
|
interface: 'input',
|
||||||
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
title: tval('Summary'),
|
||||||
|
'x-component': 'ApprovalsSummary',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const ApprovalsSummary = (props) => {
|
||||||
|
const { value = '', style } = props;
|
||||||
|
const valueArray = value.split(',');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{valueArray.map((val) => (
|
||||||
|
<div style={style} key={val}>
|
||||||
|
{val}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -13,8 +13,18 @@ export const CollectionFlowNodes = {
|
|||||||
title: 'ID',
|
title: 'ID',
|
||||||
'x-component': 'RemoteSelect',
|
'x-component': 'RemoteSelect',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
fieldNames: { label: 'title', value: 'id' },
|
fieldNames: {
|
||||||
service: { resource: 'flow_nodes', params: { filter: { type: 'manual' } } },
|
label: 'title',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
service: {
|
||||||
|
resource: 'flow_nodes',
|
||||||
|
params: {
|
||||||
|
filter: {
|
||||||
|
type: 'manual',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -22,7 +32,11 @@ export const CollectionFlowNodes = {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
name: 'title',
|
name: 'title',
|
||||||
interface: 'input',
|
interface: 'input',
|
||||||
uiSchema: { type: 'string', title: '{{t("Title")}}', 'x-component': 'Input' },
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Title")}}',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,12 @@ export const CollectionWorkflows = {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
name: 'title',
|
name: 'title',
|
||||||
interface: 'input',
|
interface: 'input',
|
||||||
uiSchema: { title: '{{t("Name")}}', type: 'string', 'x-component': 'Input', required: true },
|
uiSchema: {
|
||||||
|
title: '{{t("Name")}}',
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
@ -19,8 +24,14 @@ export const CollectionWorkflows = {
|
|||||||
title: '{{t("Status", { ns: "workflow" })}}',
|
title: '{{t("Status", { ns: "workflow" })}}',
|
||||||
'x-component': 'Select',
|
'x-component': 'Select',
|
||||||
enum: [
|
enum: [
|
||||||
{ label: '{{t("On", { ns: "workflow" })}}', value: true },
|
{
|
||||||
{ label: '{{t("Off", { ns: "workflow" })}}', value: false },
|
label: '{{t("On", { ns: "workflow" })}}',
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '{{t("Off", { ns: "workflow" })}}',
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Plugin } from '@tachybase/client';
|
import { Plugin } from '@tachybase/client';
|
||||||
import { ApprovalDataProvider } from './ApprovalData.provider';
|
import { ApprovalDataProvider } from './ApprovalData.provider';
|
||||||
import { ApprovalProcess } from './ApprovalProcess.view';
|
import { ApprovalProcess } from './ApprovalProcess.view';
|
||||||
|
import { ApprovalsSummary } from './ApprovalsSummary.view';
|
||||||
|
|
||||||
export class PluginKitApprovalCommon extends Plugin {
|
export class PluginKitApprovalCommon extends Plugin {
|
||||||
async afterAdd() {}
|
async afterAdd() {}
|
||||||
@ -8,8 +9,10 @@ export class PluginKitApprovalCommon extends Plugin {
|
|||||||
async load() {
|
async load() {
|
||||||
this.app.addComponents({
|
this.app.addComponents({
|
||||||
// ApprovalCommon,
|
// ApprovalCommon,
|
||||||
|
|
||||||
'ApprovalCommon.Provider.ApprovalDataProvider': ApprovalDataProvider,
|
'ApprovalCommon.Provider.ApprovalDataProvider': ApprovalDataProvider,
|
||||||
'ApprovalCommon.ViewComponent.ApprovalProcess': ApprovalProcess,
|
'ApprovalCommon.ViewComponent.ApprovalProcess': ApprovalProcess,
|
||||||
|
ApprovalsSummary: ApprovalsSummary,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { renderColumnDetail } from './render.detail';
|
|||||||
import { renderColumnStatus } from './render.status';
|
import { renderColumnStatus } from './render.status';
|
||||||
import { renderColumnTaskNode } from './render.taskNode';
|
import { renderColumnTaskNode } from './render.taskNode';
|
||||||
|
|
||||||
|
// 审批处理-表格行配置
|
||||||
export const getAntdTableColumns = ({ t, styles }) => {
|
export const getAntdTableColumns = ({ t, styles }) => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Plugin } from '@tachybase/client';
|
import { Plugin } from '@tachybase/client';
|
||||||
import { PluginKitApprovalRecordBlock } from './approval-record-block/plugin';
|
import { PluginKitApprovalRecordBlock } from './approval-record-block/plugin';
|
||||||
import { PluginKitApprovalBlock } from './approval-block';
|
import { KitApprovalBlock } from './approval-block/plugin';
|
||||||
|
|
||||||
export class PluginKitApprovalUsage extends Plugin {
|
export class KitApprovalUsage extends Plugin {
|
||||||
async afterAdd() {
|
async afterAdd() {
|
||||||
this.pm.add(PluginKitApprovalRecordBlock);
|
this.pm.add(PluginKitApprovalRecordBlock);
|
||||||
this.pm.add(PluginKitApprovalBlock);
|
this.pm.add(KitApprovalBlock);
|
||||||
}
|
}
|
||||||
async beforeLoad() {}
|
async beforeLoad() {}
|
||||||
async load() {}
|
async load() {}
|
@ -12,6 +12,7 @@
|
|||||||
"Initiator": "Initiator",
|
"Initiator": "Initiator",
|
||||||
"Application content": "Application content",
|
"Application content": "Application content",
|
||||||
"Approval process": "Approval process",
|
"Approval process": "Approval process",
|
||||||
|
"Approval Summary": "Approval Summary",
|
||||||
"History": "History",
|
"History": "History",
|
||||||
"Approval ID": "Approval ID",
|
"Approval ID": "Approval ID",
|
||||||
"Node": "Node",
|
"Node": "Node",
|
||||||
@ -61,5 +62,6 @@
|
|||||||
"End on reject": "End on reject",
|
"End on reject": "End on reject",
|
||||||
"If checked, the workflow will be terminated after rejection branch processed.": "If checked, the workflow will be terminated after rejection branch processed.",
|
"If checked, the workflow will be terminated after rejection branch processed.": "If checked, the workflow will be terminated after rejection branch processed.",
|
||||||
"Disabled": "Disabled",
|
"Disabled": "Disabled",
|
||||||
"Trigger data": "Trigger data"
|
"Trigger data": "Trigger data",
|
||||||
|
"Select fields to display in the approval summary": "Select fields to display in the approval summary"
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"Initiator": "发起人",
|
"Initiator": "发起人",
|
||||||
"Application content": "申请内容",
|
"Application content": "申请内容",
|
||||||
"Approval process": "审批处理",
|
"Approval process": "审批处理",
|
||||||
|
"Approval Summary": "审批摘要",
|
||||||
"No data yet": "暂无数据",
|
"No data yet": "暂无数据",
|
||||||
"Approval ID": "单据编号",
|
"Approval ID": "单据编号",
|
||||||
"Current status": "当前状态",
|
"Current status": "当前状态",
|
||||||
@ -76,5 +77,6 @@
|
|||||||
"When checked, the workflow will terminate when the rejection branch ends.": "勾选后,否决分支结束后工作流将终止。",
|
"When checked, the workflow will terminate when the rejection branch ends.": "勾选后,否决分支结束后工作流将终止。",
|
||||||
"Disabled": "已失效",
|
"Disabled": "已失效",
|
||||||
"Submission may be withdrawn, please try refresh the list.": "提交可能已被撤回,请尝试刷新列表。",
|
"Submission may be withdrawn, please try refresh the list.": "提交可能已被撤回,请尝试刷新列表。",
|
||||||
"Trigger data": "触发器数据"
|
"Trigger data": "触发器数据",
|
||||||
|
"Select fields to display in the approval summary": "选择审批摘要显示字段"
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ export default class ApprovalInstruction extends Instruction {
|
|||||||
filter: {
|
filter: {
|
||||||
'executions.id': processor.execution.id,
|
'executions.id': processor.execution.id,
|
||||||
},
|
},
|
||||||
fields: ['id', 'status', 'data'],
|
fields: ['id', 'status', 'data', 'summaryString'],
|
||||||
appends: ['approvalExecutions'],
|
appends: ['approvalExecutions'],
|
||||||
except: ['data'],
|
except: ['data'],
|
||||||
});
|
});
|
||||||
@ -145,6 +145,7 @@ export default class ApprovalInstruction extends Instruction {
|
|||||||
index,
|
index,
|
||||||
status: node.config.order && index ? APPROVAL_ACTION_STATUS.ASSIGNED : APPROVAL_ACTION_STATUS.PENDING,
|
status: node.config.order && index ? APPROVAL_ACTION_STATUS.ASSIGNED : APPROVAL_ACTION_STATUS.PENDING,
|
||||||
snapshot: approvalExecution.snapshot,
|
snapshot: approvalExecution.snapshot,
|
||||||
|
summaryString: approval.summaryString,
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
transaction: processor.transaction,
|
transaction: processor.transaction,
|
||||||
|
@ -5,6 +5,7 @@ import { parseCollectionName } from '@tachybase/data-source-manager';
|
|||||||
import { EXECUTION_STATUS, Trigger, toJSON, JOB_STATUS } from '@tachybase/plugin-workflow';
|
import { EXECUTION_STATUS, Trigger, toJSON, JOB_STATUS } from '@tachybase/plugin-workflow';
|
||||||
import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS } from './constants';
|
import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS } from './constants';
|
||||||
import { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
|
import { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
|
||||||
|
import { getSummaryString } from './tools';
|
||||||
|
|
||||||
const ExecutionStatusMap = {
|
const ExecutionStatusMap = {
|
||||||
[EXECUTION_STATUS.RESOLVED]: APPROVAL_STATUS.APPROVED,
|
[EXECUTION_STATUS.RESOLVED]: APPROVAL_STATUS.APPROVED,
|
||||||
@ -51,6 +52,10 @@ export default class ApprovalTrigger extends Trigger {
|
|||||||
data: toJSON(data),
|
data: toJSON(data),
|
||||||
approvalId: approval.id,
|
approvalId: approval.id,
|
||||||
applicantRoleName: approval.applicantRoleName,
|
applicantRoleName: approval.applicantRoleName,
|
||||||
|
summaryString: getSummaryString({
|
||||||
|
summaryConfig: workflow.config.summary,
|
||||||
|
data,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{ transaction },
|
{ transaction },
|
||||||
);
|
);
|
||||||
@ -60,13 +65,14 @@ export default class ApprovalTrigger extends Trigger {
|
|||||||
if (workflow.type !== ApprovalTrigger.TYPE) {
|
if (workflow.type !== ApprovalTrigger.TYPE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { approvalId, data } = execution.context;
|
const { approvalId, data, summaryString } = execution.context;
|
||||||
const approvalExecution = await this.workflow.db.getRepository('approvalExecutions').create({
|
const approvalExecution = await this.workflow.db.getRepository('approvalExecutions').create({
|
||||||
values: {
|
values: {
|
||||||
approvalId,
|
approvalId,
|
||||||
executionId: execution.id,
|
executionId: execution.id,
|
||||||
status: execution.status,
|
status: execution.status,
|
||||||
snapshot: data,
|
snapshot: data,
|
||||||
|
summaryString: summaryString,
|
||||||
},
|
},
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
@ -192,6 +198,7 @@ export default class ApprovalTrigger extends Trigger {
|
|||||||
// updatedById: currentUser.id,
|
// updatedById: currentUser.id,
|
||||||
workflowId: workflow.id,
|
workflowId: workflow.id,
|
||||||
workflowKey: workflow.key,
|
workflowKey: workflow.key,
|
||||||
|
summaryString: '12,11,15',
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
});
|
});
|
||||||
@ -216,7 +223,20 @@ export default class ApprovalTrigger extends Trigger {
|
|||||||
if (dataSourceName !== dataSourceHeader) {
|
if (dataSourceName !== dataSourceHeader) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
(Array.isArray(data) ? data : [data]).forEach(async (row) => {
|
(Array.isArray(data) ? data : [data]).forEach(async (row) => {
|
||||||
|
let dataCurrent = {};
|
||||||
|
if (row.id) {
|
||||||
|
// XXX: 丑陋的实现, 应该从 data 直接获取的就是有值的 data, 走通优先.
|
||||||
|
const { repository } = this.workflow.app.dataSourceManager.dataSources
|
||||||
|
.get(dataSourceName)
|
||||||
|
.collectionManager.getCollection(collectionName);
|
||||||
|
const curretSummaryConfig = workflow.config?.summary || [];
|
||||||
|
dataCurrent = await repository.findOne({
|
||||||
|
filterByTk: data.id,
|
||||||
|
appends: [...workflow.config.appends],
|
||||||
|
});
|
||||||
|
}
|
||||||
let payload = row;
|
let payload = row;
|
||||||
if (trigger[1]) {
|
if (trigger[1]) {
|
||||||
const paths = trigger[1].split('.');
|
const paths = trigger[1].split('.');
|
||||||
@ -235,6 +255,8 @@ export default class ApprovalTrigger extends Trigger {
|
|||||||
if (!collection || collection.model !== payload.constructor) {
|
if (!collection || collection.model !== payload.constructor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 以上是 审批摘要取值逻辑
|
||||||
await approvalRepo.create({
|
await approvalRepo.create({
|
||||||
values: {
|
values: {
|
||||||
collectionName: workflow.config.collection,
|
collectionName: workflow.config.collection,
|
||||||
@ -246,6 +268,10 @@ export default class ApprovalTrigger extends Trigger {
|
|||||||
workflowId: workflow.id,
|
workflowId: workflow.id,
|
||||||
workflowKey: workflow.key,
|
workflowKey: workflow.key,
|
||||||
applicantRoleName: context.state.currentRole,
|
applicantRoleName: context.state.currentRole,
|
||||||
|
summaryString: getSummaryString({
|
||||||
|
summaryConfig: workflow.config.summary,
|
||||||
|
data: dataCurrent,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import actions, { utils } from '@tachybase/actions';
|
import actions, { utils } from '@tachybase/actions';
|
||||||
import WorkflowPlugin, { EXECUTION_STATUS, JOB_STATUS } from '@tachybase/plugin-workflow';
|
import WorkflowPlugin, { EXECUTION_STATUS, JOB_STATUS, toJSON } from '@tachybase/plugin-workflow';
|
||||||
import { APPROVAL_STATUS, APPROVAL_ACTION_STATUS } from './constants';
|
import { APPROVAL_STATUS, APPROVAL_ACTION_STATUS } from './constants';
|
||||||
import { parseCollectionName } from '@tachybase/data-source-manager';
|
import { parseCollectionName } from '@tachybase/data-source-manager';
|
||||||
|
|
||||||
@ -60,6 +60,7 @@ const approvals = {
|
|||||||
dataKey: values[collection.filterTargetKey],
|
dataKey: values[collection.filterTargetKey],
|
||||||
workflowKey: workflow.key,
|
workflowKey: workflow.key,
|
||||||
applicantRoleName: context.state.currentRole,
|
applicantRoleName: context.state.currentRole,
|
||||||
|
summary: toJSON(workflow.config?.summary ?? []),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return actions.create(context, next);
|
return actions.create(context, next);
|
||||||
@ -237,6 +238,7 @@ const approvalRecords = {
|
|||||||
status: values.status,
|
status: values.status,
|
||||||
comment: values.comment,
|
comment: values.comment,
|
||||||
snapshot: approvalRecord.approval.data,
|
snapshot: approvalRecord.approval.data,
|
||||||
|
summaryString: approvalRecord.approval.summaryString,
|
||||||
});
|
});
|
||||||
context.body = approvalRecord.get();
|
context.body = approvalRecord.get();
|
||||||
context.status = 202;
|
context.status = 202;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { defineCollection } from '@tachybase/database';
|
import { defineCollection } from '@tachybase/database';
|
||||||
|
|
||||||
|
// 审批
|
||||||
export default defineCollection({
|
export default defineCollection({
|
||||||
namespace: 'workflow.approvalExecutions',
|
namespace: 'workflow.approvalExecutions',
|
||||||
dumpRules: 'required',
|
dumpRules: 'required',
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { defineCollection } from '@tachybase/database';
|
import { defineCollection } from '@tachybase/database';
|
||||||
|
|
||||||
|
// 审批待办
|
||||||
export default defineCollection({
|
export default defineCollection({
|
||||||
namespace: 'workflow.approvalRecords',
|
namespace: 'workflow.approvalRecords',
|
||||||
dumpRules: 'required',
|
dumpRules: 'required',
|
||||||
@ -48,6 +50,11 @@ export default defineCollection({
|
|||||||
name: 'snapshot',
|
name: 'snapshot',
|
||||||
defaultValue: {},
|
defaultValue: {},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'summaryString',
|
||||||
|
defaultValue: '',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
name: 'comment',
|
name: 'comment',
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { defineCollection } from '@tachybase/database';
|
import { defineCollection } from '@tachybase/database';
|
||||||
|
|
||||||
|
// 审批发起
|
||||||
export default defineCollection({
|
export default defineCollection({
|
||||||
namespace: 'workflow.approvals',
|
namespace: 'workflow.approvals',
|
||||||
dumpRules: 'required',
|
dumpRules: 'required',
|
||||||
@ -59,6 +61,11 @@ export default defineCollection({
|
|||||||
name: 'data',
|
name: 'data',
|
||||||
defaultValue: {},
|
defaultValue: {},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'summaryString',
|
||||||
|
defaultValue: '',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'belongsTo',
|
type: 'belongsTo',
|
||||||
name: 'applicantRole',
|
name: 'applicantRole',
|
||||||
|
21
packages/plugins/@hera/plugin-approval/src/server/tools.ts
Normal file
21
packages/plugins/@hera/plugin-approval/src/server/tools.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
interface ParamsType {
|
||||||
|
summaryConfig: Array<string>;
|
||||||
|
data: object;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSummaryString(params: ParamsType): string {
|
||||||
|
const { summaryConfig = [], data } = params;
|
||||||
|
const result = summaryConfig
|
||||||
|
.map((key) => {
|
||||||
|
const value = _.get(data, key);
|
||||||
|
// XXX: 丑陋的实现, 不应该依赖具体字段, 应该从 summaryConfig, 拿到的就是最终的值, 走通优先
|
||||||
|
if (Object.prototype.toString.call(value) === '[object Object]') {
|
||||||
|
return _.get(value, 'name');
|
||||||
|
}
|
||||||
|
return _.get(data, key);
|
||||||
|
})
|
||||||
|
.join(',');
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user