215 lines
7.5 KiB
Vue
215 lines
7.5 KiB
Vue
<template>
|
||
<a-drawer v-model:open="visible" :title="`动作管理 — ${planName}`" width="900" destroy-on-close @close="visible = false">
|
||
<div style="margin-bottom: 12px">
|
||
<a-button type="primary" size="small" @click="handleAddAction">
|
||
<template #icon><PlusOutlined /></template>
|
||
添加动作
|
||
</a-button>
|
||
</div>
|
||
|
||
<a-table :dataSource="actions" :columns="tableColumns" :loading="loading" :pagination="false" row-key="id" size="small" bordered>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.dataIndex === 'enabled'">
|
||
<a-tag :color="record.enabled ? 'green' : 'default'">{{ record.enabled ? '启用' : '停用' }}</a-tag>
|
||
</template>
|
||
<template v-if="column.dataIndex === 'actionType'">
|
||
<a-tag color="blue">{{ actionTypeLabel(record.actionType) }}</a-tag>
|
||
</template>
|
||
<template v-if="column.dataIndex === 'onFail'">
|
||
<a-tag :color="record.onFail === 'stop' ? 'orange' : 'default'">{{ record.onFail === 'stop' ? '终止' : '继续' }}</a-tag>
|
||
</template>
|
||
<template v-if="column.dataIndex === 'summary'">
|
||
<span style="font-size: 12px; color: #666">{{ formatActionSummary(record) }}</span>
|
||
</template>
|
||
<template v-if="column.key === 'operation'">
|
||
<a-space>
|
||
<a-button size="small" @click="handleEditAction(record)">编辑</a-button>
|
||
<a-popconfirm title="确认删除该动作?" @confirm="handleDeleteAction(record)">
|
||
<a-button size="small" danger>删除</a-button>
|
||
</a-popconfirm>
|
||
</a-space>
|
||
</template>
|
||
</template>
|
||
</a-table>
|
||
|
||
<!-- update-begin---author:GHT ---date:2026-06-05 for:【XSLMES-20260605-K8R2】动作管理复用可视化编辑器,与向导添加动作一致 -->
|
||
<VisualActionEditor ref="visualEditorRef" @success="handleActionSaved" />
|
||
<!-- update-end---author:GHT ---date:2026-06-05 for:【XSLMES-20260605-K8R2】动作管理复用可视化编辑器 -->
|
||
</a-drawer>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { ref } from 'vue';
|
||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||
import { useMessage } from '/@/hooks/web/useMessage';
|
||
import {
|
||
listActions,
|
||
saveAction,
|
||
editAction,
|
||
deleteAction,
|
||
getTableColumns,
|
||
listBizDocRegistry,
|
||
getRegistryByTable,
|
||
} from '../MesXslIntegrationPlan.api';
|
||
import VisualActionEditor from './VisualActionEditor.vue';
|
||
|
||
const STAGE_LABELS: Record<string, string> = { proofread: '校对', audit: '审核', approve: '批准' };
|
||
|
||
const ACTION_TYPE_LABELS: Record<string, string> = {
|
||
REGISTRY_STAGE_SYNC: '审批环节同步',
|
||
REGISTRY_STAGE_REVERT: '审批环节回退',
|
||
SQL_UPDATE: 'SQL更新',
|
||
};
|
||
|
||
const { createMessage } = useMessage();
|
||
|
||
const visible = ref(false);
|
||
const loading = ref(false);
|
||
const planId = ref('');
|
||
const planName = ref('');
|
||
const planRecord = ref<Recordable>({});
|
||
const actions = ref<any[]>([]);
|
||
|
||
const visualEditorRef = ref();
|
||
const bizDocList = ref<any[]>([]);
|
||
const sourceColumns = ref<any[]>([]);
|
||
const sourceRegistry = ref<any>(null);
|
||
|
||
const tableColumns = [
|
||
{ title: '顺序', dataIndex: 'execOrder', width: 60, align: 'center' },
|
||
{ title: '动作名称', dataIndex: 'actionName', width: 140 },
|
||
{ title: '类型', dataIndex: 'actionType', width: 120 },
|
||
{ title: '配置摘要', dataIndex: 'summary', ellipsis: true },
|
||
{ title: '失败策略', dataIndex: 'onFail', width: 90 },
|
||
{ title: '启用', dataIndex: 'enabled', width: 70 },
|
||
{ title: '操作', key: 'operation', width: 130, align: 'center' },
|
||
];
|
||
|
||
function actionTypeLabel(type: string) {
|
||
return ACTION_TYPE_LABELS[type] || type || '-';
|
||
}
|
||
|
||
function formatActionSummary(record: Recordable) {
|
||
if (record.actionType === 'REGISTRY_STAGE_SYNC' || record.actionType === 'REGISTRY_STAGE_REVERT') {
|
||
try {
|
||
const cfg = JSON.parse(record.actionConfig || '{}');
|
||
if (record.actionType === 'REGISTRY_STAGE_SYNC') {
|
||
const stage = cfg.registryStage?.stage || cfg.stage;
|
||
const from = cfg.registryStage?.expectedFrom || cfg.expectedFrom;
|
||
const after = cfg.registryStage?.statusAfter || cfg.statusAfter || stage;
|
||
return `环节→${STAGE_LABELS[stage] || stage || '?'}${from ? `,前置=${from}` : ''},通过后=${after}`;
|
||
}
|
||
const target = cfg.registryStage?.targetStage ?? cfg.targetStage;
|
||
return target !== undefined && target !== null && target !== '' ? `回退→${target}` : '回退→未配置';
|
||
} catch {
|
||
return record.actionConfig || '-';
|
||
}
|
||
}
|
||
if (record.actionType === 'SQL_UPDATE') {
|
||
try {
|
||
const cfg = JSON.parse(record.actionConfig || '{}');
|
||
const base = record.sqlTemplate || '-';
|
||
return cfg.syncTrace ? `${base};痕迹同步:是` : base;
|
||
} catch {
|
||
return record.sqlTemplate || '-';
|
||
}
|
||
}
|
||
return record.sqlTemplate || '-';
|
||
}
|
||
|
||
async function loadEditorContext() {
|
||
const sourceTable = planRecord.value.sourceTable;
|
||
if (!sourceTable) return;
|
||
try {
|
||
const [cols, registryRes, docsRes] = await Promise.all([
|
||
getTableColumns(sourceTable),
|
||
getRegistryByTable(sourceTable),
|
||
listBizDocRegistry(),
|
||
]);
|
||
sourceColumns.value = (cols as any) || [];
|
||
sourceRegistry.value = registryRes || null;
|
||
bizDocList.value = (docsRes as any)?.records || (Array.isArray(docsRes) ? docsRes : []);
|
||
} catch {
|
||
sourceColumns.value = [];
|
||
sourceRegistry.value = null;
|
||
bizDocList.value = [];
|
||
}
|
||
}
|
||
|
||
async function open(plan: Recordable) {
|
||
planId.value = plan.id;
|
||
planName.value = plan.planName;
|
||
planRecord.value = plan;
|
||
visible.value = true;
|
||
await Promise.all([loadActions(), loadEditorContext()]);
|
||
}
|
||
|
||
async function loadActions() {
|
||
loading.value = true;
|
||
try {
|
||
actions.value = (await listActions(planId.value)) || [];
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
function openVisualEditor(action?: Recordable) {
|
||
if (!planRecord.value.sourceTable) {
|
||
createMessage.warning('方案未配置触发业务表');
|
||
return;
|
||
}
|
||
visualEditorRef.value?.open({
|
||
sourceTable: planRecord.value.sourceTable,
|
||
sourceColumns: sourceColumns.value,
|
||
bizDocList: bizDocList.value,
|
||
sourceRegistry: sourceRegistry.value,
|
||
action: action
|
||
? { ...action, planId: planId.value }
|
||
: { planId: planId.value, execOrder: actions.value.length + 1 },
|
||
execOrder: action?.execOrder ?? actions.value.length + 1,
|
||
});
|
||
}
|
||
|
||
function handleAddAction() {
|
||
openVisualEditor();
|
||
}
|
||
|
||
function handleEditAction(record: Recordable) {
|
||
openVisualEditor(record);
|
||
}
|
||
|
||
async function handleDeleteAction(record: Recordable) {
|
||
await deleteAction({ id: record.id }, loadActions);
|
||
}
|
||
|
||
async function handleActionSaved(actionData: Recordable) {
|
||
const payload = {
|
||
...actionData,
|
||
planId: planId.value,
|
||
enabled: actionData.enabled !== false && actionData.enabled !== 0 ? 1 : 0,
|
||
};
|
||
try {
|
||
if (actionData.id) {
|
||
await editAction(payload);
|
||
} else {
|
||
await saveAction(payload);
|
||
}
|
||
createMessage.success('保存成功');
|
||
await loadActions();
|
||
} catch (e: any) {
|
||
createMessage.error(e?.message || '保存失败');
|
||
}
|
||
}
|
||
|
||
defineExpose({ open, openAndEditFirstAction });
|
||
|
||
async function openAndEditFirstAction(plan: Recordable) {
|
||
await open(plan);
|
||
if (actions.value.length > 0) {
|
||
openVisualEditor(actions.value[0]);
|
||
} else {
|
||
openVisualEditor();
|
||
}
|
||
}
|
||
</script>
|