feat: refactor resubmit (#1290)
Co-authored-by: sealday <sealday@gmail.com> Reviewed-on: https://git.daoyoucloud.com:8443/daoyoucloud/tachybase/pulls/1290
This commit is contained in:
parent
0b958cf528
commit
1d5306d427
@ -38,3 +38,5 @@ export default class DatabaseUtils {
|
|||||||
return this.db.options.schema || 'public';
|
return this.db.options.schema || 'public';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export * from './traverseJSON';
|
||||||
|
112
packages/core/database/src/database-utils/traverseJSON.ts
Normal file
112
packages/core/database/src/database-utils/traverseJSON.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { Collection } from '@tachybase/database';
|
||||||
|
|
||||||
|
type TraverseOptions = {
|
||||||
|
collection: Collection;
|
||||||
|
exclude?: string[];
|
||||||
|
include?: string[];
|
||||||
|
through?: string;
|
||||||
|
excludePk?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const traverseHasMany = (arr: any[], { collection, exclude = [], include = [] }: TraverseOptions) => {
|
||||||
|
if (!arr) {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
return arr.map((item) => traverseJSON(item, { collection, exclude, include }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const traverseBelongsToMany = (arr: any[], { collection, exclude = [], through }: TraverseOptions) => {
|
||||||
|
if (!arr) {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
const throughCollection = collection.db.getCollection(through);
|
||||||
|
return arr.map((item) => {
|
||||||
|
const data = traverseJSON(item[through], { collection: throughCollection, exclude });
|
||||||
|
if (data && Object.keys(data).length) {
|
||||||
|
item[through] = data;
|
||||||
|
} else {
|
||||||
|
delete item[through];
|
||||||
|
}
|
||||||
|
return traverseJSON(item, {
|
||||||
|
collection,
|
||||||
|
excludePk: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseInclude = (keys: string[]) => {
|
||||||
|
const map = {};
|
||||||
|
for (const key of keys) {
|
||||||
|
const args = key.split('.');
|
||||||
|
const field = args.shift();
|
||||||
|
map[field] = map[field] || [];
|
||||||
|
if (args.length) {
|
||||||
|
map[field].push(args.join('.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const traverseJSON = (data, options: TraverseOptions) => {
|
||||||
|
if (!data) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
const { collection, exclude = [], include = [], excludePk = true } = options;
|
||||||
|
const map = parseInclude(include);
|
||||||
|
const result = {};
|
||||||
|
for (const key of Object.keys(data || {})) {
|
||||||
|
const subInclude = map[key];
|
||||||
|
if (include.length > 0 && !subInclude) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (exclude.includes(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (['createdAt', 'updatedAt', 'createdBy', 'createdById', 'updatedById', 'updatedBy'].includes(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const field = collection.getField(key);
|
||||||
|
if (!field) {
|
||||||
|
result[key] = data[key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (field.options.primaryKey && excludePk) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (field.options.isForeignKey) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (['sort', 'password', 'sequence'].includes(field.type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (field.type === 'hasOne') {
|
||||||
|
result[key] = traverseJSON(data[key], {
|
||||||
|
collection: collection.db.getCollection(field.target),
|
||||||
|
exclude: [field.foreignKey],
|
||||||
|
include: subInclude,
|
||||||
|
});
|
||||||
|
} else if (field.type === 'hasMany') {
|
||||||
|
result[key] = traverseHasMany(data[key], {
|
||||||
|
collection: collection.db.getCollection(field.target),
|
||||||
|
exclude: [field.foreignKey],
|
||||||
|
include: subInclude,
|
||||||
|
});
|
||||||
|
} else if (field.type === 'belongsTo') {
|
||||||
|
result[key] = traverseJSON(data[key], {
|
||||||
|
collection: collection.db.getCollection(field.target),
|
||||||
|
// exclude: [field.foreignKey],
|
||||||
|
include: subInclude,
|
||||||
|
excludePk: false,
|
||||||
|
});
|
||||||
|
} else if (field.type === 'belongsToMany') {
|
||||||
|
result[key] = traverseBelongsToMany(data[key], {
|
||||||
|
collection: collection.db.getCollection(field.target),
|
||||||
|
exclude: [field.foreignKey, field.otherKey],
|
||||||
|
through: field.through,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result[key] = data[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
@ -38,6 +38,7 @@ export * from './relation-repository/single-relation-repository';
|
|||||||
export * from './repository';
|
export * from './repository';
|
||||||
export * from './update-associations';
|
export * from './update-associations';
|
||||||
export { snakeCase } from './utils';
|
export { snakeCase } from './utils';
|
||||||
|
export * from './database-utils';
|
||||||
export * from './value-parsers';
|
export * from './value-parsers';
|
||||||
export * from './view-collection';
|
export * from './view-collection';
|
||||||
export * from './view/view-inference';
|
export * from './view/view-inference';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Context } from '@tachybase/actions';
|
import { Context } from '@tachybase/actions';
|
||||||
import { Collection } from '@tachybase/database';
|
import { traverseJSON } from '@tachybase/database';
|
||||||
|
|
||||||
export const dateTemplate = async (ctx: Context, next) => {
|
export const dateTemplate = async (ctx: Context, next) => {
|
||||||
const { resourceName, actionName } = ctx.action;
|
const { resourceName, actionName } = ctx.action;
|
||||||
@ -14,114 +14,3 @@ export const dateTemplate = async (ctx: Context, next) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
type TraverseOptions = {
|
|
||||||
collection: Collection;
|
|
||||||
exclude?: string[];
|
|
||||||
include?: string[];
|
|
||||||
through?: string;
|
|
||||||
excludePk?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const traverseHasMany = (arr: any[], { collection, exclude = [], include = [] }: TraverseOptions) => {
|
|
||||||
if (!arr) {
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
return arr.map((item) => traverseJSON(item, { collection, exclude, include }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const traverseBelongsToMany = (arr: any[], { collection, exclude = [], through }: TraverseOptions) => {
|
|
||||||
if (!arr) {
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
const throughCollection = collection.db.getCollection(through);
|
|
||||||
return arr.map((item) => {
|
|
||||||
const data = traverseJSON(item[through], { collection: throughCollection, exclude });
|
|
||||||
if (data && Object.keys(data).length) {
|
|
||||||
item[through] = data;
|
|
||||||
} else {
|
|
||||||
delete item[through];
|
|
||||||
}
|
|
||||||
return traverseJSON(item, {
|
|
||||||
collection,
|
|
||||||
excludePk: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseInclude = (keys: string[]) => {
|
|
||||||
const map = {};
|
|
||||||
for (const key of keys) {
|
|
||||||
const args = key.split('.');
|
|
||||||
const field = args.shift();
|
|
||||||
map[field] = map[field] || [];
|
|
||||||
if (args.length) {
|
|
||||||
map[field].push(args.join('.'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
};
|
|
||||||
|
|
||||||
const traverseJSON = (data, options: TraverseOptions) => {
|
|
||||||
if (!data) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
const { collection, exclude = [], include = [], excludePk = true } = options;
|
|
||||||
const map = parseInclude(include);
|
|
||||||
const result = {};
|
|
||||||
for (const key of Object.keys(data || {})) {
|
|
||||||
const subInclude = map[key];
|
|
||||||
if (include.length > 0 && !subInclude) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (exclude.includes(key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (['createdAt', 'updatedAt', 'createdBy', 'createdById', 'updatedById', 'updatedBy'].includes(key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const field = collection.getField(key);
|
|
||||||
if (!field) {
|
|
||||||
result[key] = data[key];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (field.options.primaryKey && excludePk) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (field.options.isForeignKey) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (['sort', 'password', 'sequence'].includes(field.type)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (field.type === 'hasOne') {
|
|
||||||
result[key] = traverseJSON(data[key], {
|
|
||||||
collection: collection.db.getCollection(field.target),
|
|
||||||
exclude: [field.foreignKey],
|
|
||||||
include: subInclude,
|
|
||||||
});
|
|
||||||
} else if (field.type === 'hasMany') {
|
|
||||||
result[key] = traverseHasMany(data[key], {
|
|
||||||
collection: collection.db.getCollection(field.target),
|
|
||||||
exclude: [field.foreignKey],
|
|
||||||
include: subInclude,
|
|
||||||
});
|
|
||||||
} else if (field.type === 'belongsTo') {
|
|
||||||
result[key] = traverseJSON(data[key], {
|
|
||||||
collection: collection.db.getCollection(field.target),
|
|
||||||
// exclude: [field.foreignKey],
|
|
||||||
include: subInclude,
|
|
||||||
excludePk: false,
|
|
||||||
});
|
|
||||||
} else if (field.type === 'belongsToMany') {
|
|
||||||
result[key] = traverseBelongsToMany(data[key], {
|
|
||||||
collection: collection.db.getCollection(field.target),
|
|
||||||
exclude: [field.foreignKey, field.otherKey],
|
|
||||||
through: field.through,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
result[key] = data[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
@ -9,8 +9,6 @@ import {
|
|||||||
} from '@tachybase/client';
|
} from '@tachybase/client';
|
||||||
import { uid } from '@tachybase/utils/client';
|
import { uid } from '@tachybase/utils/client';
|
||||||
|
|
||||||
import { Spin } from 'antd';
|
|
||||||
|
|
||||||
import { useFlowContext } from '../../../../../FlowContext';
|
import { useFlowContext } from '../../../../../FlowContext';
|
||||||
|
|
||||||
// 发起人操作界面-创建区块
|
// 发起人操作界面-创建区块
|
||||||
@ -19,30 +17,26 @@ export const SchemaAddBlock = ({ value, onChange }) => {
|
|||||||
const { workflow } = useFlowContext();
|
const { workflow } = useFlowContext();
|
||||||
const { components } = useContext(SchemaComponentContext);
|
const { components } = useContext(SchemaComponentContext);
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// 获取对应数据表的表单Schema
|
// 获取对应数据表的表单Schema
|
||||||
const { data, loading } = useRequest(() =>
|
const { data, loading } = useRequest(async () => {
|
||||||
E(this, null, function* () {
|
if (value) {
|
||||||
let m;
|
const { data } = await api.request({ url: `uiSchemas:getJsonSchema/${value}` });
|
||||||
if (value) {
|
if (data.data?.['x-uid'] === value) return data.data;
|
||||||
const { data: h } = yield api.request({ url: `uiSchemas:getJsonSchema/${value}` });
|
}
|
||||||
if (((m = h.data) == null ? void 0 : m['x-uid']) === value) return h.data;
|
const name = uid();
|
||||||
}
|
const values = {
|
||||||
const l = uid(),
|
type: 'void',
|
||||||
d = {
|
name: name,
|
||||||
type: 'void',
|
'x-uid': name,
|
||||||
name: l,
|
'x-component': 'Grid',
|
||||||
'x-uid': l,
|
'x-initializer': 'ApprovalApplyAddBlockButton',
|
||||||
'x-component': 'Grid',
|
properties: {},
|
||||||
'x-initializer': 'ApprovalApplyAddBlockButton',
|
};
|
||||||
properties: {},
|
return await api.resource('uiSchemas').insert({ values }), onChange(name), values;
|
||||||
};
|
});
|
||||||
return yield api.resource('uiSchemas').insert({ values: d }), onChange(l), d;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Spin />;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -61,7 +55,6 @@ export const SchemaAddBlock = ({ value, onChange }) => {
|
|||||||
useFormBlockProps,
|
useFormBlockProps,
|
||||||
useActionResubmit,
|
useActionResubmit,
|
||||||
}}
|
}}
|
||||||
// @ts-ignore ugly
|
|
||||||
schema={data}
|
schema={data}
|
||||||
/>
|
/>
|
||||||
</SchemaComponentProvider>
|
</SchemaComponentProvider>
|
||||||
@ -89,24 +82,3 @@ function useActionResubmit() {
|
|||||||
function ProviderActionResubmit(props) {
|
function ProviderActionResubmit(props) {
|
||||||
return props.children;
|
return props.children;
|
||||||
}
|
}
|
||||||
// TODO:
|
|
||||||
const E = (f, o, p) =>
|
|
||||||
// eslint-disable-next-line promise/param-names
|
|
||||||
new Promise((r, G) => {
|
|
||||||
const u = ($) => {
|
|
||||||
try {
|
|
||||||
A(p.next($));
|
|
||||||
} catch (U) {
|
|
||||||
G(U);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
y = ($) => {
|
|
||||||
try {
|
|
||||||
A(p.throw($));
|
|
||||||
} catch (U) {
|
|
||||||
G(U);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
A = ($) => ($.done ? r($.value) : Promise.resolve($.value).then(u, y));
|
|
||||||
A((p = p.apply(f, o)).next());
|
|
||||||
});
|
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
import { useCurrentUserContext } from '@tachybase/client';
|
import { useCurrentUserContext } from '@tachybase/client';
|
||||||
|
|
||||||
import { useFlowContext } from '../../../../../FlowContext';
|
|
||||||
import { APPROVAL_STATUS } from '../../../constants';
|
import { APPROVAL_STATUS } from '../../../constants';
|
||||||
import { useApproval } from '../../approval-common/ApprovalData.provider';
|
import { useApproval } from '../../approval-common/ApprovalData.provider';
|
||||||
|
import { useResubmit } from '../../approval-common/Resubmit.provider';
|
||||||
|
|
||||||
export function ProviderActionResubmit(props) {
|
export function ProviderActionResubmit(props) {
|
||||||
const { data } = useCurrentUserContext();
|
const { data } = useCurrentUserContext();
|
||||||
|
const { isResubmit } = useResubmit();
|
||||||
const { status, createdById } = useApproval();
|
const { status, createdById } = useApproval();
|
||||||
const { workflow } = useFlowContext();
|
|
||||||
|
|
||||||
const isSameId = data.data.id === createdById;
|
const isSameId = data.data.id === createdById;
|
||||||
// const isEnabledWithdraw = workflow.enabled && workflow.config.withdrawable;
|
const isDraft = status === APPROVAL_STATUS.DRAFT;
|
||||||
// const isNotDraft = status !== APPROVAL_STATUS.DRAFT;
|
if (isSameId && !isResubmit && !isDraft) {
|
||||||
|
|
||||||
if (isSameId) {
|
|
||||||
return props.children;
|
return props.children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,14 +11,8 @@ export function ActionBarProvider(props) {
|
|||||||
|
|
||||||
const isSameId = data.data.id === createdById;
|
const isSameId = data.data.id === createdById;
|
||||||
const isSameExcutionId = latestExecutionId === approvalExecution.id;
|
const isSameExcutionId = latestExecutionId === approvalExecution.id;
|
||||||
const isExcutionDid = [
|
|
||||||
APPROVAL_STATUS.DRAFT,
|
|
||||||
APPROVAL_STATUS.RETURNED,
|
|
||||||
APPROVAL_STATUS.SUBMITTED,
|
|
||||||
APPROVAL_STATUS.RESUBMIT,
|
|
||||||
].includes(status);
|
|
||||||
|
|
||||||
if (!isSameId || !isSameExcutionId || !isExcutionDid) {
|
if (!isSameId || !isSameExcutionId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { useCurrentUserContext } from '@tachybase/client';
|
|||||||
import { useFlowContext } from '../../../../../FlowContext';
|
import { useFlowContext } from '../../../../../FlowContext';
|
||||||
import { APPROVAL_STATUS } from '../../../constants';
|
import { APPROVAL_STATUS } from '../../../constants';
|
||||||
import { useApproval } from '../../approval-common/ApprovalData.provider';
|
import { useApproval } from '../../approval-common/ApprovalData.provider';
|
||||||
|
import { useResubmit } from '../../approval-common/Resubmit.provider';
|
||||||
|
|
||||||
const ContextApprovalStatus = createContext(APPROVAL_STATUS.SUBMITTED);
|
const ContextApprovalStatus = createContext(APPROVAL_STATUS.SUBMITTED);
|
||||||
|
|
||||||
@ -16,11 +17,16 @@ export function ApplyActionStatusProvider(props) {
|
|||||||
const { status, createdById } = useApproval();
|
const { status, createdById } = useApproval();
|
||||||
const { workflow } = useFlowContext();
|
const { workflow } = useFlowContext();
|
||||||
const { data } = useCurrentUserContext();
|
const { data } = useCurrentUserContext();
|
||||||
|
const { isResubmit } = useResubmit();
|
||||||
const isSameId = data.data.id === createdById;
|
const isSameId = data.data.id === createdById;
|
||||||
const isEnbled = workflow.enabled;
|
const isEnabled = workflow.enabled;
|
||||||
const isStatusDid = [APPROVAL_STATUS.RESUBMIT, APPROVAL_STATUS.DRAFT, APPROVAL_STATUS.RETURNED].includes(status);
|
const isStatusDid = [APPROVAL_STATUS.RESUBMIT, APPROVAL_STATUS.DRAFT, APPROVAL_STATUS.RETURNED].includes(status);
|
||||||
|
|
||||||
if (isSameId && isEnbled && isStatusDid) {
|
if (value === APPROVAL_STATUS.DRAFT && status === APPROVAL_STATUS.DRAFT) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((isSameId && isEnabled && isStatusDid) || (isSameId && isEnabled && isResubmit)) {
|
||||||
return <ContextApprovalStatus.Provider value={value}>{children}</ContextApprovalStatus.Provider>;
|
return <ContextApprovalStatus.Provider value={value}>{children}</ContextApprovalStatus.Provider>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,17 +3,19 @@ import { useCurrentUserContext } from '@tachybase/client';
|
|||||||
import { useFlowContext } from '../../../../../FlowContext';
|
import { useFlowContext } from '../../../../../FlowContext';
|
||||||
import { APPROVAL_STATUS } from '../../../constants';
|
import { APPROVAL_STATUS } from '../../../constants';
|
||||||
import { useApproval } from '../../approval-common/ApprovalData.provider';
|
import { useApproval } from '../../approval-common/ApprovalData.provider';
|
||||||
|
import { useResubmit } from '../../approval-common/Resubmit.provider';
|
||||||
|
|
||||||
export function WithdrawActionProvider({ children }) {
|
export function WithdrawActionProvider({ children }) {
|
||||||
const { data } = useCurrentUserContext();
|
const { data } = useCurrentUserContext();
|
||||||
const { status, createdById } = useApproval();
|
const { status, createdById } = useApproval();
|
||||||
const { workflow } = useFlowContext();
|
const { workflow } = useFlowContext();
|
||||||
|
const { isResubmit } = useResubmit();
|
||||||
|
|
||||||
const isSameId = data.data.id === createdById;
|
const isSameId = data.data.id === createdById;
|
||||||
const isEnabledWithdraw = workflow.enabled && workflow.config.withdrawable;
|
const isEnabledWithdraw = workflow.enabled && workflow.config.withdrawable;
|
||||||
const isStatusSubmitted = APPROVAL_STATUS.SUBMITTED === status;
|
const isStatusSubmitted = APPROVAL_STATUS.SUBMITTED === status;
|
||||||
|
|
||||||
if (isSameId && isEnabledWithdraw && isStatusSubmitted) {
|
if (isSameId && isEnabledWithdraw && isStatusSubmitted && !isResubmit) {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import { FormBlockProvider } from '../../../common/FormBlock.provider';
|
|||||||
import { APPROVAL_STATUS } from '../../../constants';
|
import { APPROVAL_STATUS } from '../../../constants';
|
||||||
import { NAMESPACE } from '../../../locale';
|
import { NAMESPACE } from '../../../locale';
|
||||||
import { ApprovalContext } from '../../approval-common/ApprovalData.provider';
|
import { ApprovalContext } from '../../approval-common/ApprovalData.provider';
|
||||||
|
import { ResubmitProvider } from '../../approval-common/Resubmit.provider';
|
||||||
import { ContextWithActionEnabled } from '../../approval-common/WithActionEnabled.provider';
|
import { ContextWithActionEnabled } from '../../approval-common/WithActionEnabled.provider';
|
||||||
import { ContextApprovalExecution } from '../common/ApprovalExecution.provider';
|
import { ContextApprovalExecution } from '../common/ApprovalExecution.provider';
|
||||||
import { FlowContextProvider } from '../common/FlowContext.provider';
|
import { FlowContextProvider } from '../common/FlowContext.provider';
|
||||||
@ -85,77 +86,79 @@ export const ViewActionLaunchContent = () => {
|
|||||||
>
|
>
|
||||||
<ApprovalContext.Provider value={approval}>
|
<ApprovalContext.Provider value={approval}>
|
||||||
<ContextApprovalExecution.Provider value={approvalValue}>
|
<ContextApprovalExecution.Provider value={approvalValue}>
|
||||||
<SchemaComponent
|
<ResubmitProvider>
|
||||||
components={{
|
<SchemaComponent
|
||||||
SchemaComponentProvider: SchemaComponentProvider,
|
components={{
|
||||||
RemoteSchemaComponent: RemoteSchemaComponent,
|
SchemaComponentProvider,
|
||||||
SchemaComponentContextProvider,
|
RemoteSchemaComponent,
|
||||||
FormBlockProvider,
|
SchemaComponentContextProvider,
|
||||||
ActionBarProvider,
|
FormBlockProvider,
|
||||||
ApplyActionStatusProvider,
|
ActionBarProvider,
|
||||||
WithdrawActionProvider,
|
ApplyActionStatusProvider,
|
||||||
DetailsBlockProvider,
|
WithdrawActionProvider,
|
||||||
ProviderActionResubmit,
|
DetailsBlockProvider,
|
||||||
}}
|
ProviderActionResubmit,
|
||||||
scope={{
|
}}
|
||||||
useForm,
|
scope={{
|
||||||
useSubmit: useSubmit,
|
useForm,
|
||||||
useFormBlockProps,
|
useSubmit,
|
||||||
useDetailsBlockProps: useFormBlockContext,
|
useFormBlockProps,
|
||||||
useWithdrawAction,
|
useDetailsBlockProps: useFormBlockContext,
|
||||||
useDestroyAction,
|
useWithdrawAction,
|
||||||
useActionResubmit,
|
useDestroyAction,
|
||||||
}}
|
useActionResubmit,
|
||||||
schema={{
|
}}
|
||||||
name: `view-${approval == null ? void 0 : approval.id}`,
|
schema={{
|
||||||
type: 'void',
|
name: `view-${approval == null ? void 0 : approval.id}`,
|
||||||
properties: {
|
type: 'void',
|
||||||
tabs: {
|
properties: {
|
||||||
type: 'void',
|
tabs: {
|
||||||
'x-component': 'Tabs',
|
type: 'void',
|
||||||
properties: Object.assign(
|
'x-component': 'Tabs',
|
||||||
{
|
properties: Object.assign(
|
||||||
detail: {
|
{
|
||||||
type: 'void',
|
detail: {
|
||||||
title: `{{t('Application content', { ns: '${NAMESPACE}' })}}`,
|
type: 'void',
|
||||||
'x-component': 'Tabs.TabPane',
|
title: `{{t('Application content', { ns: '${NAMESPACE}' })}}`,
|
||||||
properties: {
|
'x-component': 'Tabs.TabPane',
|
||||||
detail: {
|
properties: {
|
||||||
type: 'void',
|
detail: {
|
||||||
'x-decorator': 'SchemaComponentContextProvider',
|
type: 'void',
|
||||||
'x-decorator-props': {
|
'x-decorator': 'SchemaComponentContextProvider',
|
||||||
designable: false,
|
'x-decorator-props': {
|
||||||
},
|
designable: false,
|
||||||
'x-component': 'RemoteSchemaComponent',
|
},
|
||||||
'x-component-props': {
|
'x-component': 'RemoteSchemaComponent',
|
||||||
uid: workflow?.config.applyForm,
|
'x-component-props': {
|
||||||
noForm: true,
|
uid: workflow?.config.applyForm,
|
||||||
},
|
noForm: true,
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
needHideProcess
|
|
||||||
? {}
|
|
||||||
: {
|
|
||||||
process: {
|
|
||||||
type: 'void',
|
|
||||||
title: `{{t('Approval process', { ns: '${NAMESPACE}' })}}`,
|
|
||||||
'x-component': 'Tabs.TabPane',
|
|
||||||
properties: {
|
|
||||||
process: {
|
|
||||||
type: 'void',
|
|
||||||
'x-decorator': 'CardItem',
|
|
||||||
'x-component': 'ApprovalCommon.ViewComponent.ApprovalProcess',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
},
|
||||||
|
needHideProcess
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
process: {
|
||||||
|
type: 'void',
|
||||||
|
title: `{{t('Approval process', { ns: '${NAMESPACE}' })}}`,
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
properties: {
|
||||||
|
process: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'CardItem',
|
||||||
|
'x-component': 'ApprovalCommon.ViewComponent.ApprovalProcess',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</ResubmitProvider>
|
||||||
</ContextApprovalExecution.Provider>
|
</ContextApprovalExecution.Provider>
|
||||||
</ApprovalContext.Provider>
|
</ApprovalContext.Provider>
|
||||||
</FlowContextProvider>
|
</FlowContextProvider>
|
||||||
|
@ -16,7 +16,7 @@ import { Button, Dropdown } from 'antd';
|
|||||||
import { useTranslation } from '../../../../locale';
|
import { useTranslation } from '../../../../locale';
|
||||||
import { FlowContextProvider } from '../../common/FlowContext.provider';
|
import { FlowContextProvider } from '../../common/FlowContext.provider';
|
||||||
import { useActionResubmit } from '../hooks/useActionResubmit';
|
import { useActionResubmit } from '../hooks/useActionResubmit';
|
||||||
import { useSubmit } from './hooks/useSubmit';
|
import { useCreateSubmit } from './hooks/useSubmit';
|
||||||
import { useWithdrawAction } from './hooks/useWithdrawAction';
|
import { useWithdrawAction } from './hooks/useWithdrawAction';
|
||||||
import { ActionBarProvider } from './Pd.ActionBar';
|
import { ActionBarProvider } from './Pd.ActionBar';
|
||||||
import { ApplyActionStatusProvider } from './Pd.ActionStatus';
|
import { ApplyActionStatusProvider } from './Pd.ActionStatus';
|
||||||
@ -108,15 +108,16 @@ export const ApplyButton = () => {
|
|||||||
<SchemaComponent
|
<SchemaComponent
|
||||||
schema={schema}
|
schema={schema}
|
||||||
components={{
|
components={{
|
||||||
RemoteSchemaComponent: RemoteSchemaComponent,
|
RemoteSchemaComponent,
|
||||||
CollectionProvider_deprecated: CollectionProvider_deprecated,
|
CollectionProvider_deprecated,
|
||||||
FlowContextProvider: FlowContextProvider,
|
FlowContextProvider,
|
||||||
ApplyActionStatusProvider: ApplyActionStatusProvider,
|
ApplyActionStatusProvider,
|
||||||
ActionBarProvider,
|
ActionBarProvider,
|
||||||
WithdrawActionProvider: WithdrawActionProvider,
|
ProviderActionResubmit: () => null,
|
||||||
|
WithdrawActionProvider,
|
||||||
}}
|
}}
|
||||||
scope={{
|
scope={{
|
||||||
useSubmit: useSubmit,
|
useSubmit: useCreateSubmit,
|
||||||
useWithdrawAction,
|
useWithdrawAction,
|
||||||
useActionResubmit,
|
useActionResubmit,
|
||||||
}}
|
}}
|
||||||
|
@ -7,21 +7,23 @@ import {
|
|||||||
} from '@tachybase/client';
|
} from '@tachybase/client';
|
||||||
import { useField, useForm } from '@tachybase/schema';
|
import { useField, useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { useFlowContext } from '../../../../../../../FlowContext';
|
import { useFlowContext } from '../../../../../../../FlowContext';
|
||||||
import { useContextApprovalStatus } from '../Pd.ActionStatus';
|
import { useContextApprovalStatus } from '../Pd.ActionStatus';
|
||||||
|
|
||||||
export function useSubmit() {
|
export function useCreateSubmit() {
|
||||||
const from = useForm();
|
const from = useForm();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const { setVisible } = useActionContext();
|
const { setVisible } = useActionContext();
|
||||||
const { __parent } = useBlockRequestContext();
|
const { __parent } = useBlockRequestContext();
|
||||||
const collection = useCollection_deprecated();
|
const collection = useCollection_deprecated();
|
||||||
const contextWe = useContextApprovalStatus();
|
const status = useContextApprovalStatus();
|
||||||
const apiClient = useAPIClient();
|
const apiClient = useAPIClient();
|
||||||
const { workflow } = useFlowContext();
|
const { workflow } = useFlowContext();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run({ approvalStatus }) {
|
||||||
try {
|
try {
|
||||||
from.submit();
|
from.submit();
|
||||||
field.data = field.data || {};
|
field.data = field.data || {};
|
||||||
@ -30,8 +32,8 @@ export function useSubmit() {
|
|||||||
await apiClient.resource('approvals').create({
|
await apiClient.resource('approvals').create({
|
||||||
values: {
|
values: {
|
||||||
collectionName: joinCollectionName(collection.dataSource, collection.name),
|
collectionName: joinCollectionName(collection.dataSource, collection.name),
|
||||||
data: from.values,
|
data: _.omit(from.values, [collection.getPrimaryKey()]),
|
||||||
status: contextWe,
|
status: typeof approvalStatus !== 'undefined' ? approvalStatus : status,
|
||||||
workflowId: workflow.id,
|
workflowId: workflow.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -43,7 +45,7 @@ export function useSubmit() {
|
|||||||
if (service) {
|
if (service) {
|
||||||
service.refresh();
|
service.refresh();
|
||||||
}
|
}
|
||||||
} catch (h) {
|
} catch (error) {
|
||||||
field.data && (field.data.loading = false);
|
field.data && (field.data.loading = false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,59 +1,14 @@
|
|||||||
import { useAPIClient } from '@tachybase/client';
|
|
||||||
import { useFlowContext } from '@tachybase/plugin-workflow/client';
|
|
||||||
import { useField } from '@tachybase/schema';
|
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { APPROVAL_STATUS } from '../../../../constants';
|
import { useResubmit } from '../../../approval-common/Resubmit.provider';
|
||||||
import { useApproval } from '../../../approval-common/ApprovalData.provider';
|
|
||||||
import { useHandleRefresh } from '../../common/useHandleRefresh';
|
|
||||||
|
|
||||||
// 重新发起
|
// 重新发起
|
||||||
export function useActionResubmit() {
|
export function useActionResubmit() {
|
||||||
const { refreshTable } = useHandleRefresh();
|
const { setResubmit } = useResubmit();
|
||||||
|
|
||||||
const field = useField();
|
|
||||||
const approval = useApproval();
|
|
||||||
const api = useAPIClient();
|
|
||||||
|
|
||||||
const { workflow } = useFlowContext();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run() {
|
||||||
try {
|
setResubmit(true);
|
||||||
field.data = field.data ?? {};
|
|
||||||
|
|
||||||
field.data.loading = true;
|
|
||||||
|
|
||||||
const appendsConfigs = [...workflow.config.appends];
|
|
||||||
const summaryConfigs = [...workflow.config.summary];
|
|
||||||
const appends = _.intersection(appendsConfigs, summaryConfigs);
|
|
||||||
|
|
||||||
const { data: approvalData } = await api.resource('approvals').get({
|
|
||||||
filterByTk: approval.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { collectionName, data, workflowId } = approvalData.data;
|
|
||||||
|
|
||||||
const newData = _.omit(data, ['id', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy']);
|
|
||||||
|
|
||||||
await api.resource('approvals').reSubmit({
|
|
||||||
values: {
|
|
||||||
collectionName: collectionName,
|
|
||||||
data: newData,
|
|
||||||
status: APPROVAL_STATUS.RESUBMIT,
|
|
||||||
workflowId: workflowId,
|
|
||||||
collectionAppends: appends,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
field.data.loading = false;
|
|
||||||
refreshTable();
|
|
||||||
} catch (v) {
|
|
||||||
if (field.data) {
|
|
||||||
field.data.loading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { useForm } from '@tachybase/schema';
|
|||||||
import { useFlowContext } from '../../../../../../FlowContext';
|
import { useFlowContext } from '../../../../../../FlowContext';
|
||||||
import { ApprovalStatusEnumDict } from '../../../../constants';
|
import { ApprovalStatusEnumDict } from '../../../../constants';
|
||||||
import { useApproval } from '../../../approval-common/ApprovalData.provider';
|
import { useApproval } from '../../../approval-common/ApprovalData.provider';
|
||||||
|
import { useResubmit } from '../../../approval-common/Resubmit.provider';
|
||||||
import { useContextApprovalExecution } from '../../common/ApprovalExecution.provider';
|
import { useContextApprovalExecution } from '../../common/ApprovalExecution.provider';
|
||||||
|
|
||||||
export function useFormBlockProps() {
|
export function useFormBlockProps() {
|
||||||
@ -13,11 +14,12 @@ export function useFormBlockProps() {
|
|||||||
const { workflow } = useFlowContext();
|
const { workflow } = useFlowContext();
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
const { data } = useCurrentUserContext();
|
const { data } = useCurrentUserContext();
|
||||||
|
const { isResubmit } = useResubmit();
|
||||||
|
|
||||||
const { editable } = ApprovalStatusEnumDict[approval.status];
|
const { editable } = ApprovalStatusEnumDict[approval.status];
|
||||||
|
|
||||||
const needEditable =
|
const needEditable =
|
||||||
editable &&
|
(isResubmit || editable) &&
|
||||||
approval?.latestExecutionId === approvalExecution.id &&
|
approval?.latestExecutionId === approvalExecution.id &&
|
||||||
approval?.createdById === data?.data.id &&
|
approval?.createdById === data?.data.id &&
|
||||||
workflow.enabled;
|
workflow.enabled;
|
||||||
|
@ -5,12 +5,17 @@ import _ from 'lodash';
|
|||||||
|
|
||||||
import { useFlowContext } from '../../../../../../FlowContext';
|
import { useFlowContext } from '../../../../../../FlowContext';
|
||||||
import { useApproval } from '../../../approval-common/ApprovalData.provider';
|
import { useApproval } from '../../../approval-common/ApprovalData.provider';
|
||||||
|
import { useResubmit } from '../../../approval-common/Resubmit.provider';
|
||||||
import { useHandleRefresh } from '../../common/useHandleRefresh';
|
import { useHandleRefresh } from '../../common/useHandleRefresh';
|
||||||
|
import { useCreateSubmit } from '../apply-button/hooks/useSubmit';
|
||||||
import { useContextApprovalStatus } from '../Pd.ApplyActionStatus';
|
import { useContextApprovalStatus } from '../Pd.ApplyActionStatus';
|
||||||
|
|
||||||
export function useSubmit() {
|
export function useSubmit() {
|
||||||
const { refreshTable } = useHandleRefresh();
|
const { refreshTable } = useHandleRefresh();
|
||||||
const apiClient = useAPIClient();
|
const apiClient = useAPIClient();
|
||||||
|
const { isResubmit } = useResubmit();
|
||||||
|
const { run: create } = useCreateSubmit();
|
||||||
|
const status = useContextApprovalStatus();
|
||||||
|
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
@ -20,7 +25,10 @@ export function useSubmit() {
|
|||||||
const contextApprovalStatus = useContextApprovalStatus();
|
const contextApprovalStatus = useContextApprovalStatus();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run(props) {
|
||||||
|
if (isResubmit) {
|
||||||
|
return await create({ approvalStatus: status });
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
form.submit();
|
form.submit();
|
||||||
_.set(field, ['data', 'loading'], true);
|
_.set(field, ['data', 'loading'], true);
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
import React, { useContext, useState } from 'react';
|
||||||
|
|
||||||
|
interface ResubmitProps {
|
||||||
|
isResubmit?: boolean;
|
||||||
|
setResubmit?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ResubmitContext = React.createContext<ResubmitProps>({});
|
||||||
|
|
||||||
|
export const ResubmitProvider = ({ children }) => {
|
||||||
|
const [isResubmit, setResubmit] = useState(false);
|
||||||
|
return <ResubmitContext.Provider value={{ isResubmit, setResubmit }}>{children}</ResubmitContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useResubmit = () => {
|
||||||
|
return useContext(ResubmitContext);
|
||||||
|
};
|
@ -1,8 +1,8 @@
|
|||||||
import actions, { utils } from '@tachybase/actions';
|
import actions, { utils } from '@tachybase/actions';
|
||||||
import { parseCollectionName } from '@tachybase/data-source-manager';
|
import { parseCollectionName } from '@tachybase/data-source-manager';
|
||||||
|
import { traverseJSON } from '@tachybase/database';
|
||||||
|
|
||||||
import { EXECUTION_STATUS, JOB_STATUS, PluginWorkflow } from '../..';
|
import { EXECUTION_STATUS, JOB_STATUS, PluginWorkflow } from '../..';
|
||||||
import { appends } from '../../../client/schemas/collection';
|
|
||||||
import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS } from './constants';
|
import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS } from './constants';
|
||||||
import { getSummary } from './tools';
|
import { getSummary } from './tools';
|
||||||
import { getAssociationName, jsonParse } from './utils';
|
import { getAssociationName, jsonParse } from './utils';
|
||||||
@ -47,7 +47,7 @@ const approvals = {
|
|||||||
const { repository, model } = collection;
|
const { repository, model } = collection;
|
||||||
const values = await repository.create({
|
const values = await repository.create({
|
||||||
values: {
|
values: {
|
||||||
...data,
|
...traverseJSON(data, { collection }),
|
||||||
createdBy: context.state.currentUser.id,
|
createdBy: context.state.currentUser.id,
|
||||||
updatedBy: context.state.currentUser.id,
|
updatedBy: context.state.currentUser.id,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user