- Workbench.vue 新增第4个页签「我提交的」,迁移原 MyInstances 列表(状态筛选/业务类型/详情·撤回·催办),惰性加载,默认页签仍为我的待办 - 删除独立路由 /my (modId 101) 及 MyInstances.vue - 提示:UserBase 侧 app_module 的 modId=101(我的办件)需另行清理
This commit is contained in:
@@ -9,7 +9,7 @@ import type { RouteRecordRaw } from "vue-router";
|
|||||||
* 办理页 /task/:taskId 为 UserMsg jumpPath 落地页(不挂菜单)。
|
* 办理页 /task/:taskId 为 UserMsg jumpPath 落地页(不挂菜单)。
|
||||||
* <p>
|
* <p>
|
||||||
* 详情/深链页(不挂菜单)通过 meta.parentId 关联父级菜单(UserBase 同款范式):左侧菜单保持
|
* 详情/深链页(不挂菜单)通过 meta.parentId 关联父级菜单(UserBase 同款范式):左侧菜单保持
|
||||||
* 父级高亮、面包屑补全"父页>本页"。同一详情页可能被多个列表进入(如办件详情既可从"我的办件"
|
* 父级高亮、面包屑补全"父页>本页"。同一详情页可能被多个列表进入(如办件详情既可从"我提交的"
|
||||||
* 也可从"办件记录"),此时列表页跳转带 ?pid=<父菜单modId> 动态覆盖 meta.parentId 静态默认。
|
* 也可从"办件记录"),此时列表页跳转带 ?pid=<父菜单modId> 动态覆盖 meta.parentId 静态默认。
|
||||||
*/
|
*/
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
@@ -19,12 +19,6 @@ const routes: RouteRecordRaw[] = [
|
|||||||
component: () => import("@/views/flow/Workbench.vue"),
|
component: () => import("@/views/flow/Workbench.vue"),
|
||||||
meta: { title: "工作台", modId: 100 },
|
meta: { title: "工作台", modId: 100 },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "/my",
|
|
||||||
name: "flow_my",
|
|
||||||
component: () => import("@/views/flow/MyInstances.vue"),
|
|
||||||
meta: { title: "我的办件", modId: 101 },
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/task/:taskId",
|
path: "/task/:taskId",
|
||||||
name: "flow_task_handle",
|
name: "flow_task_handle",
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
// 我的办件(提交人视角):列表 + 撤回/催办/详情
|
|
||||||
import { ref } from "vue";
|
|
||||||
import { Message, Tag } from "view-ui-plus";
|
|
||||||
import MyConfirm from "@/components/MyConfirm";
|
|
||||||
import TablePageAlovaNew from "@/components/TablePageAlovaNew.vue";
|
|
||||||
import InstanceDrawer from "@/views/flow/components/InstanceDrawer.vue";
|
|
||||||
import { OperatorEnum } from "@/types";
|
|
||||||
import { flowApi, INSTANCE_STATUS, INSTANCE_STATUS_COLOR } from "@/api/module/flow";
|
|
||||||
import { actionColumn } from "@/utils/tableActions";
|
|
||||||
|
|
||||||
const tableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
|
||||||
const dataParams = ref<{ status?: number }>({ status: undefined });
|
|
||||||
const drawerVisible = ref(false);
|
|
||||||
const drawerInstanceId = ref<string | number>("");
|
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{ title: "序号", type: "index", width: 70, align: "center" },
|
|
||||||
{ title: "办件标题", key: "bizTitle", minWidth: 220 },
|
|
||||||
{ title: "业务类型", key: "bizType", width: 110 },
|
|
||||||
{ title: "状态", width: 100, align: "center", render: (h: any, p: any) =>
|
|
||||||
h(Tag, { color: INSTANCE_STATUS_COLOR[p.row.status] || "gray" }, () => INSTANCE_STATUS[p.row.status] || p.row.status) },
|
|
||||||
{ title: "当前节点", key: "currentNodes", width: 150 },
|
|
||||||
{ title: "提交时间", width: 170, render: (h: any, p: any) => h("span", (p.row.submitTime || "").replace("T", " ")) },
|
|
||||||
{ title: "办结时间", width: 170, render: (h: any, p: any) => h("span", (p.row.finishTime || "").replace("T", " ") || "-") },
|
|
||||||
actionColumn(
|
|
||||||
[
|
|
||||||
{ key: "detail", label: "详情", icon: "icon-browse", on: (r: any) => openDetail(r.instanceId) },
|
|
||||||
{ key: "withdraw", label: "撤回", icon: "icon-yaohao", on: (r: any) => onWithdraw(r), disabledWhen: (r: any) => r.status !== 10, danger: true },
|
|
||||||
{ key: "urge", label: "催办", icon: "icon-fasong", on: (r: any) => onUrge(r), disabledWhen: (r: any) => r.status !== 10 },
|
|
||||||
],
|
|
||||||
{ mode: "text", width: 180, fixed: "right" },
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
// dataApi 返回 Method(alova usePagination 负责发送与解包),不能调 .send()
|
|
||||||
const tableApi = (p: { pageIndex: number; pageSize: number }) =>
|
|
||||||
flowApi.my({ status: dataParams.value.status || undefined, page: p.pageIndex, size: p.pageSize });
|
|
||||||
|
|
||||||
function onSearch() {
|
|
||||||
tableRef.value?.refreshData();
|
|
||||||
}
|
|
||||||
|
|
||||||
function openDetail(instanceId: string | number) {
|
|
||||||
drawerInstanceId.value = instanceId;
|
|
||||||
drawerVisible.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onWithdraw(row: any) {
|
|
||||||
await MyConfirm({
|
|
||||||
title: "撤回",
|
|
||||||
msg: `确定撤回办件「${row.bizTitle}」吗?`,
|
|
||||||
info: "撤回后流程终止,不可恢复",
|
|
||||||
async onOk() {
|
|
||||||
try {
|
|
||||||
await flowApi.withdraw(row.instanceId).send();
|
|
||||||
Message.success("已撤回");
|
|
||||||
tableRef.value?.reloadData(OperatorEnum.edit);
|
|
||||||
} catch (e: any) {
|
|
||||||
Message.error(e?.message || "撤回失败(可能已有任务被办理)");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onUrge(row: any) {
|
|
||||||
try {
|
|
||||||
await flowApi.urge(row.instanceId).send();
|
|
||||||
Message.success("已催办");
|
|
||||||
} catch (e: any) {
|
|
||||||
Message.error(e?.message || "催办失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="page-wrapper yh-fill">
|
|
||||||
<div class="main-container">
|
|
||||||
<div class="search-wrap fix">
|
|
||||||
<Select v-model="dataParams.status" class="search-wrap_sel" clearable placeholder="状态" @on-change="onSearch">
|
|
||||||
<Option :value="10" label="审批中" />
|
|
||||||
<Option :value="20" label="已完成" />
|
|
||||||
<Option :value="30" label="已拒绝" />
|
|
||||||
<Option :value="40" label="已撤回" />
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
<TablePageAlovaNew ref="tableRef" :dataApi="tableApi" :columns="columns" />
|
|
||||||
</div>
|
|
||||||
<InstanceDrawer v-model="drawerVisible" :instance-id="drawerInstanceId" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,22 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// 工作台:我的待办 / 我的已办(概览 §9.4 主路径查询,走 assignee 索引)。
|
// 工作台:我的待办 / 我的已办 / 抄送我的 / 我提交的(概览 §9.4 主路径查询,走 assignee 索引)。
|
||||||
// 规范骨架(bsch应用页规范 §1):tabs-wrapper + Tabs type=card,Tab 切换只 v-show 内容区,分页状态各自独立
|
// 规范骨架(bsch应用页规范 §1):tabs-wrapper + Tabs type=card,Tab 切换只 v-show 内容区,分页状态各自独立
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { Tag } from "view-ui-plus";
|
import { Message, Tag } from "view-ui-plus";
|
||||||
|
import MyConfirm from "@/components/MyConfirm";
|
||||||
import TablePageAlovaNew from "@/components/TablePageAlovaNew.vue";
|
import TablePageAlovaNew from "@/components/TablePageAlovaNew.vue";
|
||||||
import InstanceDrawer from "@/views/flow/components/InstanceDrawer.vue";
|
import InstanceDrawer from "@/views/flow/components/InstanceDrawer.vue";
|
||||||
import { OperatorEnum } from "@/types";
|
import { OperatorEnum } from "@/types";
|
||||||
import { flowApi, TASK_STATUS, TASK_STATUS_COLOR, INSTANCE_STATUS } from "@/api/module/flow";
|
import { flowApi, TASK_STATUS, TASK_STATUS_COLOR, INSTANCE_STATUS, INSTANCE_STATUS_COLOR } from "@/api/module/flow";
|
||||||
import { actionColumn } from "@/utils/tableActions";
|
import { actionColumn } from "@/utils/tableActions";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const tab = ref<"todo" | "done" | "cc">("todo");
|
const tab = ref<"my" | "todo" | "done" | "cc">("todo");
|
||||||
const drawerVisible = ref(false);
|
const drawerVisible = ref(false);
|
||||||
const drawerInstanceId = ref<string | number>("");
|
const drawerInstanceId = ref<string | number>("");
|
||||||
const todoTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
const todoTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||||
const doneTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
const doneTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||||
const ccTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
const ccTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||||
|
const myTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||||
|
const myParams = ref<{ status?: number }>({ status: undefined });
|
||||||
|
|
||||||
const todoColumns = [
|
const todoColumns = [
|
||||||
{ title: "序号", type: "index", width: 70, align: "center" },
|
{ title: "序号", type: "index", width: 70, align: "center" },
|
||||||
@@ -59,10 +62,62 @@ const ccColumns = [
|
|||||||
actionColumn([{ key: "detail", label: "详情", icon: "icon-browse", on: (r: any) => openDetail(r.instanceId) }], { mode: "text", width: 100, fixed: "right" }),
|
actionColumn([{ key: "detail", label: "详情", icon: "icon-browse", on: (r: any) => openDetail(r.instanceId) }], { mode: "text", width: 100, fixed: "right" }),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 我提交的(提交人视角):2026-10-12 由独立页 /my 并入本页签,口径不变
|
||||||
|
const myColumns = [
|
||||||
|
{ title: "序号", type: "index", width: 70, align: "center" },
|
||||||
|
{ title: "办件标题", key: "bizTitle", minWidth: 220 },
|
||||||
|
{ title: "业务类型", key: "bizType", width: 110 },
|
||||||
|
{ title: "状态", width: 100, align: "center", render: (h: any, p: any) =>
|
||||||
|
h(Tag, { color: INSTANCE_STATUS_COLOR[p.row.status] || "gray" }, () => INSTANCE_STATUS[p.row.status] || p.row.status) },
|
||||||
|
{ title: "当前节点", key: "currentNodes", width: 150 },
|
||||||
|
{ title: "提交时间", width: 170, render: (h: any, p: any) => h("span", (p.row.submitTime || "").replace("T", " ")) },
|
||||||
|
{ title: "办结时间", width: 170, render: (h: any, p: any) => h("span", (p.row.finishTime || "").replace("T", " ") || "-") },
|
||||||
|
actionColumn(
|
||||||
|
[
|
||||||
|
{ key: "detail", label: "详情", icon: "icon-browse", on: (r: any) => openDetail(r.instanceId) },
|
||||||
|
{ key: "withdraw", label: "撤回", icon: "icon-yaohao", on: (r: any) => onWithdraw(r), disabledWhen: (r: any) => r.status !== 10, danger: true },
|
||||||
|
{ key: "urge", label: "催办", icon: "icon-fasong", on: (r: any) => onUrge(r), disabledWhen: (r: any) => r.status !== 10 },
|
||||||
|
],
|
||||||
|
{ mode: "text", width: 180, fixed: "right" },
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
// dataApi 返回 Method(alova usePagination 负责发送与解包),不能调 .send()
|
// dataApi 返回 Method(alova usePagination 负责发送与解包),不能调 .send()
|
||||||
const todoApi = (p: { pageIndex: number; pageSize: number }) => flowApi.todo({ page: p.pageIndex, size: p.pageSize });
|
const todoApi = (p: { pageIndex: number; pageSize: number }) => flowApi.todo({ page: p.pageIndex, size: p.pageSize });
|
||||||
const doneApi = (p: { pageIndex: number; pageSize: number }) => flowApi.done({ page: p.pageIndex, size: p.pageSize });
|
const doneApi = (p: { pageIndex: number; pageSize: number }) => flowApi.done({ page: p.pageIndex, size: p.pageSize });
|
||||||
const ccApi = (p: { pageIndex: number; pageSize: number }) => flowApi.ccMy({ page: p.pageIndex, size: p.pageSize });
|
const ccApi = (p: { pageIndex: number; pageSize: number }) => flowApi.ccMy({ page: p.pageIndex, size: p.pageSize });
|
||||||
|
const myApi = (p: { pageIndex: number; pageSize: number }) =>
|
||||||
|
flowApi.my({ status: myParams.value.status || undefined, page: p.pageIndex, size: p.pageSize });
|
||||||
|
|
||||||
|
function onMySearch() {
|
||||||
|
myTableRef.value?.refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onWithdraw(row: any) {
|
||||||
|
await MyConfirm({
|
||||||
|
title: "撤回",
|
||||||
|
msg: `确定撤回办件「${row.bizTitle}」吗?`,
|
||||||
|
info: "撤回后流程终止,不可恢复",
|
||||||
|
async onOk() {
|
||||||
|
try {
|
||||||
|
await flowApi.withdraw(row.instanceId).send();
|
||||||
|
Message.success("已撤回");
|
||||||
|
myTableRef.value?.reloadData(OperatorEnum.edit);
|
||||||
|
} catch (e: any) {
|
||||||
|
Message.error(e?.message || "撤回失败(可能已有任务被办理)");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onUrge(row: any) {
|
||||||
|
try {
|
||||||
|
await flowApi.urge(row.instanceId).send();
|
||||||
|
Message.success("已催办");
|
||||||
|
} catch (e: any) {
|
||||||
|
Message.error(e?.message || "催办失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function goHandle(row: any) {
|
function goHandle(row: any) {
|
||||||
router.push(`/task/${row.taskId}?pid=100`);
|
router.push(`/task/${row.taskId}?pid=100`);
|
||||||
@@ -73,9 +128,10 @@ function openDetail(instanceId: string | number) {
|
|||||||
drawerVisible.value = true;
|
drawerVisible.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 两个内容区 v-show 共存,已办/抄送首次切换才拉取(保持原惰性加载行为)
|
// 各内容区 v-show 共存,非首个页签首次切换才拉取(保持原惰性加载行为)
|
||||||
const doneLoaded = ref(false);
|
const doneLoaded = ref(false);
|
||||||
const ccLoaded = ref(false);
|
const ccLoaded = ref(false);
|
||||||
|
const myLoaded = ref(false);
|
||||||
function switchTab(name: string) {
|
function switchTab(name: string) {
|
||||||
tab.value = name as any;
|
tab.value = name as any;
|
||||||
if (name === "done" && !doneLoaded.value) {
|
if (name === "done" && !doneLoaded.value) {
|
||||||
@@ -86,6 +142,10 @@ function switchTab(name: string) {
|
|||||||
ccLoaded.value = true;
|
ccLoaded.value = true;
|
||||||
ccTableRef.value?.reloadData(OperatorEnum.sel);
|
ccTableRef.value?.reloadData(OperatorEnum.sel);
|
||||||
}
|
}
|
||||||
|
if (name === "my" && !myLoaded.value) {
|
||||||
|
myLoaded.value = true;
|
||||||
|
myTableRef.value?.reloadData(OperatorEnum.sel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -96,6 +156,7 @@ function switchTab(name: string) {
|
|||||||
<TabPane label="我的待办" name="todo" />
|
<TabPane label="我的待办" name="todo" />
|
||||||
<TabPane label="我的已办" name="done" />
|
<TabPane label="我的已办" name="done" />
|
||||||
<TabPane label="抄送我的" name="cc" />
|
<TabPane label="抄送我的" name="cc" />
|
||||||
|
<TabPane label="我提交的" name="my" />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<div class="tab-body" v-show="tab === 'todo'">
|
<div class="tab-body" v-show="tab === 'todo'">
|
||||||
@@ -107,6 +168,17 @@ function switchTab(name: string) {
|
|||||||
<div class="tab-body" v-show="tab === 'cc'">
|
<div class="tab-body" v-show="tab === 'cc'">
|
||||||
<TablePageAlovaNew ref="ccTableRef" :dataApi="ccApi" :columns="ccColumns" :autoLoad="false" />
|
<TablePageAlovaNew ref="ccTableRef" :dataApi="ccApi" :columns="ccColumns" :autoLoad="false" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab-body" v-show="tab === 'my'">
|
||||||
|
<div class="search-wrap fix">
|
||||||
|
<Select v-model="myParams.status" class="search-wrap_sel" clearable placeholder="状态" @on-change="onMySearch">
|
||||||
|
<Option :value="10" label="审批中" />
|
||||||
|
<Option :value="20" label="已完成" />
|
||||||
|
<Option :value="30" label="已拒绝" />
|
||||||
|
<Option :value="40" label="已撤回" />
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<TablePageAlovaNew ref="myTableRef" :dataApi="myApi" :columns="myColumns" :autoLoad="false" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<InstanceDrawer v-model="drawerVisible" :instance-id="drawerInstanceId" />
|
<InstanceDrawer v-model="drawerVisible" :instance-id="drawerInstanceId" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user