fix: 审批, 自动刷新机制和撤回后更改子表格关联字段 (#1260)
Reviewed-on: daoyoucloud/tachybase#1260 Co-authored-by: bai.zixv <bai.zixv@foxmail.com> Co-committed-by: bai.zixv <bai.zixv@foxmail.com>
This commit is contained in:
		
							parent
							
								
									a15f5aedf0
								
							
						
					
					
						commit
						ef2e2c9beb
					
				@ -0,0 +1,19 @@
 | 
			
		||||
import { useActionContext, useAPIClient, useTableBlockContext } from '@tachybase/client';
 | 
			
		||||
 | 
			
		||||
// NOTE: 用于处理关闭弹窗, 和刷新外边显示的表格
 | 
			
		||||
export function useHandleRefresh(delay = 500) {
 | 
			
		||||
  const { service } = useTableBlockContext();
 | 
			
		||||
  const { setVisible, setSubmitted } = useActionContext() as any;
 | 
			
		||||
 | 
			
		||||
  const refreshTable = () => {
 | 
			
		||||
    setVisible(false);
 | 
			
		||||
    setSubmitted?.(true);
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      service.refresh();
 | 
			
		||||
    }, delay);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    refreshTable,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
@ -22,11 +22,24 @@ export const ViewActionLaunch = ({ popoverComponent = 'Action.Drawer', popoverCo
 | 
			
		||||
          drawer: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            'x-component': popoverComponent,
 | 
			
		||||
            'x-component-props': { className: 'nb-action-popup', ...popoverComponentProps },
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              className: 'nb-action-popup',
 | 
			
		||||
              ...popoverComponentProps,
 | 
			
		||||
            },
 | 
			
		||||
            properties: {
 | 
			
		||||
              content: Object.assign({ type: 'void' }, record.approvalId ? {} : { 'x-decorator': 'RecordDecorator' }, {
 | 
			
		||||
              content: Object.assign(
 | 
			
		||||
                {
 | 
			
		||||
                  type: 'void',
 | 
			
		||||
                },
 | 
			
		||||
                record.approvalId
 | 
			
		||||
                  ? {}
 | 
			
		||||
                  : {
 | 
			
		||||
                      'x-decorator': 'RecordDecorator',
 | 
			
		||||
                    },
 | 
			
		||||
                {
 | 
			
		||||
                  'x-component': 'ViewActionContent',
 | 
			
		||||
              }),
 | 
			
		||||
                },
 | 
			
		||||
              ),
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@ -58,8 +58,6 @@ export const ViewActionLaunchContent = () => {
 | 
			
		||||
  ) as any;
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  const approvalData = data?.data;
 | 
			
		||||
  const { approval, execution, ...approvalValue } = approvalData || {};
 | 
			
		||||
  const { workflow } = approval || {};
 | 
			
		||||
 | 
			
		||||
  if (loading) {
 | 
			
		||||
    return <Spin />;
 | 
			
		||||
@ -69,6 +67,9 @@ export const ViewActionLaunchContent = () => {
 | 
			
		||||
    return <Result status="error" title="Loading failed" />;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const { approval, execution, ...approvalValue } = approvalData || {};
 | 
			
		||||
  const { workflow } = approval || {};
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <FlowContextProvider
 | 
			
		||||
      value={{
 | 
			
		||||
 | 
			
		||||
@ -1,27 +1,30 @@
 | 
			
		||||
import { useActionContext, useAPIClient } from '@tachybase/client';
 | 
			
		||||
import { useAPIClient } from '@tachybase/client';
 | 
			
		||||
import { useField } from '@tachybase/schema';
 | 
			
		||||
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { useApproval } from '../../../approval-common/ApprovalData.provider';
 | 
			
		||||
import { useHandleRefresh } from '../../common/useHandleRefresh';
 | 
			
		||||
 | 
			
		||||
export function useDestroyAction() {
 | 
			
		||||
  const { refreshTable } = useHandleRefresh();
 | 
			
		||||
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const { setVisible, setSubmitted } = useActionContext() as any;
 | 
			
		||||
  const approval = useApproval();
 | 
			
		||||
  const apiClient = useAPIClient();
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    async run() {
 | 
			
		||||
      try {
 | 
			
		||||
        console.log('%c Line:16 🍓 run', 'font-size:18px;color:#6ec1c2;background:#93c0a4');
 | 
			
		||||
 | 
			
		||||
        _.set(field, ['data', 'loading'], true);
 | 
			
		||||
 | 
			
		||||
        await apiClient.resource('approvals').destroy({
 | 
			
		||||
          filterByTk: approval.id,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        setSubmitted(true);
 | 
			
		||||
        setVisible(false);
 | 
			
		||||
        refreshTable();
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        _.set(field, ['data', 'loading'], false);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -1,40 +1,43 @@
 | 
			
		||||
import { useActionContext, useAPIClient } from '@tachybase/client';
 | 
			
		||||
import { useAPIClient } from '@tachybase/client';
 | 
			
		||||
import { useField, useForm } from '@tachybase/schema';
 | 
			
		||||
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { useFlowContext } from '../../../../../../FlowContext';
 | 
			
		||||
import { useApproval } from '../../../approval-common/ApprovalData.provider';
 | 
			
		||||
import { useHandleRefresh } from '../../common/useHandleRefresh';
 | 
			
		||||
import { useContextApprovalStatus } from '../Pd.ApplyActionStatus';
 | 
			
		||||
 | 
			
		||||
export function useSubmit() {
 | 
			
		||||
  const from = useForm();
 | 
			
		||||
  const { refreshTable } = useHandleRefresh();
 | 
			
		||||
  const apiClient = useAPIClient();
 | 
			
		||||
 | 
			
		||||
  const form = useForm();
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const { setVisible, setSubmitted } = useActionContext() as any;
 | 
			
		||||
 | 
			
		||||
  const { id } = useApproval();
 | 
			
		||||
  const { workflow } = useFlowContext();
 | 
			
		||||
  const contextApprovalStatus = useContextApprovalStatus();
 | 
			
		||||
  const apiClient = useAPIClient();
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    async run() {
 | 
			
		||||
      try {
 | 
			
		||||
        from.submit();
 | 
			
		||||
 | 
			
		||||
        form.submit();
 | 
			
		||||
        _.set(field, ['data', 'loading'], true);
 | 
			
		||||
 | 
			
		||||
        apiClient.resource('approvals').update({
 | 
			
		||||
          filterByTk: id,
 | 
			
		||||
          values: {
 | 
			
		||||
            collectionName: workflow.config.collection,
 | 
			
		||||
            data: from.values,
 | 
			
		||||
            data: form.values,
 | 
			
		||||
            status: contextApprovalStatus,
 | 
			
		||||
            schemaFormId: workflow.config.applyForm,
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
        setSubmitted(true);
 | 
			
		||||
        setVisible(false);
 | 
			
		||||
        from.reset();
 | 
			
		||||
 | 
			
		||||
        form.reset();
 | 
			
		||||
        _.set(field, ['data', 'loading'], false);
 | 
			
		||||
        refreshTable();
 | 
			
		||||
      } catch (m) {
 | 
			
		||||
        _.set(field, ['data', 'loading'], false);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -1,30 +1,33 @@
 | 
			
		||||
import { useActionContext, useAPIClient } from '@tachybase/client';
 | 
			
		||||
import { useActionContext, useAPIClient, useTableBlockContext } from '@tachybase/client';
 | 
			
		||||
import { useField } from '@tachybase/schema';
 | 
			
		||||
 | 
			
		||||
import { useApproval } from '../../../approval-common/ApprovalData.provider';
 | 
			
		||||
import { useHandleRefresh } from '../../common/useHandleRefresh';
 | 
			
		||||
 | 
			
		||||
// 撤回
 | 
			
		||||
export function useWithdrawAction() {
 | 
			
		||||
  const { refreshTable } = useHandleRefresh(100);
 | 
			
		||||
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const { setVisible, setSubmitted } = useActionContext() as any;
 | 
			
		||||
  const approval = useApproval();
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    async run() {
 | 
			
		||||
      try {
 | 
			
		||||
        field.data = field.data ?? {};
 | 
			
		||||
 | 
			
		||||
        field.data.loading = true;
 | 
			
		||||
 | 
			
		||||
        await api.resource('approvals').withdraw({
 | 
			
		||||
          filterByTk: approval.id,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        setVisible(false);
 | 
			
		||||
 | 
			
		||||
        setSubmitted(true);
 | 
			
		||||
        // setSubmitted(true);
 | 
			
		||||
 | 
			
		||||
        field.data.loading = false;
 | 
			
		||||
        refreshTable();
 | 
			
		||||
      } catch (v) {
 | 
			
		||||
        console.log('%c Line:33 🌽 v', 'font-size:18px;color:#33a5ff;background:#fca650', v);
 | 
			
		||||
        if (field.data) {
 | 
			
		||||
          field.data.loading = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1,36 +1,39 @@
 | 
			
		||||
import { useActionContext, useAPIClient, useRefreshActionProps } from '@tachybase/client';
 | 
			
		||||
import { useAPIClient } from '@tachybase/client';
 | 
			
		||||
import { useField, useForm } from '@tachybase/schema';
 | 
			
		||||
 | 
			
		||||
import { useHandleRefresh } from '../../common/useHandleRefresh';
 | 
			
		||||
import { useContextApprovalAction } from '../Pd.ApprovalAction';
 | 
			
		||||
import { useContextApprovalExecutions } from '../Pd.ApprovalExecutions';
 | 
			
		||||
 | 
			
		||||
export function useSubmit() {
 | 
			
		||||
  const { refreshTable } = useHandleRefresh();
 | 
			
		||||
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
  const form = useForm();
 | 
			
		||||
  const approvalExecutions = useContextApprovalExecutions();
 | 
			
		||||
  const { status } = useContextApprovalAction();
 | 
			
		||||
  const { setVisible, setSubmitted } = useActionContext() as any;
 | 
			
		||||
  // TODO: 自动更新外层block, 提升交互体验
 | 
			
		||||
  // const { onClick: refreshAction } = useRefreshActionProps();
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    run: async () => {
 | 
			
		||||
      try {
 | 
			
		||||
        if (form.values.status) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await form.submit();
 | 
			
		||||
        field.data = field.data ?? {};
 | 
			
		||||
        field.data.loading = true;
 | 
			
		||||
        setVisible(false);
 | 
			
		||||
 | 
			
		||||
        await api.resource('approvalRecords').submit({
 | 
			
		||||
          filterByTk: approvalExecutions.id,
 | 
			
		||||
          values: { ...form.values, status },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        field.data.loading = false;
 | 
			
		||||
        await form.reset();
 | 
			
		||||
        // refreshAction?.();
 | 
			
		||||
        setSubmitted?.(true);
 | 
			
		||||
 | 
			
		||||
        refreshTable();
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        field.data && (field.data.loading = false);
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ import { parseCollectionName } from '@tachybase/data-source-manager';
 | 
			
		||||
import { EXECUTION_STATUS, JOB_STATUS, PluginWorkflow } from '../..';
 | 
			
		||||
import { APPROVAL_ACTION_STATUS, APPROVAL_STATUS } from './constants';
 | 
			
		||||
import { getSummary } from './tools';
 | 
			
		||||
import { getAssociationName, jsonParse } from './utils';
 | 
			
		||||
 | 
			
		||||
const workflows = {
 | 
			
		||||
  async listApprovalFlows(context, next) {
 | 
			
		||||
@ -71,13 +72,27 @@ const approvals = {
 | 
			
		||||
    return actions.create(context, next);
 | 
			
		||||
  },
 | 
			
		||||
  async update(context, next) {
 | 
			
		||||
    const { collectionName, data, status } = context.action.params.values ?? {};
 | 
			
		||||
    const { collectionName, data, status, schemaFormId } = context.action.params.values ?? {};
 | 
			
		||||
 | 
			
		||||
    const [dataSourceName, cName] = parseCollectionName(collectionName);
 | 
			
		||||
    const dataSource = context.app.dataSourceManager.dataSources.get(dataSourceName);
 | 
			
		||||
    const collection = dataSource.collectionManager.getCollection(cName);
 | 
			
		||||
 | 
			
		||||
    /** 以下为,处理子表单子表格等关联字段的更新逻辑 */
 | 
			
		||||
    const schemaOfForm = await context.db.getRepository('uiSchemas').getJsonSchema(schemaFormId);
 | 
			
		||||
    const itemsOfSchema = await jsonParse(`**["x-component-props".mode]`, schemaOfForm);
 | 
			
		||||
    const fieldAssociationName = itemsOfSchema
 | 
			
		||||
      .filter((item) => {
 | 
			
		||||
        return ['Nester', 'SubTable', 'PopoverNester'].includes(item?.['x-component-props']?.mode);
 | 
			
		||||
      })
 | 
			
		||||
      .map((item) => getAssociationName(item['x-collection-field']));
 | 
			
		||||
    const updateAssociationValues = [...new Set(fieldAssociationName)];
 | 
			
		||||
    /** 以上为,处理子表单子表格等关联字段的更新逻辑 */
 | 
			
		||||
 | 
			
		||||
    const [target] = await collection.repository.update({
 | 
			
		||||
      filterByTk: data[collection.filterTargetKey],
 | 
			
		||||
      values: data,
 | 
			
		||||
      updateAssociationValues,
 | 
			
		||||
    });
 | 
			
		||||
    context.action.mergeParams({
 | 
			
		||||
      values: {
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,14 @@
 | 
			
		||||
import jsonata from 'jsonata';
 | 
			
		||||
 | 
			
		||||
export function getAssociationName(str) {
 | 
			
		||||
  const lastIndex = str.lastIndexOf('.');
 | 
			
		||||
  if (lastIndex !== -1) {
 | 
			
		||||
    return str.substring(lastIndex + 1);
 | 
			
		||||
  }
 | 
			
		||||
  return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function jsonParse(expression, scope) {
 | 
			
		||||
  const result = jsonata(expression).evaluate(scope);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user