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:
sealday 2024-07-09 03:53:01 +08:00
parent 0b958cf528
commit 1d5306d427
17 changed files with 268 additions and 304 deletions

View File

@ -38,3 +38,5 @@ export default class DatabaseUtils {
return this.db.options.schema || 'public'; return this.db.options.schema || 'public';
} }
} }
export * from './traverseJSON';

View 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;
};

View File

@ -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';

View File

@ -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;
};

View File

@ -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());
});

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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>;
} }

View File

@ -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;
} }

View File

@ -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>

View File

@ -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,
}} }}

View File

@ -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);
} }
}, },

View File

@ -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;
}
}
}, },
}; };
} }

View File

@ -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;

View File

@ -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);

View File

@ -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);
};

View File

@ -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,
}, },