钉钉回调事件处理
This commit is contained in:
@@ -11,6 +11,9 @@ import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { filterObj } from '/@/utils/common/compUtils';
|
||||
import { isFunction } from '@/utils/is';
|
||||
import { registerImPageListProvider } from '/@/views/system/im/imPageListRegistry';
|
||||
//update-begin---author:GHT ---date:20260609 for:【审批注册中心】列表页静态注入审批痕迹列(默认隐藏)-----------
|
||||
import { traceColumns } from '/@/views/xslmes/approval/integration/traceColumns';
|
||||
//update-end---author:GHT ---date:20260609 for:【审批注册中心】列表页静态注入审批痕迹列(默认隐藏)-----------
|
||||
//update-begin---author:GHT ---date:2026-05-29 for:【QH-MES审批流设计】列表选中行同步到审批发起上下文-----
|
||||
import { useApprovalSelection } from '/@/components/ApprovalLaunch/useApprovalSelection';
|
||||
//update-end---author:GHT ---date:2026-05-29 for:【QH-MES审批流设计】列表选中行同步到审批发起上下文-----
|
||||
@@ -573,6 +576,14 @@ export function useListTable(tableProps: TableProps): [
|
||||
}
|
||||
}
|
||||
|
||||
//update-begin---author:GHT ---date:20260609 for:【审批注册中心】静态追加审批痕迹列(默认隐藏),无需注册中心判断-----------
|
||||
const existingCols: any[] = (defaultTableProps.columns as any[]) ?? [];
|
||||
const hasTrace = existingCols.some((c) => String(c.dataIndex ?? '').startsWith('trace'));
|
||||
if (!hasTrace) {
|
||||
defaultTableProps.columns = [...existingCols, ...traceColumns];
|
||||
}
|
||||
//update-end---author:GHT ---date:20260609 for:【审批注册中心】静态追加审批痕迹列(默认隐藏),无需注册中心判断-----------
|
||||
|
||||
return [
|
||||
...useTable(defaultTableProps),
|
||||
{
|
||||
|
||||
@@ -383,6 +383,10 @@
|
||||
};
|
||||
// 清空历史 HTTP 回调配置,避免与集成方案双写
|
||||
form.value.props.callbackActions = { onNodeApprove: [], onApprove: [], onReject: [] };
|
||||
// update-begin---author:GHT ---date:2026-06-09 for:【审批流设计】打开节点配置时强制刷新集成方案下拉,避免先开设计器后生成方案导致缓存空值-----
|
||||
integrationPlansCacheKey.value = '';
|
||||
loadIntegrationPlans();
|
||||
// update-end---author:GHT ---date:2026-06-09 for:【审批流设计】打开节点配置时强制刷新集成方案下拉,避免先开设计器后生成方案导致缓存空值-----
|
||||
}
|
||||
open.value = true;
|
||||
}
|
||||
|
||||
@@ -2,13 +2,6 @@ import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||
|
||||
const STAGE_DICT = 'mes_xsl_approval_stage';
|
||||
|
||||
function hasStage(values: Recordable, stage: string) {
|
||||
const raw = values?.enabledStages;
|
||||
if (!raw) return false;
|
||||
if (Array.isArray(raw)) return raw.includes(stage);
|
||||
return String(raw).split(',').includes(stage);
|
||||
}
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{ title: '业务编码', dataIndex: 'docCode', width: 140, align: 'left' },
|
||||
{ title: '物理表名', dataIndex: 'tableName', width: 200, align: 'left' },
|
||||
@@ -84,46 +77,11 @@ export const formSchema: FormSchema[] = [
|
||||
componentProps: { placeholder: '默认 status' },
|
||||
},
|
||||
{
|
||||
label: '校对人字段',
|
||||
field: 'proofreadByField',
|
||||
label: '列表接口路径',
|
||||
field: 'listApiPath',
|
||||
component: 'Input',
|
||||
defaultValue: 'proofread_by',
|
||||
ifShow: ({ values }) => hasStage(values, 'proofread'),
|
||||
},
|
||||
{
|
||||
label: '校对时间字段',
|
||||
field: 'proofreadTimeField',
|
||||
component: 'Input',
|
||||
defaultValue: 'proofread_time',
|
||||
ifShow: ({ values }) => hasStage(values, 'proofread'),
|
||||
},
|
||||
{
|
||||
label: '审核人字段',
|
||||
field: 'auditByField',
|
||||
component: 'Input',
|
||||
defaultValue: 'audit_by',
|
||||
ifShow: ({ values }) => hasStage(values, 'audit'),
|
||||
},
|
||||
{
|
||||
label: '审核时间字段',
|
||||
field: 'auditTimeField',
|
||||
component: 'Input',
|
||||
defaultValue: 'audit_time',
|
||||
ifShow: ({ values }) => hasStage(values, 'audit'),
|
||||
},
|
||||
{
|
||||
label: '批准人字段',
|
||||
field: 'approveByField',
|
||||
component: 'Input',
|
||||
defaultValue: 'approve_by',
|
||||
ifShow: ({ values }) => hasStage(values, 'approve'),
|
||||
},
|
||||
{
|
||||
label: '批准时间字段',
|
||||
field: 'approveTimeField',
|
||||
component: 'Input',
|
||||
defaultValue: 'approve_time',
|
||||
ifShow: ({ values }) => hasStage(values, 'approve'),
|
||||
slot: 'listApiPath',
|
||||
helpMessage: '从二级菜单选取后自动填入路径;配置后列表响应自动追加 traceProofreadBy / traceAuditBy / traceApproveBy 等6个字段',
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
{ title: '流程节点', dataIndex: 'nodeName', width: 200 },
|
||||
{ title: '识别环节', dataIndex: 'stage', width: 130 },
|
||||
{ title: '前置状态', dataIndex: 'expectedFromLabel', width: 90 },
|
||||
{ title: '通过后状态', dataIndex: 'statusAfterLabel', width: 100 },
|
||||
{ title: '生成方案', dataIndex: 'willGenerate', width: 88 },
|
||||
{ title: '未配置原因', dataIndex: 'unconfiguredReason', ellipsis: true },
|
||||
];
|
||||
@@ -182,6 +183,12 @@
|
||||
return '环节未完整配置';
|
||||
}
|
||||
|
||||
function resolveStatusAfter(stage?: string, statusChain?: any[]) {
|
||||
if (!stage) return null;
|
||||
const hit = (statusChain || []).find((item) => item.value === stage);
|
||||
return hit ? stage : null;
|
||||
}
|
||||
|
||||
function resolveExpectedFrom(bindings: any[], index: number, statusChain: any[], initialStatus: string) {
|
||||
const current = bindings[index];
|
||||
if (!current?.stage) {
|
||||
@@ -226,6 +233,8 @@
|
||||
record.triggerPhase = null;
|
||||
record.expectedFrom = null;
|
||||
record.expectedFromLabel = '-';
|
||||
record.statusAfter = null;
|
||||
record.statusAfterLabel = '-';
|
||||
return;
|
||||
}
|
||||
const cfgIdx = configuredBindings.indexOf(record);
|
||||
@@ -234,6 +243,9 @@
|
||||
const expectedFrom = resolveExpectedFrom(bindings, bindings.indexOf(record), statusChain, initialStatus);
|
||||
record.expectedFrom = expectedFrom;
|
||||
record.expectedFromLabel = labelOfStatusChain(statusChain, expectedFrom);
|
||||
const statusAfter = resolveStatusAfter(record.stage, statusChain);
|
||||
record.statusAfter = statusAfter;
|
||||
record.statusAfterLabel = statusAfter ? labelOfStatusChain(statusChain, statusAfter) : '需手配';
|
||||
});
|
||||
|
||||
preview.value.configuredNodeCount = configuredBindings.length;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="640" @ok="handleSubmit">
|
||||
<BasicForm @register="registerForm" />
|
||||
<BasicForm @register="registerForm">
|
||||
<template #listApiPath="{ model, field }">
|
||||
<RegistryMenuSelect :value="model[field]" @change="(val) => (model[field] = val)" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
@@ -10,6 +14,7 @@
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from '../MesXslBizDocRegistry.data';
|
||||
import { saveOrUpdate } from '../MesXslBizDocRegistry.api';
|
||||
import RegistryMenuSelect from './RegistryMenuSelect.vue';
|
||||
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
const isUpdate = ref(false);
|
||||
|
||||
@@ -96,10 +96,11 @@
|
||||
if (record.actionType === 'REGISTRY_STAGE_SYNC') {
|
||||
const stage = cfg.registryStage?.stage || cfg.stage;
|
||||
const from = cfg.registryStage?.expectedFrom || cfg.expectedFrom;
|
||||
return `环节→${STAGE_LABELS[stage] || stage || '?'}${from ? `,前置=${from}` : ''}`;
|
||||
const after = cfg.registryStage?.statusAfter || cfg.statusAfter || stage;
|
||||
return `环节→${STAGE_LABELS[stage] || stage || '?'}${from ? `,前置=${from}` : ''},通过后=${after}`;
|
||||
}
|
||||
const target = cfg.registryStage?.targetStage || cfg.targetStage || 'compile';
|
||||
return `回退→${target}`;
|
||||
const target = cfg.registryStage?.targetStage ?? cfg.targetStage;
|
||||
return target !== undefined && target !== null && target !== '' ? `回退→${target}` : '回退→未配置';
|
||||
} catch {
|
||||
return record.actionConfig || '-';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-select
|
||||
:value="selectedPaths"
|
||||
mode="multiple"
|
||||
allow-clear
|
||||
show-search
|
||||
placeholder="从二级菜单选取,自动填入列表接口路径;也可在下方直接编辑"
|
||||
:filter-option="filterOption"
|
||||
style="width: 100%"
|
||||
@change="handleSelectChange"
|
||||
>
|
||||
<a-select-opt-group v-for="group in menuGroups" :key="group.path" :label="group.title">
|
||||
<a-select-option
|
||||
v-for="item in group.children"
|
||||
:key="item.apiPath"
|
||||
:value="item.apiPath"
|
||||
:title="item.apiPath"
|
||||
>
|
||||
<span>{{ item.title }}</span>
|
||||
<span style="margin-left: 8px; color: #8c8c8c; font-size: 11px">{{ item.apiPath }}</span>
|
||||
</a-select-option>
|
||||
</a-select-opt-group>
|
||||
</a-select>
|
||||
|
||||
<a-input
|
||||
:value="inputVal"
|
||||
style="margin-top: 6px"
|
||||
placeholder="列表接口路径(多个逗号分隔,可手动编辑)"
|
||||
@change="handleInputChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { usePermissionStoreWithOut } from '/@/store/modules/permission';
|
||||
import type { Menu } from '/@/router/types';
|
||||
|
||||
interface MenuGroup {
|
||||
path: string;
|
||||
title: string;
|
||||
children: { apiPath: string; title: string; path: string }[];
|
||||
}
|
||||
|
||||
const props = defineProps<{ value?: string }>();
|
||||
const emit = defineEmits(['change', 'update:value']);
|
||||
|
||||
const permStore = usePermissionStoreWithOut();
|
||||
|
||||
const menuGroups = computed<MenuGroup[]>(() => {
|
||||
const list = permStore.getBackMenuList as Menu[];
|
||||
if (!list || list.length === 0) return [];
|
||||
const groups: MenuGroup[] = [];
|
||||
for (const parent of list) {
|
||||
if (!parent.children || parent.children.length === 0) continue;
|
||||
const leafChildren = parent.children.filter((c) => !c.hideMenu);
|
||||
if (leafChildren.length === 0) continue;
|
||||
groups.push({
|
||||
path: parent.path,
|
||||
title: (parent.meta?.title as string) || parent.name,
|
||||
children: leafChildren.map((c) => ({
|
||||
path: c.path,
|
||||
apiPath: c.path + '/list',
|
||||
title: (c.meta?.title as string) || c.name,
|
||||
})),
|
||||
});
|
||||
}
|
||||
return groups;
|
||||
});
|
||||
|
||||
const allApiPaths = computed<string[]>(() =>
|
||||
menuGroups.value.flatMap((g) => g.children.map((c) => c.apiPath)),
|
||||
);
|
||||
|
||||
// 当前文本框的值(原始逗号分隔串)
|
||||
const inputVal = ref(props.value || '');
|
||||
|
||||
// 从文本框值解析出在 menuGroups 里的路径(用于 Select 的高亮选中)
|
||||
const selectedPaths = computed<string[]>(() => {
|
||||
if (!inputVal.value) return [];
|
||||
return inputVal.value
|
||||
.split(',')
|
||||
.map((p) => p.trim())
|
||||
.filter((p) => allApiPaths.value.includes(p));
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(val) => {
|
||||
inputVal.value = val || '';
|
||||
},
|
||||
);
|
||||
|
||||
function handleSelectChange(vals: string[]) {
|
||||
// 将已有的手动路径(不在菜单里的)保留,把菜单选取结果合并进去
|
||||
const manualPaths = inputVal.value
|
||||
.split(',')
|
||||
.map((p) => p.trim())
|
||||
.filter((p) => p && !allApiPaths.value.includes(p));
|
||||
const merged = [...manualPaths, ...vals].filter(Boolean).join(',');
|
||||
inputVal.value = merged;
|
||||
emit('change', merged);
|
||||
emit('update:value', merged);
|
||||
}
|
||||
|
||||
function handleInputChange(e: Event) {
|
||||
const val = (e.target as HTMLInputElement).value;
|
||||
inputVal.value = val;
|
||||
emit('change', val);
|
||||
emit('update:value', val);
|
||||
}
|
||||
|
||||
function filterOption(input: string, option: any) {
|
||||
const title = option?.children?.[0]?.children || '';
|
||||
const path = option.value || '';
|
||||
const lc = input.toLowerCase();
|
||||
return String(title).toLowerCase().includes(lc) || String(path).toLowerCase().includes(lc);
|
||||
}
|
||||
</script>
|
||||
@@ -58,7 +58,7 @@
|
||||
type="info"
|
||||
show-icon
|
||||
style="margin-bottom: 14px"
|
||||
message="按审批注册中心配置自动更新源单状态、操作人/时间,并双写审批痕迹明细,无需绑定 Java 校对/审核/批准接口。"
|
||||
message="审批环节仅用于匹配审批流与写入痕迹;业务表 status 由「通过后状态」控制。操作人/时间写入痕迹表,无需绑定 Java 接口。"
|
||||
/>
|
||||
<template v-if="vc.registryStage">
|
||||
<a-form-item v-if="vc.visualType === 'REGISTRY_STAGE_SYNC'" label="审批环节" required>
|
||||
@@ -73,6 +73,9 @@
|
||||
<div v-if="!registryStageOptions.length" style="font-size: 12px; color: #faad14; margin-top: 4px">
|
||||
未配置启用环节,请先在审批注册中心配置 enabled_stages
|
||||
</div>
|
||||
<div v-else style="font-size: 12px; color: #888; margin-top: 4px">
|
||||
仅参与审批流匹配与痕迹同步(proofread/audit/approve),不会直接写入业务表 status。
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="vc.visualType === 'REGISTRY_STAGE_SYNC'" label="前置状态">
|
||||
<a-select
|
||||
@@ -88,24 +91,45 @@
|
||||
<a-input
|
||||
v-else
|
||||
v-model:value="vc.registryStage.expectedFrom"
|
||||
placeholder="未解析到状态字典,可手填 compile / proofread / audit"
|
||||
placeholder="未解析到状态字典,可手填状态字典值"
|
||||
/>
|
||||
<div style="font-size: 12px; color: #888; margin-top: 4px">
|
||||
取自触发表「{{ sourceStatusFieldName }}」字段字典{{ sourceStatusDictCode ? `(${sourceStatusDictCode})` : '' }};留空则自动推断。仅当前状态等于此前置值时才执行。
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="vc.visualType === 'REGISTRY_STAGE_REVERT'" label="回退目标">
|
||||
<a-form-item v-if="vc.visualType === 'REGISTRY_STAGE_SYNC'" label="通过后状态" required>
|
||||
<a-select
|
||||
v-if="sourceStatusDictItems.length"
|
||||
v-model:value="vc.registryStage.targetStage"
|
||||
v-model:value="vc.registryStage.statusAfter"
|
||||
:options="sourceStatusDictItems"
|
||||
placeholder="默认 compile(编制态)"
|
||||
allow-clear
|
||||
placeholder="请选择本环节通过后业务表应变为的状态"
|
||||
show-search
|
||||
option-filter-prop="label"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<a-input v-else v-model:value="vc.registryStage.targetStage" placeholder="默认 compile(编制态)" />
|
||||
<a-input
|
||||
v-else
|
||||
v-model:value="vc.registryStage.statusAfter"
|
||||
placeholder="未解析到状态字典,可手填业务状态值"
|
||||
/>
|
||||
<div style="font-size: 12px; color: #888; margin-top: 4px">
|
||||
本环节审批通过后,将触发表「{{ sourceStatusFieldName }}」更新为此值(与审批环节码无关,按各单据自己的状态字典配置)。
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="vc.visualType === 'REGISTRY_STAGE_REVERT'" label="回退目标" required>
|
||||
<a-select
|
||||
v-if="sourceStatusDictItems.length"
|
||||
v-model:value="vc.registryStage.targetStage"
|
||||
:options="sourceStatusDictItems"
|
||||
placeholder="请选择驳回后回退到的业务状态"
|
||||
show-search
|
||||
option-filter-prop="label"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<a-input v-else v-model:value="vc.registryStage.targetStage" placeholder="未解析到状态字典,可手填字典键值(item_value)" />
|
||||
<div style="font-size: 12px; color: #888; margin-top: 4px">
|
||||
保存为字典键值(item_value),执行时原样写入触发表「{{ sourceStatusFieldName }}」,与界面显示文字无关。
|
||||
</div>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</template>
|
||||
@@ -305,6 +329,7 @@
|
||||
interface RegistryStageConfig {
|
||||
stage?: string;
|
||||
expectedFrom?: string;
|
||||
statusAfter?: string;
|
||||
targetStage?: string;
|
||||
}
|
||||
|
||||
@@ -321,10 +346,18 @@
|
||||
const emit = defineEmits<{ success: [action: any] }>();
|
||||
const { createMessage } = useMessage();
|
||||
|
||||
/** 审批环节码固定中文名(与业务 status 字典无关) */
|
||||
const APPROVAL_STAGE_LABELS: Record<string, string> = {
|
||||
proofread: '校对',
|
||||
audit: '审核',
|
||||
approve: '批准',
|
||||
};
|
||||
|
||||
/** 触发表 status 字段未带字典注释时的兜底映射 */
|
||||
const SOURCE_TABLE_STATUS_DICT: Record<string, string> = {
|
||||
mes_xsl_mixer_ps_compile: 'xslmes_mixer_ps_status',
|
||||
mes_xsl_formula_spec: 'xslmes_formula_spec_status',
|
||||
mes_xsl_raw_material_entry: 'xslmes_entry_status',
|
||||
};
|
||||
|
||||
/** 目标表 status 字段未带字典注释时的兜底映射 */
|
||||
@@ -362,7 +395,7 @@
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
.map((v) => ({ value: v, label: dictLabelMap[v] || v }));
|
||||
.map((v) => ({ value: v, label: APPROVAL_STAGE_LABELS[v] || dictLabelMap[v] || v }));
|
||||
});
|
||||
const targetColumns = ref<ColMeta[]>([]);
|
||||
|
||||
@@ -387,6 +420,7 @@
|
||||
const defaultRegistryStage = (): RegistryStageConfig => ({
|
||||
stage: '',
|
||||
expectedFrom: '',
|
||||
statusAfter: '',
|
||||
targetStage: '',
|
||||
});
|
||||
|
||||
@@ -428,7 +462,12 @@
|
||||
if (parsed.expectedFrom !== undefined && parsed.expectedFrom !== null) {
|
||||
merged.registryStage!.expectedFrom = parsed.expectedFrom;
|
||||
}
|
||||
if (parsed.targetStage) merged.registryStage!.targetStage = parsed.targetStage;
|
||||
if (parsed.statusAfter !== undefined && parsed.statusAfter !== null) {
|
||||
merged.registryStage!.statusAfter = parsed.statusAfter;
|
||||
}
|
||||
if (parsed.targetStage !== undefined && parsed.targetStage !== null) {
|
||||
merged.registryStage!.targetStage = parsed.targetStage;
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
@@ -461,7 +500,7 @@
|
||||
},
|
||||
);
|
||||
|
||||
// 审批环节变化时,前置状态留空则填入默认推断值
|
||||
// 审批环节变化时,前置/通过后状态留空则填入默认推断值
|
||||
watch(
|
||||
() => vc.value.registryStage?.stage,
|
||||
(stage) => {
|
||||
@@ -469,6 +508,9 @@
|
||||
if (!vc.value.registryStage.expectedFrom) {
|
||||
vc.value.registryStage.expectedFrom = defaultExpectedFromForStage(stage);
|
||||
}
|
||||
if (!vc.value.registryStage.statusAfter) {
|
||||
vc.value.registryStage.statusAfter = defaultStatusAfterForStage(stage);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -548,6 +590,16 @@
|
||||
return items.length ? items[0].value : '';
|
||||
}
|
||||
|
||||
/** 推断通过后业务状态:字典含环节码时用环节码,否则不自动填充(需用户手选) */
|
||||
function defaultStatusAfterForStage(stage?: string): string {
|
||||
if (!stage) return '';
|
||||
const items = sourceStatusDictItems.value;
|
||||
if (items.some((i) => i.value === stage)) {
|
||||
return stage;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function defaultRevertTargetStage(): string {
|
||||
const items = sourceStatusDictItems.value;
|
||||
if (!items.length) return 'compile';
|
||||
@@ -565,7 +617,12 @@
|
||||
if (config.registryStage?.expectedFrom !== undefined && config.registryStage?.expectedFrom !== null) {
|
||||
payload.expectedFrom = config.registryStage.expectedFrom;
|
||||
}
|
||||
if (config.registryStage?.targetStage) payload.targetStage = config.registryStage.targetStage;
|
||||
if (config.registryStage?.statusAfter !== undefined && config.registryStage?.statusAfter !== null) {
|
||||
payload.statusAfter = config.registryStage.statusAfter;
|
||||
}
|
||||
if (config.registryStage?.targetStage !== undefined && config.registryStage?.targetStage !== null) {
|
||||
payload.targetStage = config.registryStage.targetStage;
|
||||
}
|
||||
return JSON.stringify(payload);
|
||||
}
|
||||
|
||||
@@ -607,6 +664,7 @@
|
||||
if (type === 'REGISTRY_STAGE_SYNC' && registryStageOptions.value.length && !vc.value.registryStage?.stage) {
|
||||
vc.value.registryStage!.stage = registryStageOptions.value[0].value;
|
||||
vc.value.registryStage!.expectedFrom = defaultExpectedFromForStage(vc.value.registryStage!.stage);
|
||||
vc.value.registryStage!.statusAfter = defaultStatusAfterForStage(vc.value.registryStage!.stage);
|
||||
}
|
||||
if (type === 'REGISTRY_STAGE_REVERT' && !vc.value.registryStage?.targetStage) {
|
||||
vc.value.registryStage!.targetStage = defaultRevertTargetStage();
|
||||
@@ -687,6 +745,7 @@
|
||||
if (registryStageOptions.value.length) {
|
||||
vc.value.registryStage!.stage = registryStageOptions.value[0].value;
|
||||
vc.value.registryStage!.expectedFrom = defaultExpectedFromForStage(vc.value.registryStage!.stage);
|
||||
vc.value.registryStage!.statusAfter = defaultStatusAfterForStage(vc.value.registryStage!.stage);
|
||||
}
|
||||
vc.value.registryStage!.targetStage = defaultRevertTargetStage();
|
||||
formRef.value?.clearValidate?.();
|
||||
@@ -702,6 +761,10 @@
|
||||
createMessage.warning('请选择审批环节');
|
||||
return;
|
||||
}
|
||||
if (!vc.value.registryStage?.statusAfter) {
|
||||
createMessage.warning('请选择通过后状态');
|
||||
return;
|
||||
}
|
||||
emit('success', {
|
||||
...form.value,
|
||||
actionType: 'REGISTRY_STAGE_SYNC',
|
||||
@@ -712,6 +775,10 @@
|
||||
return;
|
||||
}
|
||||
if (vc.value.visualType === 'REGISTRY_STAGE_REVERT') {
|
||||
if (vc.value.registryStage?.targetStage === undefined || vc.value.registryStage?.targetStage === null || vc.value.registryStage?.targetStage === '') {
|
||||
createMessage.warning('请选择回退目标(业务状态字典项)');
|
||||
return;
|
||||
}
|
||||
emit('success', {
|
||||
...form.value,
|
||||
actionType: 'REGISTRY_STAGE_REVERT',
|
||||
@@ -777,10 +844,19 @@
|
||||
}
|
||||
|
||||
await loadSourceStatusDict();
|
||||
// 旧数据兼容:未配置 statusAfter 时,若字典含环节码则回填,否则保持空由用户手选
|
||||
if (isUpdate.value && vc.value.registryStage?.stage && !vc.value.registryStage?.statusAfter) {
|
||||
const legacy = defaultStatusAfterForStage(vc.value.registryStage.stage);
|
||||
if (legacy) {
|
||||
vc.value.registryStage.statusAfter = legacy;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isUpdate.value) {
|
||||
if (registryStageOptions.value.length && !vc.value.registryStage?.stage) {
|
||||
vc.value.registryStage!.stage = registryStageOptions.value[0].value;
|
||||
vc.value.registryStage!.expectedFrom = defaultExpectedFromForStage(vc.value.registryStage!.stage);
|
||||
vc.value.registryStage!.statusAfter = defaultStatusAfterForStage(vc.value.registryStage!.stage);
|
||||
}
|
||||
if (!vc.value.registryStage?.targetStage) {
|
||||
vc.value.registryStage!.targetStage = defaultRevertTargetStage();
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { BasicColumn } from '/@/components/Table';
|
||||
|
||||
/**
|
||||
* 按 sentinel key 分组的审批痕迹列。
|
||||
* key = 后端注入的字段名(traceProofreadBy / traceAuditBy / traceApproveBy)
|
||||
* 只要响应里出现该 key,就注入对应两列。
|
||||
*/
|
||||
export const traceColumnsByStage: Record<string, BasicColumn[]> = {
|
||||
traceProofreadBy: [
|
||||
{ title: '校对人', dataIndex: 'traceProofreadBy', width: 100, align: 'center', defaultHidden: true },
|
||||
{ title: '校对时间', dataIndex: 'traceProofreadTime', width: 165, align: 'center', defaultHidden: true },
|
||||
],
|
||||
traceAuditBy: [
|
||||
{ title: '审核人', dataIndex: 'traceAuditBy', width: 100, align: 'center', defaultHidden: true },
|
||||
{ title: '审核时间', dataIndex: 'traceAuditTime', width: 165, align: 'center', defaultHidden: true },
|
||||
],
|
||||
traceApproveBy: [
|
||||
{ title: '批准人', dataIndex: 'traceApproveBy', width: 100, align: 'center', defaultHidden: true },
|
||||
{ title: '批准时间', dataIndex: 'traceApproveTime', width: 165, align: 'center', defaultHidden: true },
|
||||
],
|
||||
};
|
||||
|
||||
/** 全量痕迹列(密炼PS等已知需要全部的场景直接引用) */
|
||||
export const traceColumns: BasicColumn[] = Object.values(traceColumnsByStage).flat();
|
||||
@@ -0,0 +1,16 @@
|
||||
import { useTable } from '/@/components/Table';
|
||||
import type { BasicTableProps } from '/@/components/Table';
|
||||
import { traceColumns } from './traceColumns';
|
||||
|
||||
/**
|
||||
* 替换 useTable(不经过 useListPage 的特殊场景):自动追加审批痕迹列(默认隐藏)。
|
||||
* 普通列表页已由 useListPage 统一注入,无需使用本函数。
|
||||
*/
|
||||
export function useTraceTable(tableProps: BasicTableProps) {
|
||||
const columns = tableProps.columns as any[] | undefined;
|
||||
const alreadyHasTrace = columns?.some((c) => c.dataIndex === 'traceProofreadBy');
|
||||
return useTable({
|
||||
...tableProps,
|
||||
columns: alreadyHasTrace ? columns : [...(columns ?? []), ...traceColumns],
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const { createConfirm } = useMessage();
|
||||
|
||||
enum Api {
|
||||
list = '/xslmes/mesXslDingCallbackLog/list',
|
||||
save = '/xslmes/mesXslDingCallbackLog/add',
|
||||
edit = '/xslmes/mesXslDingCallbackLog/edit',
|
||||
deleteOne = '/xslmes/mesXslDingCallbackLog/delete',
|
||||
deleteBatch = '/xslmes/mesXslDingCallbackLog/deleteBatch',
|
||||
exportXlsUrl = '/xslmes/mesXslDingCallbackLog/exportXls',
|
||||
importExcelUrl = '/xslmes/mesXslDingCallbackLog/importExcel',
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表分页查询
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 删除单条
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存或新增
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
const url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url, params });
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出 XLS
|
||||
*/
|
||||
export const getExportUrl = Api.exportXlsUrl;
|
||||
|
||||
/**
|
||||
* 导入 XLS
|
||||
*/
|
||||
export const getImportUrl = Api.importExcelUrl;
|
||||
@@ -0,0 +1,158 @@
|
||||
import { BasicColumn } from '/@/components/Table';
|
||||
import { FormSchema } from '/@/components/Form';
|
||||
import { rules } from '/@/utils/helper/validator';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '钉钉事件ID',
|
||||
align: 'center',
|
||||
dataIndex: 'eventId',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '事件类型',
|
||||
align: 'center',
|
||||
dataIndex: 'eventType',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
title: '审批实例ID',
|
||||
align: 'center',
|
||||
dataIndex: 'processInstanceId',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '接收时间',
|
||||
align: 'center',
|
||||
dataIndex: 'receivedTime',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
title: '是否已处理',
|
||||
align: 'center',
|
||||
dataIndex: 'processed_dictText',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '关联业务表',
|
||||
align: 'center',
|
||||
dataIndex: 'bizTable',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '关联业务记录ID',
|
||||
align: 'center',
|
||||
dataIndex: 'bizDataId',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
title: '关联审批台账ID',
|
||||
align: 'center',
|
||||
dataIndex: 'recordId',
|
||||
width: 160,
|
||||
},
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '事件类型',
|
||||
field: 'eventType',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
label: '审批实例ID',
|
||||
field: 'processInstanceId',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
label: '是否已处理',
|
||||
field: 'processed',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: { dictCode: 'yn' },
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
label: '接收时间',
|
||||
field: 'receivedTime',
|
||||
component: 'RangePicker',
|
||||
componentProps: { valueType: 'Date', showTime: true, format: 'YYYY-MM-DD HH:mm:ss' },
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '关联业务表',
|
||||
field: 'bizTable',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
|
||||
export const formSchema: FormSchema[] = [
|
||||
{ label: '', field: 'id', component: 'Input', show: false },
|
||||
{
|
||||
label: '钉钉事件ID',
|
||||
field: 'eventId',
|
||||
component: 'Input',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '事件类型',
|
||||
field: 'eventType',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '如 bpms_instance_change' },
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '审批实例ID',
|
||||
field: 'processInstanceId',
|
||||
component: 'Input',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '接收时间',
|
||||
field: 'receivedTime',
|
||||
component: 'DatePicker',
|
||||
componentProps: { showTime: true, format: 'YYYY-MM-DD HH:mm:ss', valueFormat: 'YYYY-MM-DD HH:mm:ss', style: { width: '100%' } },
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '是否已处理',
|
||||
field: 'processed',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: { dictCode: 'yn', placeholder: '请选择' },
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '关联业务表',
|
||||
field: 'bizTable',
|
||||
component: 'Input',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '关联业务记录ID',
|
||||
field: 'bizDataId',
|
||||
component: 'Input',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '关联审批台账ID',
|
||||
field: 'recordId',
|
||||
component: 'Input',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '原始推送数据',
|
||||
field: 'rawData',
|
||||
component: 'InputTextArea',
|
||||
componentProps: { rows: 6, placeholder: 'JSON 原始推送内容' },
|
||||
colProps: { span: 24 },
|
||||
},
|
||||
{
|
||||
label: '处理备注',
|
||||
field: 'processRemark',
|
||||
component: 'InputTextArea',
|
||||
componentProps: { rows: 3, placeholder: '处理结果或失败原因' },
|
||||
colProps: { span: 24 },
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined">新增</a-button>
|
||||
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls">导出</a-button>
|
||||
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
|
||||
<a-button type="primary" danger preIcon="ant-design:delete-outlined" @click="batchHandleDelete">批量删除</a-button>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<MesXslDingCallbackLogModal @register="registerModal" @success="handleSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="xslmes-mesXslDingCallbackLog" setup>
|
||||
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import MesXslDingCallbackLogModal from './components/MesXslDingCallbackLogModal.vue';
|
||||
import { columns, searchFormSchema } from './MesXslDingCallbackLog.data';
|
||||
import { list, deleteOne, batchDelete, getExportUrl, getImportUrl } from './MesXslDingCallbackLog.api';
|
||||
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
|
||||
const { tableContext, onExportXls, onImportXls } = useListPage({
|
||||
tableProps: {
|
||||
title: '钉钉回调日志',
|
||||
api: list,
|
||||
columns,
|
||||
canResize: false,
|
||||
formConfig: {
|
||||
labelWidth: 90,
|
||||
schemas: searchFormSchema,
|
||||
autoSubmitOnEnter: true,
|
||||
showAdvancedButton: true,
|
||||
fieldMapToTime: [['receivedTime', ['receivedTime_begin', 'receivedTime_end'], 'YYYY-MM-DD HH:mm:ss']],
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
},
|
||||
},
|
||||
exportConfig: {
|
||||
name: '钉钉回调日志',
|
||||
url: getExportUrl,
|
||||
},
|
||||
importConfig: {
|
||||
url: getImportUrl,
|
||||
success: handleSuccess,
|
||||
},
|
||||
});
|
||||
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
function handleAdd() {
|
||||
openModal(true, { isUpdate: false, showFooter: true });
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
openModal(true, { record, isUpdate: true, showFooter: true });
|
||||
}
|
||||
|
||||
function handleDetail(record: Recordable) {
|
||||
openModal(true, { record, isUpdate: true, showFooter: false });
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
deleteOne({ id: record.id }, handleSuccess);
|
||||
}
|
||||
|
||||
function batchHandleDelete() {
|
||||
batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
|
||||
}
|
||||
|
||||
function handleSuccess() {
|
||||
reload();
|
||||
}
|
||||
|
||||
function getTableAction(record: Recordable) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function getDropDownAction(record: Recordable) {
|
||||
return [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
placement: 'topLeft',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" :width="1000" @ok="handleSubmit">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form';
|
||||
import { formSchema } from '../MesXslDingCallbackLog.data';
|
||||
import { saveOrUpdate } from '../MesXslDingCallbackLog.api';
|
||||
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
|
||||
const isUpdate = ref(true);
|
||||
const isDetail = ref(false);
|
||||
|
||||
const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 110,
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
baseColProps: { span: 12 },
|
||||
});
|
||||
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
resetFields();
|
||||
setModalProps({ confirmLoading: false, showOkBtn: !!data?.showFooter });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
isDetail.value = !data?.showFooter;
|
||||
|
||||
setProps({ disabled: isDetail.value });
|
||||
|
||||
if (unref(isUpdate) && data?.record) {
|
||||
setFieldsValue({ ...data.record });
|
||||
}
|
||||
});
|
||||
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : unref(isDetail) ? '详情' : '编辑'));
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
await saveOrUpdate(values, unref(isUpdate));
|
||||
closeModal();
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -19,7 +19,7 @@ const deptSelectProps = {
|
||||
};
|
||||
|
||||
const hasWorkflowInfo = ({ values }) =>
|
||||
!!(values.proofreadBy || values.proofreadTime || values.auditBy || values.auditTime || values.approveBy || values.approveTime);
|
||||
!!(values.traceProofreadBy || values.traceProofreadTime || values.traceAuditBy || values.traceAuditTime || values.traceApproveBy || values.traceApproveTime);
|
||||
|
||||
function sectionDivider(label: string, field: string, ifShow?: FormSchema['ifShow']): FormSchema {
|
||||
return {
|
||||
@@ -51,12 +51,6 @@ export const columns: BasicColumn[] = [
|
||||
width: 100,
|
||||
customRender: ({ record }) => record?.createBy_dictText || record?.createBy || '',
|
||||
},
|
||||
{ title: '校对人', align: 'center', dataIndex: 'proofreadBy', width: 100, defaultHidden: true },
|
||||
{ title: '校对时间', align: 'center', dataIndex: 'proofreadTime', width: 165, defaultHidden: true },
|
||||
{ title: '审核人', align: 'center', dataIndex: 'auditBy', width: 100, defaultHidden: true },
|
||||
{ title: '审核时间', align: 'center', dataIndex: 'auditTime', width: 165, defaultHidden: true },
|
||||
{ title: '批准人', align: 'center', dataIndex: 'approveBy', width: 100, defaultHidden: true },
|
||||
{ title: '批准时间', align: 'center', dataIndex: 'approveTime', width: 165, defaultHidden: true },
|
||||
{ title: '所属工厂', align: 'center', dataIndex: 'factoryName', width: 120, defaultHidden: true },
|
||||
{ title: '施工代号', align: 'center', dataIndex: 'constructionCode_dictText', width: 110, defaultHidden: true },
|
||||
{ title: '创建人', align: 'center', dataIndex: 'createBy', width: 100, defaultHidden: true },
|
||||
@@ -222,51 +216,51 @@ export const formSchema: FormSchema[] = [
|
||||
sectionDivider('审批记录', 'dividerWorkflow', hasWorkflowInfo),
|
||||
{
|
||||
label: '校对人',
|
||||
field: 'proofreadBy',
|
||||
field: 'traceProofreadBy',
|
||||
component: 'Input',
|
||||
componentProps: { disabled: true, bordered: false },
|
||||
colProps: colHalf,
|
||||
ifShow: ({ values }) => !!values.proofreadBy,
|
||||
ifShow: ({ values }) => !!values.traceProofreadBy,
|
||||
},
|
||||
{
|
||||
label: '校对时间',
|
||||
field: 'proofreadTime',
|
||||
field: 'traceProofreadTime',
|
||||
component: 'Input',
|
||||
componentProps: { disabled: true, bordered: false },
|
||||
colProps: colHalf,
|
||||
ifShow: ({ values }) => !!values.proofreadTime,
|
||||
ifShow: ({ values }) => !!values.traceProofreadTime,
|
||||
},
|
||||
{
|
||||
label: '审核人',
|
||||
field: 'auditBy',
|
||||
field: 'traceAuditBy',
|
||||
component: 'Input',
|
||||
componentProps: { disabled: true, bordered: false },
|
||||
colProps: colHalf,
|
||||
ifShow: ({ values }) => !!values.auditBy,
|
||||
ifShow: ({ values }) => !!values.traceAuditBy,
|
||||
},
|
||||
{
|
||||
label: '审核时间',
|
||||
field: 'auditTime',
|
||||
field: 'traceAuditTime',
|
||||
component: 'Input',
|
||||
componentProps: { disabled: true, bordered: false },
|
||||
colProps: colHalf,
|
||||
ifShow: ({ values }) => !!values.auditTime,
|
||||
ifShow: ({ values }) => !!values.traceAuditTime,
|
||||
},
|
||||
{
|
||||
label: '批准人',
|
||||
field: 'approveBy',
|
||||
field: 'traceApproveBy',
|
||||
component: 'Input',
|
||||
componentProps: { disabled: true, bordered: false },
|
||||
colProps: colHalf,
|
||||
ifShow: ({ values }) => !!values.approveBy,
|
||||
ifShow: ({ values }) => !!values.traceApproveBy,
|
||||
},
|
||||
{
|
||||
label: '批准时间',
|
||||
field: 'approveTime',
|
||||
field: 'traceApproveTime',
|
||||
component: 'Input',
|
||||
componentProps: { disabled: true, bordered: false },
|
||||
colProps: colHalf,
|
||||
ifShow: ({ values }) => !!values.approveTime,
|
||||
ifShow: ({ values }) => !!values.traceApproveTime,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user