feat(ui): 应用页规范全量重构 + 工作台与流程轨迹优化
build / build (push) Successful in 3m17s

应用页规范(bsch)重构:
- 6 个列表页迁规范骨架: page-wrapper/tabs-wrapper + search-wrap 搜索区(关键字 200px 即输即搜, 去查询按钮) + link-table table-bottom-box 定高表格 + page-panel 分页栏
- 分页列表统一接 TablePageAlovaNew(页长 [10,20,30,40]/customPageCount 记忆/增删智能翻页); dataApi 须返回 Method, 调 .send() 会导致表格静默空数据
- 操作列统一图标式 operatingHandle(Tooltip+fixed right 居中); 各列表补序号列; 危险操作统一 MyConfirm 二次确认
- 弹窗表单必填红星 + 统一提示「请填写红色星号内容!」
- TablePageAlovaNew 补页长记忆与重载后清空勾选; 新增 src/types OperatorEnum

工作台与流程轨迹优化:
- 已办列表去重: 每办件一行, doneCount>1 显示「共办理 N 次」标签
- 新增 TraceTimeline 轨迹时间流(时间升序/kind/轮次, 按人员/科室切换写回 URL), 接入详情/办理页
- 新增流程源码只读抽屉 SourceDrawer, 接入定义列表与图示页
- 办理人映射/流程定义新增「启用」回路(/admin/map/enable, /admin/def/enable)
- 图示视图口径统一 dept/user 两档, 缺省人员视图; 状态列 Tag 色映射统一导出
This commit is contained in:
chenxing
2026-09-18 16:52:40 +08:00
parent 0083246039
commit cdf04f0930
16 changed files with 1172 additions and 481 deletions
+29 -26
View File
@@ -1,8 +1,11 @@
<script setup lang="ts">
// 办件详情:状态 + 业务摘要 + 流程轨迹时间线 + 分支会签进度(概览 §9.4 进度图数据源)
// 轨迹两档显示(2026-09-18):mode=user(人员,缺省)|dept(科室),写进 query 便于分享/刷新保持,
// 并随"流程示意图"跳转带给图示页(两边口径一致)。
import { ref, computed, onMounted } from "vue";
import { useRoute, useRouter } from "vue-router";
import { flowApi, INSTANCE_STATUS } from "@/api/module/flow";
import TraceTimeline from "@/views/flow/components/TraceTimeline.vue";
import config from "@/assets/config/host.config";
const route = useRoute();
@@ -10,6 +13,14 @@ const router = useRouter();
const loading = ref(false);
const detail = ref<any>(null);
/** 显示口径:dept=按科室 / user=按人员(不传=人员) */
const mode = ref<string>(route.query.mode === "dept" ? "dept" : "user");
function switchMode(val: string) {
mode.value = val;
router.replace({ query: { ...route.query, mode: val } });
}
const snapshotRows = computed(() => {
const raw = detail.value?.bizSnapshot;
if (!raw) return [];
@@ -56,11 +67,16 @@ const branchText = computed(() => {
/** 流程示意图图片直嵌(2026-09-16 "CAS 验证码式":后端 /diagram.png 返回 PNG 流,img 直显)。
* img 不走 alova(无 baseUrl 拼接),须显式带 serviceHost——/{ctx}/front/ 子路径部署下
* 裸 /api 会落到网关根导致 404。 */
* 裸 /api 会落到网关根导致 404。mode 跟随本页选择,缩略图与轨迹口径一致。 */
const diagramSrc = computed(
() => `${config.serviceHost}/api/flow/diagram.png?instanceId=${route.params.instanceId}`,
() => `${config.serviceHost}/api/flow/diagram.png?instanceId=${route.params.instanceId}&mode=${mode.value}`,
);
/** 跳流程图时带上当前口径(图示页读 mode,缺省人员) */
function toDiagram() {
router.push({ path: "/diagram", query: { instanceId: String(route.params.instanceId), mode: mode.value } });
}
function statusName(s: number) {
return INSTANCE_STATUS[s] || s;
}
@@ -84,7 +100,7 @@ onMounted(async () => {
<div class="head">
<span class="title">{{ detail.bizTitle }}</span>
<Tag :color="statusColor(detail.status)">{{ statusName(detail.status) }}</Tag>
<a @click="router.push({ path: '/diagram', query: { instanceId: String(route.params.instanceId) } })">流程示意图</a>
<a @click="toDiagram()">流程示意图</a>
<span class="muted" v-if="branchText">{{ branchText }}</span>
</div>
@@ -121,36 +137,25 @@ onMounted(async () => {
<Card class="block" :bordered="false" dis-hover>
<template #title>
流程示意图
<a class="diagram-more" @click="router.push({ path: '/diagram', query: { instanceId: String(route.params.instanceId) } })">查看大图</a>
<a class="diagram-more" @click="toDiagram()">查看大图</a>
</template>
<img class="diagram-img" :src="diagramSrc" alt="流程示意图" />
</Card>
<Card class="block" :bordered="false" dis-hover>
<template #title>流程轨迹</template>
<Timeline>
<TimelineItem v-for="t in detail.trace" :key="t.taskId"
:color="t.status === 1 ? 'green' : t.status === 2 ? 'red' : t.status === 0 ? 'blue' : 'gray'">
<span class="node">{{ t.nodeName || t.nodeId }}</span>
<Tag size="small">{{ t.assigneeName || t.assigneeId }}</Tag>
<Tag size="small" v-if="t.status !== 1">{{ taskStatusName(t.status) }}</Tag>
<span class="opinion" v-if="t.opinion">「{{ t.opinion }}」</span>
<div class="time">{{ (t.handleTime || t.arriveTime || "").replace("T", " ") }}</div>
</TimelineItem>
</Timeline>
<template #title>
流程轨迹
<RadioGroup class="trace-mode" :model-value="mode" size="small" type="button" @on-change="switchMode">
<Radio label="user">按人员</Radio>
<Radio label="dept">按科室</Radio>
</RadioGroup>
</template>
<TraceTimeline :trace="detail.trace || []" :mode="mode" />
</Card>
</div>
<div v-else class="page muted">加载中…</div>
</template>
<script lang="ts">
// 任务状态名(避免引入整表;口径同 api/module/flow TASK_STATUS)
function taskStatusName(s: number) {
return ({ 0: "待办", 2: "拒绝", 3: "失效" } as Record<number, string>)[s] || "同意";
}
export default { methods: { taskStatusName } };
</script>
<style scoped>
.page { padding: 12px 16px; }
.head { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
@@ -164,7 +169,5 @@ export default { methods: { taskStatusName } };
.diagram-box { display: flex; justify-content: center; }
.diagram-img { max-width: 100%; }
.diagram-more { float: right; font-size: 12px; font-weight: normal; margin-right: 16px; }
.node { font-weight: 600; margin-right: 6px; }
.opinion { color: #666; }
.time { color: #aaa; font-size: 12px; }
.trace-mode { float: right; font-weight: normal; margin-right: 16px; }
</style>