build / build (push) Successful in 3m17s
alova 的 Method 请求体是构造函数第 5 个参数(instance.data),不是 config 上的键。 原 post() 把 body 塞进 config,被适配器静默忽略,POST 恒发空 body, 后端 @RequestBody 直接抛 HttpMessageNotReadableException: Required request body is missing。 受影响的接口(同一 helper): - def/save、map/save、callback/repush:一律 400 Required request body is missing - task/reject:opinion 送不到,而 FlowTaskService 强制要求非空,拒绝必然失败 - task/approve:请求成功但审批意见被静默丢弃 同时: - Defs.vue 保存时回传 baseGuid,否则「升版本」会另起流程线而非同线升版本 - 补上调用方已在使用但 FlowApi 未定义的 callbackHung / callbackMarkDead 验证:本地后端实测 def/save 带 body 返回 code=0(新建草稿、编辑草稿、 baseGuid 升版本 version+1 且 flowGuid 不变);alova 运行时对照确认 config.body 与 config.data 均发不出 body,仅第 5 参有效。
177 lines
6.6 KiB
Vue
177 lines
6.6 KiB
Vue
<script setup lang="ts">
|
||
// 流程定义管理(M1:JSON 文本编辑模式;发布跑静态校验,把"任务无主"拦在发布期)
|
||
import { ref, onMounted } from "vue";
|
||
import { useRouter } from "vue-router";
|
||
import { Message } from "view-ui-plus";
|
||
import { flowApi } from "@/api/module/flow";
|
||
|
||
const router = useRouter();
|
||
const DEF_STATUS: Record<number, string> = { 0: "草稿", 1: "已发布", 2: "停用" };
|
||
|
||
const loading = ref(false);
|
||
const rows = ref<any[]>([]);
|
||
const editVisible = ref(false);
|
||
const saving = ref(false);
|
||
const form = ref<any>({ id: null, code: "", name: "", contentJson: "" });
|
||
const versionVisible = ref(false);
|
||
const versions = ref<any[]>([]);
|
||
|
||
const SAMPLE_JSON = `{
|
||
"code": "sample_flow",
|
||
"name": "示例流程",
|
||
"start": "start",
|
||
"nodes": [
|
||
{"id": "start", "type": "START", "name": "开始"},
|
||
{"id": "n1", "type": "APPROVAL", "name": "科室审核",
|
||
"assignee": {"type": "DEPT_KEY", "deptKey": "ybb"}, "countersign": "ALL"},
|
||
{"id": "end", "type": "END"}
|
||
],
|
||
"edges": [
|
||
{"from": "start", "to": "n1"},
|
||
{"from": "n1", "to": "end"}
|
||
],
|
||
"settings": {"rejectPolicy": "END_REJECTED", "urge": {"enabled": true, "intervalHours": 24, "maxTimes": 3}}
|
||
}`;
|
||
|
||
const columns = [
|
||
{ title: "流程", key: "name", minWidth: 180 },
|
||
{ title: "编码", key: "code", width: 160 },
|
||
{ title: "版本", key: "version", width: 70 },
|
||
{ title: "状态", width: 90, render: (h: any, p: any) => {
|
||
const c = p.row.status === 1 ? "green" : p.row.status === 0 ? "orange" : "gray";
|
||
return h("Tag", { color: c }, () => DEF_STATUS[p.row.status] || p.row.status);
|
||
} },
|
||
{ title: "GUID", key: "flowGuid", width: 200 },
|
||
{ title: "发布时间", width: 160, render: (h: any, p: any) => h("span", (p.row.publishTime || "").replace("T", " ") || "-") },
|
||
{ title: "操作", width: 330, render: (h: any, p: any) => {
|
||
const btns: any[] = [];
|
||
if (p.row.status === 0) {
|
||
btns.push(h("Button", { size: "small", type: "primary", onClick: () => onEdit(p.row) }, () => "编辑"));
|
||
btns.push(h("Button", { size: "small", type: "success", onClick: () => onPublish(p.row) }, () => "发布"));
|
||
} else if (p.row.status === 1) {
|
||
btns.push(h("Button", { size: "small", onClick: () => onNewVersion(p.row) }, () => "升版本"));
|
||
btns.push(h("Button", { size: "small", type: "warning", onClick: () => onOffline(p.row) }, () => "停用"));
|
||
}
|
||
btns.push(h("Button", { size: "small", onClick: () => onDiagram(p.row) }, () => "图示"));
|
||
btns.push(h("Button", { size: "small", onClick: () => onVersions(p.row) }, () => "版本历史"));
|
||
return h("div", { style: "display:flex;gap:4px" }, btns);
|
||
} },
|
||
];
|
||
|
||
async function load() {
|
||
loading.value = true;
|
||
try {
|
||
rows.value = (await flowApi.defList().send()) || [];
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
function onEdit(row: any) {
|
||
flowApi.defGet(row.id).send().then((d: any) => {
|
||
form.value = { id: d.id, code: d.code, name: d.name, contentJson: d.contentJson };
|
||
editVisible.value = true;
|
||
});
|
||
}
|
||
|
||
function onNew() {
|
||
form.value = { id: null, code: "", name: "", contentJson: SAMPLE_JSON };
|
||
editVisible.value = true;
|
||
}
|
||
|
||
async function onNewVersion(row: any) {
|
||
// 升版本:以已发布内容为底稿建草稿(flowGuid 不变,version 自动 +1)
|
||
const d: any = await flowApi.defGet(row.id).send();
|
||
form.value = { id: null, code: row.code, name: row.name, contentJson: d.contentJson, baseGuid: row.flowGuid };
|
||
Message.info("已载入当前版本内容,保存即创建新草稿版本");
|
||
editVisible.value = true;
|
||
}
|
||
|
||
async function onSave() {
|
||
saving.value = true;
|
||
try {
|
||
await flowApi.defSave({
|
||
id: form.value.id || undefined,
|
||
code: form.value.code,
|
||
name: form.value.name,
|
||
contentJson: form.value.contentJson,
|
||
baseGuid: form.value.baseGuid,
|
||
}).send();
|
||
Message.success("已保存");
|
||
editVisible.value = false;
|
||
load();
|
||
} finally {
|
||
saving.value = false;
|
||
}
|
||
}
|
||
|
||
async function onPublish(row: any) {
|
||
try {
|
||
await flowApi.defPublish(row.id).send();
|
||
Message.success("发布成功");
|
||
load();
|
||
} catch (e: any) {
|
||
Message.error(e?.message || "发布校验失败");
|
||
}
|
||
}
|
||
|
||
async function onOffline(row: any) {
|
||
await flowApi.defOffline(row.id).send();
|
||
Message.success("已停用");
|
||
load();
|
||
}
|
||
|
||
async function onVersions(row: any) {
|
||
versions.value = (await flowApi.defVersions(row.flowGuid).send()) || [];
|
||
versionVisible.value = true;
|
||
}
|
||
|
||
function onDiagram(row: any) {
|
||
router.push({ path: "/diagram", query: { defId: row.id, mode: "auto" } });
|
||
}
|
||
|
||
onMounted(load);
|
||
</script>
|
||
|
||
<template>
|
||
<div class="page">
|
||
<div class="filter">
|
||
<Button type="primary" @click="onNew">新建流程</Button>
|
||
</div>
|
||
<Table :columns="columns" :data="rows" :loading="loading" stripe />
|
||
|
||
<Modal v-model="editVisible" :title="form.id ? '编辑流程' : '新建流程'" width="760" :mask-closable="false">
|
||
<Form :label-width="80">
|
||
<FormItem label="编码">
|
||
<Input v-model="form.code" :disabled="!!form.id" placeholder="流程编码(内部管理键,发布后不可改)" />
|
||
</FormItem>
|
||
<FormItem label="名称">
|
||
<Input v-model="form.name" placeholder="流程名" />
|
||
</FormItem>
|
||
<FormItem label="定义 JSON">
|
||
<Input v-model="form.contentJson" type="textarea" :rows="16"
|
||
placeholder="§5.1 流程定义 JSON(START/END 唯一、无孤儿无环、DEPT_KEY 需先配好映射)" />
|
||
</FormItem>
|
||
</Form>
|
||
<template #footer>
|
||
<Button @click="editVisible = false">取消</Button>
|
||
<Button type="primary" :loading="saving" @click="onSave">保存(草稿)</Button>
|
||
</template>
|
||
</Modal>
|
||
|
||
<Modal v-model="versionVisible" title="版本历史" width="640">
|
||
<Table :columns="[
|
||
{ title: '版本', key: 'version', width: 80 },
|
||
{ title: '名称', key: 'name' },
|
||
{ title: '状态', width: 90, render: (h, p) => h('Tag', () => DEF_STATUS[p.row.status]) },
|
||
{ title: '发布时间', width: 160, render: (h, p) => (p.row.publishTime || '').replace('T', ' ') || '-' },
|
||
]" :data="versions" size="small" />
|
||
</Modal>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.page { padding: 12px 16px; }
|
||
.filter { margin-bottom: 10px; }
|
||
</style>
|