Files
qhmes/jeecgboot-vue3/src/views/xslmes/approval/integration/components/MesXslIntegrationActionDrawer.vue

215 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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 forXSLMES-20260605-K8R2动作管理复用可视化编辑器,与向导添加动作一致 -->
<VisualActionEditor ref="visualEditorRef" @success="handleActionSaved" />
<!-- update-end---author:GHT ---date:2026-06-05 forXSLMES-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>