fix(approval): /approval 点击不可达——modId 全量对齐 GetUserMod + 页面按 bsch 应用页规范重构
根因:/approval 与 /list/detail 的 meta.modId 同为 23,menuRoute.ts 的 ROUTE_BY_MODID 按注册 顺序取首条,23 恒解析为「通知详情」;菜单下发的 path 一旦未精确命中,兜底即串页 → 表现为点不到。 - routes.ts:modId 全量对齐 /base/GetUserMod(已收到 1000 / 已发送 2000 / 全部通知 3000 / 通知统计 4000 / 应用设置 5000 / 待审核 2100);深层页按「父×10+序」重排 (/list/new=20001、/list/detail=20002、/noticelist/detail=30001,parentId 同步); /approval 去掉 parentId,按一级模块处理;文件头契约注释重写 - NoticeApproval.vue:tabs-wrapper/tabs-panel[type=card] + main-container(v-show 保活); link-table table-bottom-box + useTableHeight;page-panel + customPageCount 记忆; 操作列 operatingTextHandle(通过 / 驳回 text-error,fixed:right); 状态列改用行级 cellClassName(status-color-N,本仓 view-ui-plus 为行级对象语义); 驳回弹窗改 Form + 必填红星,校验失败统一提示「请填写红色星号内容!」 - mock/noticeapi.ts、config/menu.ts:GetUserMod 六条全量对齐并补「待审核」(顺序按平台配置)
This commit is contained in:
@@ -6,11 +6,12 @@ import type { IModule } from "@/store";
|
||||
*/
|
||||
export function getMenuList(): Promise<IModule[]> {
|
||||
const menu: IModule[] = [
|
||||
{ id: 1, modId: 1, name: "已收到", page: "/" },
|
||||
{ id: 2, modId: 2, name: "已发送", page: "/list" },
|
||||
{ id: 3, modId: 3, name: "全部通知", page: "/noticelist" },
|
||||
{ id: 4, modId: 4, name: "通知统计", page: "/stats" },
|
||||
{ id: 21, modId: 21, name: "应用设置", page: "/setting" },
|
||||
{ id: 1000, modId: 1000, name: "已收到", page: "/" },
|
||||
{ id: 2000, modId: 2000, name: "已发送", page: "/list" },
|
||||
{ id: 3000, modId: 3000, name: "全部通知", page: "/noticelist" },
|
||||
{ id: 2100, modId: 2100, name: "待审核", page: "/approval" },
|
||||
{ id: 4000, modId: 4000, name: "通知统计", page: "/stats" },
|
||||
{ id: 5000, modId: 5000, name: "应用设置", page: "/setting" },
|
||||
];
|
||||
return Promise.resolve(menu);
|
||||
}
|
||||
|
||||
@@ -272,11 +272,13 @@ export default [
|
||||
response: () =>
|
||||
ok([
|
||||
// icon:用户中心模块管理配置的 YschIcons 图标名,layout 渲染为 iconfont icon-<名称>
|
||||
{ id: 1, modId: 1, name: "已收到", parentId: 0, page: "/", icon: "sjx", orderNumber: 1, usable: true, children: [] },
|
||||
{ id: 2, modId: 2, name: "已发送", parentId: 0, page: "/list", icon: "fasong", orderNumber: 2, usable: true, children: [] },
|
||||
{ id: 3, modId: 3, name: "全部通知", parentId: 0, page: "/noticelist", icon: "liebiao", orderNumber: 3, usable: true, children: [] },
|
||||
{ id: 4, modId: 4, name: "通知统计", parentId: 0, page: "/stats", icon: "tongji", orderNumber: 4, usable: true, children: [] },
|
||||
{ id: 21, modId: 21, name: "应用设置", parentId: 0, page: "/setting", icon: "shezhi", orderNumber: 5, usable: true, children: [] },
|
||||
// id/modId 与平台模块管理的「配置 ID」一致(对照 /base/GetUserMod 现行数据)
|
||||
{ id: 1000, modId: 1000, name: "已收到", parentId: 0, page: "/", icon: "sjx", orderNumber: 1, usable: true, children: [] },
|
||||
{ id: 2000, modId: 2000, name: "已发送", parentId: 0, page: "/list", icon: "fasong", orderNumber: 2, usable: true, children: [] },
|
||||
{ id: 3000, modId: 3000, name: "全部通知", parentId: 0, page: "/noticelist", icon: "liebiao", orderNumber: 3, usable: true, children: [] },
|
||||
{ id: 2100, modId: 2100, name: "待审核", parentId: 0, page: "/approval", icon: "", orderNumber: 4, usable: true, children: [] },
|
||||
{ id: 4000, modId: 4000, name: "通知统计", parentId: 0, page: "/stats", icon: "tongji", orderNumber: 5, usable: true, children: [] },
|
||||
{ id: 5000, modId: 5000, name: "应用设置", parentId: 0, page: "/setting", icon: "shezhi", orderNumber: 6, usable: true, children: [] },
|
||||
]),
|
||||
},
|
||||
{
|
||||
|
||||
+16
-14
@@ -9,10 +9,12 @@ import type { RouteRecordRaw } from "vue-router";
|
||||
* - /list/detail?serid=&type=、/noticelist/detail?serid=&type=
|
||||
* type: 0=编辑视角(不标读) 1=普通查看(标读)
|
||||
*
|
||||
* modId 是菜单 ↔ 路由的稳定契约(对照后端 GetUserMod 现行数据):
|
||||
* 1=已收到 2=已发送 3=全部通知 4=通知统计 21=应用设置
|
||||
* 发通知为「已发送」的深层子页(modId 22 不在菜单树,meta.parentId=2 关联高亮),
|
||||
* 与 UserBase「应用管理>应用类型管理」范式一致。
|
||||
* modId 是菜单 ↔ 路由的稳定契约(对照后端 /base/GetUserMod 现行数据,即用户中心
|
||||
* 模块管理里的配置 ID):
|
||||
* 1000=已收到 2000=已发送 3000=全部通知 2100=待审核 4000=通知统计 5000=应用设置
|
||||
* 深层子页不在菜单树,编码沿用 UserBase 范式「父模块 ×10 + 序号」并靠 meta.parentId
|
||||
* 关联高亮:/list/new=20001、/list/detail=20002(父 2000),/noticelist/detail=30001(父 3000)。
|
||||
* 深层页编码不得与任何平台一级模块 ID 重复。
|
||||
*/
|
||||
const routes: RouteRecordRaw[] = [
|
||||
// 已收通知(收件箱):后端菜单 page 配置为 "/",即应用入口页
|
||||
@@ -20,14 +22,14 @@ const routes: RouteRecordRaw[] = [
|
||||
path: "/",
|
||||
name: "notice_accept",
|
||||
component: () => import("@/views/notice/NoticeAccept.vue"),
|
||||
meta: { title: "已收到", modId: 1 },
|
||||
meta: { title: "已收到", modId: 1000 },
|
||||
},
|
||||
// 已发送
|
||||
{
|
||||
path: "/list",
|
||||
name: "notice_list",
|
||||
component: () => import("@/views/notice/NoticeList.vue"),
|
||||
meta: { title: "已发送", modId: 2 },
|
||||
meta: { title: "已发送", modId: 2000 },
|
||||
},
|
||||
// 发通知(新建/编辑/转发/模板):已发送的深层子页,不在菜单里,
|
||||
// layout.vue 按.meta.parentId 推导面包屑「已发送>发通知」并高亮父菜单
|
||||
@@ -35,14 +37,14 @@ const routes: RouteRecordRaw[] = [
|
||||
path: "/list/new",
|
||||
name: "new_notice",
|
||||
component: () => import("@/views/notice/NewNotice.vue"),
|
||||
meta: { title: "发通知", modId: 22, parentId: 2 },
|
||||
meta: { title: "发通知", modId: 20001, parentId: 2000 },
|
||||
},
|
||||
// 全部通知(管理端)
|
||||
{
|
||||
path: "/noticelist",
|
||||
name: "notice_manage",
|
||||
component: () => import("@/views/notice/NoticeList.vue"),
|
||||
meta: { title: "全部通知", modId: 3 },
|
||||
meta: { title: "全部通知", modId: 3000 },
|
||||
},
|
||||
// 通知详情(同一组件挂两个路由,面包屑/菜单高亮由 meta.parentId 确定父节点:
|
||||
// 已发送下 /list/detail,全部通知下 /noticelist/detail;type 区分是否标读)
|
||||
@@ -50,34 +52,34 @@ const routes: RouteRecordRaw[] = [
|
||||
path: "/list/detail",
|
||||
name: "notice_list_detail",
|
||||
component: () => import("@/views/notice/NoticeDetails.vue"),
|
||||
meta: { title: "通知详情", modId: 23, parentId: 2 },
|
||||
meta: { title: "通知详情", modId: 20002, parentId: 2000 },
|
||||
},
|
||||
{
|
||||
path: "/noticelist/detail",
|
||||
name: "notice_manage_detail",
|
||||
component: () => import("@/views/notice/NoticeDetails.vue"),
|
||||
meta: { title: "通知详情", modId: 24, parentId: 3 },
|
||||
meta: { title: "通知详情", modId: 30001, parentId: 3000 },
|
||||
},
|
||||
// 通知统计(旧版行为:整页跳转外部统计系统)
|
||||
{
|
||||
path: "/stats",
|
||||
name: "notice_stats",
|
||||
component: () => import("@/views/notice/NoticeStats.vue"),
|
||||
meta: { title: "通知统计", modId: 4 },
|
||||
meta: { title: "通知统计", modId: 4000 },
|
||||
},
|
||||
// 应用设置(发文部门 + 自定义组)
|
||||
{
|
||||
path: "/setting",
|
||||
name: "notice_setting",
|
||||
component: () => import("@/views/notice/NoticeSetting.vue"),
|
||||
meta: { title: "应用设置", modId: 21 },
|
||||
meta: { title: "应用设置", modId: 5000 },
|
||||
},
|
||||
// 我的待审核(应用内审批;modId 23 深层页不在菜单树,菜单挂载待后端 GetUserMod 配置)
|
||||
// 待审核(应用内审批;平台模块管理已挂一级菜单,配置 ID = 2100,path = /approval)
|
||||
{
|
||||
path: "/approval",
|
||||
name: "notice_approval",
|
||||
component: () => import("@/views/notice/NoticeApproval.vue"),
|
||||
meta: { title: "我的待审核", modId: 23, parentId: 2 },
|
||||
meta: { title: "我的待审核", modId: 2100 },
|
||||
},
|
||||
|
||||
/* ---- 旧版路径兼容重定向(书签、残留的平台模块配置) ---- */
|
||||
|
||||
+186
-119
@@ -1,129 +1,77 @@
|
||||
<template>
|
||||
<div class="approval-page">
|
||||
<Tabs v-model="tab" @on-click="load">
|
||||
<TabPane label="我的待审核" name="todo" />
|
||||
<TabPane label="办件视角" name="instances" />
|
||||
</Tabs>
|
||||
|
||||
<!-- 待审核列表 -->
|
||||
<div v-if="tab === 'todo'">
|
||||
<Table :columns="todoCols" :data="todoRows" :loading="loading" no-data-text="暂无待审核通知">
|
||||
<template #opinion="{ row }">
|
||||
<span class="opinion">{{ row._opinion }}</span>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Button size="small" type="primary" :loading="acting" @click="approve(row)">通过</Button>
|
||||
<Button size="small" type="error" style="margin-left: 6px" @click="openReject(row)"
|
||||
>驳回</Button
|
||||
>
|
||||
</template>
|
||||
</Table>
|
||||
<Page
|
||||
v-if="todoPage.total > todoPage.pageSize"
|
||||
:current="todoPage.pageIndex"
|
||||
:page-size="todoPage.pageSize"
|
||||
:total="todoPage.total"
|
||||
show-total
|
||||
style="margin-top: 14px; text-align: right"
|
||||
@on-change="loadTodo"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 办件视角 -->
|
||||
<div v-else>
|
||||
<div class="filter-bar">
|
||||
<RadioGroup v-model="instStatus" type="button" @on-change="loadInstances(1)">
|
||||
<Radio :label="0">全部</Radio>
|
||||
<Radio :label="10">审批中</Radio>
|
||||
<Radio :label="20">已完成</Radio>
|
||||
<Radio :label="30">已拒绝</Radio>
|
||||
<Radio :label="40">已撤回</Radio>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<Table :columns="instCols" :data="instRows" :loading="loading" no-data-text="暂无办件">
|
||||
<template #status="{ row }">
|
||||
<Tag :color="instStatusColor(row.status)">{{ instStatusText(row.status) }}</Tag>
|
||||
</template>
|
||||
</Table>
|
||||
<Page
|
||||
v-if="instPage.total > instPage.pageSize"
|
||||
:current="instPage.pageIndex"
|
||||
:page-size="instPage.pageSize"
|
||||
:total="instPage.total"
|
||||
show-total
|
||||
style="margin-top: 14px; text-align: right"
|
||||
@on-change="loadInstances"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 驳回弹窗:意见必填 -->
|
||||
<Modal
|
||||
v-model="rejectVisible"
|
||||
title="驳回审核"
|
||||
:loading="acting"
|
||||
@on-ok="doReject"
|
||||
@on-cancel="rejectTaskId = null"
|
||||
>
|
||||
<p style="margin-bottom: 8px">
|
||||
驳回「<b>{{ rejectTitle }}</b
|
||||
>」,必须填写意见:
|
||||
</p>
|
||||
<Input v-model="rejectOpinion" type="textarea" :rows="3" placeholder="驳回意见(必填)" />
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import { ref, reactive, computed, onMounted, nextTick } from "vue";
|
||||
import { Message } from "view-ui-plus";
|
||||
import approvalApi, {
|
||||
type ApprovalInstance,
|
||||
type ApprovalTodoTask,
|
||||
} from "@/api/module/approval";
|
||||
import Utils from "@/utils";
|
||||
|
||||
/**
|
||||
* 我的待审核(应用内审批,第三步):待办列表 + 办件视角,通过/驳回走本应用后端代理
|
||||
* (operator=登录态,对端按任务办理人复核;非办理人会收到业务错提示)。
|
||||
* bizSnapshot 是发起时透传的 JSON 摘要,解析失败只展示标题。
|
||||
* 我的待审核(应用内审批,第三步):待办列表 + 办件视角。
|
||||
* 通过/驳回走本应用后端代理(operator=登录态,对端按任务办理人复核;非办理人会收到业务错提示)。
|
||||
* bizSnapshot 是发起时透传的 JSON 摘要,解析失败只展示标题。
|
||||
*
|
||||
* 规范:bsch应用页规范 §1(tabs-wrapper + tabs-panel type=card,切换只 v-show)、
|
||||
* §2(操作列 operatingHandle 文字链式)、§3(customPageCount 页长记忆)、§8(必填红星 + 统一提示)。
|
||||
*/
|
||||
const tab = ref<"todo" | "instances">("todo");
|
||||
const loading = ref(false);
|
||||
const acting = ref(false);
|
||||
|
||||
/* ============ 分页(规范 §3:customPageCount 页长记忆) ============ */
|
||||
const defaultSize = parseInt(localStorage.getItem("customPageCount") || "10");
|
||||
const todoRows = ref<(ApprovalTodoTask & { _summary: string })[]>([]);
|
||||
const todoPage = ref({ total: 0, pageIndex: 1, pageSize: 10 });
|
||||
const todoPage = ref({ total: 0, pageIndex: 1, pageSize: defaultSize });
|
||||
|
||||
const instRows = ref<ApprovalInstance[]>([]);
|
||||
const instPage = ref({ total: 0, pageIndex: 1, pageSize: 10 });
|
||||
const instRows = ref<(ApprovalInstance & { cellClassName?: Record<string, string> })[]>([]);
|
||||
const instPage = ref({ total: 0, pageIndex: 1, pageSize: defaultSize });
|
||||
const instStatus = ref(0);
|
||||
|
||||
const tableHeight = computed(() => Utils.useTableHeight({ isTabs: true, isSearch: true, isPage: true }));
|
||||
|
||||
/* ============ 驳回弹窗(规范 §1/§8:必填红星 + 统一提示"请填写红色星号内容!") ============ */
|
||||
const rejectVisible = ref(false);
|
||||
const rejectTaskId = ref<number | null>(null);
|
||||
const rejectTitle = ref("");
|
||||
const rejectOpinion = ref("");
|
||||
const rejectFormRef = ref();
|
||||
const rejectForm = reactive({ opinion: "" });
|
||||
const rejectRule = {
|
||||
opinion: [{ required: true, message: "请输入驳回意见", trigger: "blur" }],
|
||||
};
|
||||
|
||||
const todoCols = [
|
||||
{ title: "通知", key: "bizTitle", minWidth: 220, ellipsis: true, tooltip: true },
|
||||
{ title: "摘要", key: "_summary", minWidth: 200, ellipsis: true, tooltip: true },
|
||||
{ title: "当前节点", key: "nodeName", width: 110 },
|
||||
{ title: "到达时间", key: "arriveTime", width: 170, render: fmtTime },
|
||||
{ title: "操作", slot: "action", width: 150 },
|
||||
{ title: "通知", key: "bizTitle", minWidth: 220, align: "left", ellipsis: true, tooltip: true },
|
||||
{ title: "摘要", key: "_summary", minWidth: 200, align: "left", ellipsis: true, tooltip: true },
|
||||
{ title: "当前节点", key: "nodeName", width: 110, align: "center" },
|
||||
{ title: "到达时间", key: "arriveTime", width: 170, align: "center", render: fmtTime },
|
||||
{
|
||||
title: "操作",
|
||||
width: 180,
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
render: (h: any, p: any) => [
|
||||
Utils.operatingTextHandle(h, "通过", "", () => approve(p.row)),
|
||||
Utils.operatingTextHandle(h, "驳回", "text-error", () => openReject(p.row)),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const instCols = [
|
||||
{ title: "通知", key: "bizTitle", minWidth: 240, ellipsis: true, tooltip: true },
|
||||
{ title: "状态", slot: "status", width: 100 },
|
||||
{ title: "提交人", key: "submitterName", width: 100 },
|
||||
{ title: "提交时间", key: "submitTime", width: 170, render: fmtTime },
|
||||
{ title: "办结时间", key: "finishTime", width: 170, render: fmtTime },
|
||||
{ title: "通知", key: "bizTitle", minWidth: 240, align: "left", ellipsis: true, tooltip: true },
|
||||
{
|
||||
title: "状态",
|
||||
width: 100,
|
||||
align: "center",
|
||||
render: (h: any, p: any) => h("span", {}, instStatusText(p.row.status)),
|
||||
},
|
||||
{ title: "提交人", key: "submitterName", width: 110, align: "center" },
|
||||
{ title: "提交时间", key: "submitTime", width: 170, align: "center", render: fmtTime },
|
||||
{ title: "办结时间", key: "finishTime", width: 170, align: "center", render: fmtTime },
|
||||
];
|
||||
|
||||
function fmtTime(h: any, p: any) {
|
||||
return h(
|
||||
"span",
|
||||
{},
|
||||
String(p.row[p.column.key] || "").replace("T", " ").slice(0, 19) || "—"
|
||||
);
|
||||
return h("span", {}, String(p.row[p.column.key] || "").replace("T", " ").slice(0, 19) || "—");
|
||||
}
|
||||
|
||||
function parseSummary(task: ApprovalTodoTask): string {
|
||||
@@ -136,6 +84,17 @@ function parseSummary(task: ApprovalTodoTask): string {
|
||||
}
|
||||
}
|
||||
|
||||
/* ============ Tab(规范 §1:切换只 v-show,两列表分页状态各自独立) ============ */
|
||||
function tabChange(name: string) {
|
||||
tab.value = name as "todo" | "instances";
|
||||
load();
|
||||
}
|
||||
|
||||
function load() {
|
||||
if (tab.value === "todo") loadTodo(1);
|
||||
else loadInstances(1);
|
||||
}
|
||||
|
||||
async function loadTodo(page = 1) {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -156,7 +115,11 @@ async function loadInstances(page = 1) {
|
||||
.instances(instStatus.value || undefined, page, instPage.value.pageSize)
|
||||
.send();
|
||||
instPage.value = res;
|
||||
instRows.value = res.content || [];
|
||||
instRows.value = (res.content || []).map((r) => ({
|
||||
...r,
|
||||
// 状态列主题色(规范 §7):view-ui-plus 的 cellClassName 挂在行上,按列 key 取
|
||||
cellClassName: { status: instStatusClass(r.status) },
|
||||
}));
|
||||
} catch (e: any) {
|
||||
Message.error(e?.message || "办件列表加载失败");
|
||||
} finally {
|
||||
@@ -164,12 +127,25 @@ async function loadInstances(page = 1) {
|
||||
}
|
||||
}
|
||||
|
||||
function load() {
|
||||
if (tab.value === "todo") {
|
||||
loadTodo(1);
|
||||
} else {
|
||||
loadInstances(1);
|
||||
}
|
||||
function todoPageUpdate(p: number) {
|
||||
todoPage.value.pageIndex = p;
|
||||
loadTodo(p);
|
||||
}
|
||||
function todoPageSizeUpdate(size: number) {
|
||||
todoPage.value.pageIndex = 1;
|
||||
todoPage.value.pageSize = size;
|
||||
localStorage.setItem("customPageCount", String(size));
|
||||
loadTodo(1);
|
||||
}
|
||||
function instPageUpdate(p: number) {
|
||||
instPage.value.pageIndex = p;
|
||||
loadInstances(p);
|
||||
}
|
||||
function instPageSizeUpdate(size: number) {
|
||||
instPage.value.pageIndex = 1;
|
||||
instPage.value.pageSize = size;
|
||||
localStorage.setItem("customPageCount", String(size));
|
||||
loadInstances(1);
|
||||
}
|
||||
|
||||
async function approve(row: ApprovalTodoTask) {
|
||||
@@ -179,7 +155,7 @@ async function approve(row: ApprovalTodoTask) {
|
||||
Message.success("已通过");
|
||||
loadTodo(todoPage.value.pageIndex);
|
||||
} catch (e: any) {
|
||||
// 非办理人/已被办理等业务错,后端信封 msg 直接展示
|
||||
// 非办理人/已被办理等业务错,后端信封 msg 直接展示
|
||||
Message.error(e?.message || "操作失败");
|
||||
} finally {
|
||||
acting.value = false;
|
||||
@@ -189,18 +165,20 @@ async function approve(row: ApprovalTodoTask) {
|
||||
function openReject(row: ApprovalTodoTask) {
|
||||
rejectTaskId.value = row.taskId;
|
||||
rejectTitle.value = row.bizTitle;
|
||||
rejectOpinion.value = "";
|
||||
rejectForm.opinion = "";
|
||||
rejectVisible.value = true;
|
||||
nextTick(() => rejectFormRef.value?.resetFields());
|
||||
}
|
||||
|
||||
async function doReject() {
|
||||
if (!rejectOpinion.value.trim()) {
|
||||
Message.warning("驳回必须填写意见");
|
||||
const valid = await rejectFormRef.value?.validate();
|
||||
if (!valid) {
|
||||
Message.info("请填写红色星号内容!");
|
||||
return;
|
||||
}
|
||||
acting.value = true;
|
||||
try {
|
||||
await approvalApi.reject(rejectTaskId.value!, rejectOpinion.value.trim()).send();
|
||||
await approvalApi.reject(rejectTaskId.value!, rejectForm.opinion.trim()).send();
|
||||
Message.success("已驳回");
|
||||
rejectVisible.value = false;
|
||||
loadTodo(todoPage.value.pageIndex);
|
||||
@@ -211,22 +189,111 @@ async function doReject() {
|
||||
}
|
||||
}
|
||||
|
||||
/* 状态文案 / 主题状态色(规范 §7:cellClassName 挂 .status-color-N) */
|
||||
function instStatusText(s: number) {
|
||||
return ({ 10: "审批中", 20: "已完成", 30: "已拒绝", 40: "已撤回" } as Record<number, string>)[s] || String(s);
|
||||
}
|
||||
|
||||
function instStatusColor(s: number) {
|
||||
return ({ 10: "blue", 20: "green", 30: "red", 40: "default" } as Record<number, string>)[s] || "default";
|
||||
function instStatusClass(s: number) {
|
||||
return ({ 10: "status-color-2", 20: "status-color-3", 30: "status-color-4", 40: "status-color-1" } as Record<number, string>)[s] || "";
|
||||
}
|
||||
|
||||
onMounted(load);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.approval-page {
|
||||
padding: 12px 0;
|
||||
}
|
||||
.filter-bar {
|
||||
margin-bottom: 12px;
|
||||
<template>
|
||||
<div class="tabs-wrapper">
|
||||
<Tabs class="tabs-panel" type="card" :value="tab" @on-click="tabChange">
|
||||
<TabPane label="我的待审核" name="todo"></TabPane>
|
||||
<TabPane label="办件视角" name="instances"></TabPane>
|
||||
</Tabs>
|
||||
|
||||
<!-- 我的待审核 -->
|
||||
<div class="main-container" v-show="tab === 'todo'">
|
||||
<div class="search-wrap fix">
|
||||
<Button class="fl" @click="loadTodo(1)">刷新</Button>
|
||||
</div>
|
||||
<Table
|
||||
:columns="todoCols"
|
||||
:data="todoRows"
|
||||
class="link-table table-bottom-box"
|
||||
:height="tableHeight"
|
||||
:loading="loading"
|
||||
no-data-text="暂无待审核通知"
|
||||
></Table>
|
||||
<div class="page-panel">
|
||||
<div class="fl ml-15 align-middle"></div>
|
||||
<Page
|
||||
class="page-box fr"
|
||||
:total="todoPage.total"
|
||||
:current="todoPage.pageIndex"
|
||||
:page-size="todoPage.pageSize"
|
||||
:page-size-opts="[10, 20, 30, 40]"
|
||||
@on-page-size-change="todoPageSizeUpdate"
|
||||
@on-change="todoPageUpdate"
|
||||
placement="top"
|
||||
show-total
|
||||
show-sizer
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 办件视角 -->
|
||||
<div class="main-container" v-show="tab === 'instances'">
|
||||
<div class="search-wrap fix">
|
||||
<RadioGroup v-model="instStatus" class="fl" type="button" @on-change="loadInstances(1)">
|
||||
<Radio :label="0">全部</Radio>
|
||||
<Radio :label="10">审批中</Radio>
|
||||
<Radio :label="20">已完成</Radio>
|
||||
<Radio :label="30">已拒绝</Radio>
|
||||
<Radio :label="40">已撤回</Radio>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<Table
|
||||
:columns="instCols"
|
||||
:data="instRows"
|
||||
class="link-table table-bottom-box"
|
||||
:height="tableHeight"
|
||||
:loading="loading"
|
||||
no-data-text="暂无办件"
|
||||
></Table>
|
||||
<div class="page-panel">
|
||||
<div class="fl ml-15 align-middle"></div>
|
||||
<Page
|
||||
class="page-box fr"
|
||||
:total="instPage.total"
|
||||
:current="instPage.pageIndex"
|
||||
:page-size="instPage.pageSize"
|
||||
:page-size-opts="[10, 20, 30, 40]"
|
||||
@on-page-size-change="instPageSizeUpdate"
|
||||
@on-change="instPageUpdate"
|
||||
placement="top"
|
||||
show-total
|
||||
show-sizer
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 驳回弹窗:意见必填 -->
|
||||
<Modal v-model="rejectVisible" :mask-closable="false" width="450px" title="驳回审核">
|
||||
<Form ref="rejectFormRef" :model="rejectForm" :rules="rejectRule" :label-width="90">
|
||||
<FormItem label="通知:">
|
||||
<span class="reject-title">{{ rejectTitle || "—" }}</span>
|
||||
</FormItem>
|
||||
<FormItem label="驳回意见:" prop="opinion">
|
||||
<Input type="textarea" :rows="3" placeholder="请输入驳回意见" v-model="rejectForm.opinion" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<Button type="primary" :loading="acting" @click="doReject">提交</Button>
|
||||
<Button @click="rejectVisible = false">取消</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.reject-title {
|
||||
color: #515a6e;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user