Files
svc-hall-hall/src/views/MyApprovals.vue
T
chenxing d7d8789d1a
build / build (push) Successful in 2m0s
feat(p3.5): 我的审批扩四页签——我已审批/抄送我的(行映射与漂移登记)
- types 增 DoneTask/CcRow 行契约与 api.done/cc;列表组件 tabs 扩 'done'|'cc'
  (done=我办理的节点+办理时间;cc=抄送节点+抄送时间;行详情跳转只用本行 bizId 构造)
- ApprovalApi.done/cc + adapter 映射;页头文案更新
- 门禁:vue-tsc 18 零新增+build 绿(Stage S5/P3.5)
2026-10-20 00:16:24 +08:00

139 lines
4.8 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.
<script setup lang="ts">
/**
* 我的审批(/todo,P3.3):待我审批(中心 todo)+ 我提交的(本地办件)两页签。
* 完整办理=去壳任务页 iframe(FlowTaskEmbed);审批记录=token 只读抽屉(FlowRecordDrawer)。
*
* 宿主职责(P1-09):
* - open-task 换址请求带代际号——关闭/换件时废弃在途响应并清 taskUrl/选中 ID;
* - open-biz 只用与当前办件上下文一致的 bizId 构造 /apply-detail?id=,不照抄任意 URL。
*/
import { onBeforeUnmount, ref } from "vue";
import { useRouter } from "vue-router";
import { Message } from "view-ui-plus";
import FlowApprovalList from "@/components/flow-approval/FlowApprovalList.vue";
import FlowRecordDrawer from "@/components/flow-approval/FlowRecordDrawer.vue";
import FlowTaskEmbed from "@/components/flow-approval/FlowTaskEmbed.vue";
import svcFlowApprovalApi from "@/api/module/approvalAdapter";
const router = useRouter();
const listRef = ref<InstanceType<typeof FlowApprovalList> | null>(null);
// ===== 审批记录抽屉 =====
const recordVisible = ref(false);
const recordBizId = ref("");
function openRecord(bizId: string) {
recordBizId.value = bizId;
recordVisible.value = true;
}
// ===== 完整办理(去壳任务页) =====
const taskVisible = ref(false);
const taskUrl = ref("");
const taskTaskId = ref<number | string>("");
const taskBizId = ref<string | number>("");
/** 换址请求代际号:关闭/换件时 +1,晚到响应按代际丢弃(P1-09) */
let taskReqEpoch = 0;
async function openTask(payload: { bizId: string; taskId: number }) {
const epoch = ++taskReqEpoch;
taskBizId.value = payload.bizId;
taskTaskId.value = payload.taskId;
taskUrl.value = "";
taskVisible.value = true;
try {
const res: any = await svcFlowApprovalApi.taskPageUrl(payload.bizId, payload.taskId);
if (epoch !== taskReqEpoch) return; // 已关闭/已换件:废弃
const url = res?.pageUrl || "";
if (!url) {
Message.error("任务页地址获取失败");
taskVisible.value = false;
return;
}
taskUrl.value = url;
} catch (e: any) {
if (epoch !== taskReqEpoch) return;
Message.error(e?.msg || e?.message || "任务页地址获取失败");
taskVisible.value = false;
}
}
function onTaskClose() {
// 关闭即清上下文 + 废弃在途换址请求
taskReqEpoch++;
taskUrl.value = "";
taskTaskId.value = "";
taskBizId.value = "";
}
function onHandled() {
// 办理完成:刷新列表(本地 flow_status 由回调推进,前端只刷数据面)
listRef.value?.load();
}
/**
* open-biz:只用校验过的本办件 ID 构造 /apply-detail?id=(P1-09)。
* 消息 bizId 必须与打开任务页时锁定的办件上下文一致;缺失时用锁定上下文;绝不透传 bizUrl 路由。
*/
function onOpenBiz(payload: { bizId?: string | null; bizUrl?: string }) {
const msgBizId = payload.bizId != null ? String(payload.bizId) : "";
const ctxBizId = String(taskBizId.value || "");
if (!msgBizId && !ctxBizId) return;
if (msgBizId && ctxBizId && msgBizId !== ctxBizId) return; // 换件期间旧消息,作废
const applyId = Number(msgBizId || ctxBizId);
if (!Number.isInteger(applyId) || applyId <= 0) return;
taskVisible.value = false;
router.push(`/apply-detail?id=${applyId}`);
}
/** "我提交的"行查看详情(只用本行 id 构造路由) */
function openDetail(applyId: number) {
router.push(`/apply-detail?id=${applyId}`);
}
onBeforeUnmount(() => {
taskReqEpoch++;
});
</script>
<template>
<div class="page todo-page">
<div class="page-head">
<h2 class="page-title">我的审批</h2>
<span class="page-sub">「待我审批/我已审批/抄送我的」为流程中心数据(按本应用过滤);「我提交的」为本地办件</span>
</div>
<FlowApprovalList ref="listRef" :api="svcFlowApprovalApi" :tabs="['todo', 'my', 'done', 'cc']"
@open-record="openRecord" @open-task="openTask" @handled="onHandled"
@open-detail="openDetail" />
<FlowRecordDrawer v-model="recordVisible" :api="svcFlowApprovalApi" :biz-id="recordBizId" />
<FlowTaskEmbed v-model="taskVisible" :page-url="taskUrl" :task-id="taskTaskId" :biz-id="taskBizId"
@handled="onHandled" @open-biz="onOpenBiz" @close="onTaskClose" />
</div>
</template>
<style scoped>
.todo-page {
max-width: 1080px;
margin: 0 auto;
width: 100%;
box-sizing: border-box;
}
.page-head {
display: flex;
align-items: baseline;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 12px;
}
.page-title {
font-size: 18px;
font-weight: 600;
margin: 0;
}
.page-sub {
font-size: 13px;
color: var(--sh-text-weak, #6b7280);
}
</style>