fix(ui): 用户验收反馈 R2——单卡片骨架+实测高度对齐 Notice、应用管理启用/停用、Tag 真组件、科室行 deptKey、成员多选、顶栏去房子图标钮
build / build (push) Successful in 4m4s
build / build (push) Successful in 4m4s
This commit is contained in:
@@ -2,17 +2,15 @@
|
||||
// 我的办件(提交人视角):列表 + 撤回/催办/详情
|
||||
import { ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { Message } from "view-ui-plus";
|
||||
import { Message, Tag } from "view-ui-plus";
|
||||
import MyConfirm from "@/components/MyConfirm";
|
||||
import TablePageAlovaNew from "@/components/TablePageAlovaNew.vue";
|
||||
import { OperatorEnum } from "@/types";
|
||||
import { flowApi, INSTANCE_STATUS, INSTANCE_STATUS_COLOR } from "@/api/module/flow";
|
||||
import { actionColumn } from "@/utils/tableActions";
|
||||
import Utils from "@/utils";
|
||||
|
||||
const router = useRouter();
|
||||
const tableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||
const tableHeight = ref(Utils.useTableHeight({ isSearch: true, isPage: true }));
|
||||
const dataParams = ref<{ status?: number }>({ status: undefined });
|
||||
|
||||
const columns = [
|
||||
@@ -20,7 +18,7 @@ const columns = [
|
||||
{ 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) },
|
||||
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", " ") || "-") },
|
||||
@@ -70,7 +68,7 @@ async function onUrge(row: any) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-wrapper">
|
||||
<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">
|
||||
@@ -80,7 +78,7 @@ async function onUrge(row: any) {
|
||||
<Option :value="40" label="已撤回" />
|
||||
</Select>
|
||||
</div>
|
||||
<TablePageAlovaNew ref="tableRef" :dataApi="tableApi" :columns="columns" :tableHeight="tableHeight" />
|
||||
<TablePageAlovaNew ref="tableRef" :dataApi="tableApi" :columns="columns" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,19 +3,17 @@
|
||||
// 规范骨架(bsch应用页规范 §1):tabs-wrapper + Tabs type=card,Tab 切换只 v-show 内容区,分页状态各自独立
|
||||
import { ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { Tag } from "view-ui-plus";
|
||||
import TablePageAlovaNew from "@/components/TablePageAlovaNew.vue";
|
||||
import { OperatorEnum } from "@/types";
|
||||
import { flowApi, TASK_STATUS, TASK_STATUS_COLOR, INSTANCE_STATUS } from "@/api/module/flow";
|
||||
import { actionColumn } from "@/utils/tableActions";
|
||||
import Utils from "@/utils";
|
||||
|
||||
const router = useRouter();
|
||||
const tab = ref<"todo" | "done" | "cc">("todo");
|
||||
const todoTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||
const doneTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||
const ccTableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||
// tabs 页:表格高度在常规骨架上再扣 Tab 条
|
||||
const tableHeight = ref(Utils.useTableHeight({ isTabs: true, isOperat: true, isPage: true }));
|
||||
|
||||
const todoColumns = [
|
||||
{ title: "序号", type: "index", width: 70, align: "center" },
|
||||
@@ -35,13 +33,13 @@ const doneColumns = [
|
||||
title: "节点", minWidth: 150, render: (h: any, p: any) => {
|
||||
const kids: any[] = [h("span", p.row.nodeName || p.row.nodeId || "-")];
|
||||
if (p.row.doneCount > 1) {
|
||||
kids.push(h("Tag", { color: "default", size: "small", style: "margin-left:6px" },
|
||||
kids.push(h(Tag, { color: "default", size: "small", style: "margin-left:6px" },
|
||||
() => `共办理 ${p.row.doneCount} 次`));
|
||||
}
|
||||
return h("div", kids);
|
||||
},
|
||||
},
|
||||
{ title: "结果", width: 90, align: "center", render: (h: any, p: any) => h("Tag", { color: TASK_STATUS_COLOR[p.row.status] || "default" }, () => TASK_STATUS[p.row.status] || p.row.status) },
|
||||
{ title: "结果", width: 90, align: "center", render: (h: any, p: any) => h(Tag, { color: TASK_STATUS_COLOR[p.row.status] || "default" }, () => TASK_STATUS[p.row.status] || p.row.status) },
|
||||
{ title: "意见", key: "opinion", minWidth: 120 },
|
||||
{ title: "办理时间", width: 170, render: (h: any, p: any) => h("span", (p.row.handleTime || "").replace("T", " ")) },
|
||||
{ title: "办件状态", width: 100, render: (h: any, p: any) => h("span", INSTANCE_STATUS[p.row.instanceStatus] || p.row.instanceStatus) },
|
||||
@@ -84,21 +82,23 @@ function switchTab(name: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="tabs-wrapper">
|
||||
<Tabs class="tabs-panel" :value="tab" @on-click="switchTab">
|
||||
<TabPane label="我的待办" name="todo" />
|
||||
<TabPane label="我的已办" name="done" />
|
||||
<TabPane label="抄送我的" name="cc" />
|
||||
</Tabs>
|
||||
<div class="tabs-wrapper yh-fill">
|
||||
<div class="main-container yh-tabs-card">
|
||||
<Tabs class="tabs-panel" :value="tab" @on-click="switchTab">
|
||||
<TabPane label="我的待办" name="todo" />
|
||||
<TabPane label="我的已办" name="done" />
|
||||
<TabPane label="抄送我的" name="cc" />
|
||||
</Tabs>
|
||||
|
||||
<div class="main-container" v-show="tab === 'todo'">
|
||||
<TablePageAlovaNew ref="todoTableRef" :dataApi="todoApi" :columns="todoColumns" :tableHeight="tableHeight" />
|
||||
</div>
|
||||
<div class="main-container" v-show="tab === 'done'">
|
||||
<TablePageAlovaNew ref="doneTableRef" :dataApi="doneApi" :columns="doneColumns" :tableHeight="tableHeight" :autoLoad="false" />
|
||||
</div>
|
||||
<div class="main-container" v-show="tab === 'cc'">
|
||||
<TablePageAlovaNew ref="ccTableRef" :dataApi="ccApi" :columns="ccColumns" :tableHeight="tableHeight" :autoLoad="false" />
|
||||
<div class="tab-body" v-show="tab === 'todo'">
|
||||
<TablePageAlovaNew ref="todoTableRef" :dataApi="todoApi" :columns="todoColumns" />
|
||||
</div>
|
||||
<div class="tab-body" v-show="tab === 'done'">
|
||||
<TablePageAlovaNew ref="doneTableRef" :dataApi="doneApi" :columns="doneColumns" :autoLoad="false" />
|
||||
</div>
|
||||
<div class="tab-body" v-show="tab === 'cc'">
|
||||
<TablePageAlovaNew ref="ccTableRef" :dataApi="ccApi" :columns="ccColumns" :autoLoad="false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,42 +3,40 @@
|
||||
// tab2 科室管理(flw_dept 组+成员模型,取代旧「办理人映射」页——deptKey=本地自增 id,
|
||||
// 切源后旧流程定义引用的 UserBase 组 id 需重建科室后重新配置)。
|
||||
import { ref, onMounted } from "vue";
|
||||
import { Message } from "view-ui-plus";
|
||||
import { Message, Tag } from "view-ui-plus";
|
||||
import MyConfirm from "@/components/MyConfirm";
|
||||
import UserSelectInput from "@/components/UserSelectInput.vue";
|
||||
import UserCheckModal from "@/components/UserCheckModal.vue";
|
||||
import { flowApi } from "@/api/module/flow";
|
||||
import { actionColumn } from "@/utils/tableActions";
|
||||
import Utils from "@/utils";
|
||||
import { useElementHeight } from "@/utils/hook/useElementHeight";
|
||||
|
||||
const tab = ref("apps");
|
||||
|
||||
// ==================== tab1 应用管理 ====================
|
||||
const loading = ref(false);
|
||||
const rows = ref<any[]>([]);
|
||||
const tableHeight = ref(Utils.useTableHeight({ isOperat: true }));
|
||||
const appRegionRef = ref<HTMLElement | null>(null);
|
||||
const appH = useElementHeight(appRegionRef);
|
||||
|
||||
const columns = [
|
||||
{ title: "序号", type: "index", width: 70, align: "center" },
|
||||
{ title: "应用", key: "appName", minWidth: 200 },
|
||||
{ title: "appKey", key: "appKey", width: 120, align: "center" },
|
||||
{
|
||||
title: "对接流程",
|
||||
width: 120,
|
||||
align: "center",
|
||||
render: (h: any, p: any) =>
|
||||
h("i-switch", {
|
||||
props: { value: p.row.enabled === 1, size: "large", loading: p.row._switching },
|
||||
on: { "on-change": (v: boolean) => onToggle(p.row, v) },
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h: any, p: any) =>
|
||||
h("Tag", { props: { color: p.row.enabled === 1 ? "green" : "gray" } },
|
||||
h(Tag, { color: p.row.enabled === 1 ? "green" : "gray" },
|
||||
() => (p.row.enabled === 1 ? "已开启" : "已停用")),
|
||||
},
|
||||
actionColumn(
|
||||
[
|
||||
{ key: "disable", label: "停用", icon: "icon-stop", on: (r: any) => onToggle(r, false), disabledWhen: (r: any) => r.enabled !== 1, danger: true },
|
||||
{ key: "enable", label: "启用", icon: "icon-play", on: (r: any) => onToggle(r, true), disabledWhen: (r: any) => r.enabled === 1 },
|
||||
],
|
||||
{ mode: "text", width: 120 },
|
||||
),
|
||||
];
|
||||
|
||||
async function load() {
|
||||
@@ -67,6 +65,8 @@ async function onToggle(row: any, enabled: boolean) {
|
||||
// ==================== tab2 科室管理 ====================
|
||||
const deptLoading = ref(false);
|
||||
const depts = ref<any[]>([]);
|
||||
const deptRegionRef = ref<HTMLElement | null>(null);
|
||||
const deptH = useElementHeight(deptRegionRef);
|
||||
const deptColumns = [
|
||||
{ title: "序号", type: "index", width: 60, align: "center" },
|
||||
{ title: "科室名", key: "deptName", minWidth: 160 },
|
||||
@@ -78,18 +78,12 @@ const deptColumns = [
|
||||
align: "center",
|
||||
render: (h: any, p: any) => h("span", String(p.row.count)),
|
||||
},
|
||||
{
|
||||
title: "来源",
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h: any, p: any) => h("Tag", () => (p.row._pulled ? "拉取" : "手工")),
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
width: 80,
|
||||
align: "center",
|
||||
render: (h: any, p: any) =>
|
||||
h("Tag", { props: { color: p.row.status === 0 ? "green" : "gray" } },
|
||||
h(Tag, { color: p.row.status === 0 ? "green" : "gray" },
|
||||
() => (p.row.status === 0 ? "启用" : "停用")),
|
||||
},
|
||||
actionColumn(
|
||||
@@ -160,7 +154,7 @@ async function doRename() {
|
||||
}
|
||||
renameSaving.value = true;
|
||||
try {
|
||||
await flowApi.deptRename(renameRow.value.id, renameName.value.trim()).send();
|
||||
await flowApi.deptRename(renameRow.value.deptKey, renameName.value.trim()).send();
|
||||
Message.success("已改名");
|
||||
renameVisible.value = false;
|
||||
loadDepts();
|
||||
@@ -180,7 +174,7 @@ function onDeptStatus(row: any, enabled: boolean) {
|
||||
? "引用它的流程节点恢复解析到科室成员"
|
||||
: "停用后引用它的流程定义不能发布;在途办件推进到该节点会报无可用办理人",
|
||||
async onOk() {
|
||||
await flowApi.deptStatus(row.id, enabled).send();
|
||||
await flowApi.deptStatus(row.deptKey, enabled).send();
|
||||
Message.success("操作成功");
|
||||
loadDepts();
|
||||
},
|
||||
@@ -193,7 +187,7 @@ function onDelete(row: any) {
|
||||
msg: `确定删除「${row.deptName}」及其全部成员吗?`,
|
||||
info: "删除后引用该 deptKey 的流程定义节点将解析失败(发布校验拦截/办理报错),请先确认无流程引用",
|
||||
async onOk() {
|
||||
await flowApi.deptDelete(row.id).send();
|
||||
await flowApi.deptDelete(row.deptKey).send();
|
||||
Message.success("已删除");
|
||||
loadDepts();
|
||||
},
|
||||
@@ -205,8 +199,6 @@ const memberVisible = ref(false);
|
||||
const memberRow = ref<any>(null);
|
||||
const members = ref<any[]>([]);
|
||||
const memberLoading = ref(false);
|
||||
const addUserId = ref<number | null>(null);
|
||||
const addUserName = ref("");
|
||||
|
||||
function onMembers(row: any) {
|
||||
memberRow.value = row;
|
||||
@@ -217,22 +209,43 @@ function onMembers(row: any) {
|
||||
async function loadMembers(row: any) {
|
||||
memberLoading.value = true;
|
||||
try {
|
||||
members.value = ((await flowApi.deptMembers(row.id).send()) as any[]) || [];
|
||||
members.value = ((await flowApi.deptMembers(row.deptKey).send()) as any[]) || [];
|
||||
} catch (e: any) {
|
||||
Message.error(e?.message || "成员加载失败");
|
||||
members.value = [];
|
||||
} finally {
|
||||
memberLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function onMemberAdd() {
|
||||
if (!addUserId.value) {
|
||||
// 添加成员:规范选人组件(多选),提交即批量加入当前科室
|
||||
const addMemberCheckRef = ref();
|
||||
const memberSources = [
|
||||
{
|
||||
name: "基础平台",
|
||||
loader: () => flowApi.adminTeacherTree().send() as Promise<any[]>,
|
||||
},
|
||||
];
|
||||
|
||||
function onAddMemberShow() {
|
||||
addMemberCheckRef.value?.show();
|
||||
}
|
||||
|
||||
async function onMemberAddSubmit(users: any[]) {
|
||||
if (!users || !users.length) {
|
||||
Message.warning("请先选择用户");
|
||||
return;
|
||||
}
|
||||
const ids = users
|
||||
.map((u: any) => Number(typeof u === "object" && u != null ? u.id : u))
|
||||
.filter((n: number) => Number.isFinite(n) && n > 0);
|
||||
if (!ids.length) {
|
||||
Message.warning("请先选择用户");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const added: any = await flowApi.deptMemberAdd(memberRow.value.id, [addUserId.value]).send();
|
||||
Message.success(added > 0 ? `已添加 ${added} 人` : "该成员已存在");
|
||||
addUserId.value = null;
|
||||
addUserName.value = "";
|
||||
const added: any = await flowApi.deptMemberAdd(memberRow.value.deptKey, ids).send();
|
||||
Message.success(added > 0 ? `已添加 ${added} 人` : "所选成员均已存在");
|
||||
loadMembers(memberRow.value);
|
||||
loadDepts();
|
||||
} catch (e: any) {
|
||||
@@ -298,33 +311,43 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-wrapper">
|
||||
<div class="main-container">
|
||||
<Tabs v-model="tab">
|
||||
<TabPane label="应用管理" name="apps">
|
||||
<div class="fix mb-12">
|
||||
<Button class="fl" type="primary" size="large" @click="load">刷新(同步学校池)</Button>
|
||||
<span class="fl" style="color: #808695; font-size: 12px; line-height: 40px; margin-left: 10px">
|
||||
应用清单来自本校已开通应用(UserBase 学校组开通,含学校别名);开启后可用于流程归属与筛选。
|
||||
新开通/改名在 UserBase 管理端操作后回本页刷新即可
|
||||
</span>
|
||||
</div>
|
||||
<Table :columns="columns" :data="rows" :loading="loading" class="link-table table-bottom-box"
|
||||
:height="tableHeight" no-data-text="本校暂无已开通应用(请先在用户中心开通)" />
|
||||
</TabPane>
|
||||
<TabPane label="科室管理" name="depts">
|
||||
<div class="fix mb-12">
|
||||
<Button class="fl" type="primary" size="large" @click="onCreate">新建科室</Button>
|
||||
<Button class="fl" size="large" style="margin-left: 8px" @click="onGroupPreview">一键拉取教师组</Button>
|
||||
<span class="fl" style="color: #808695; font-size: 12px; line-height: 40px; margin-left: 10px">
|
||||
流程节点「按科室」办理的解析源;重复拉取=刷新组名与成员集(不重复建组)
|
||||
</span>
|
||||
</div>
|
||||
<Table :columns="deptColumns" :data="depts" :loading="deptLoading" class="link-table table-bottom-box"
|
||||
:height="tableHeight" no-data-text="暂无科室(可一键拉取教师组或手工新建)" />
|
||||
</TabPane>
|
||||
<div class="page-wrapper yh-fill">
|
||||
<div class="main-container yh-tabs-card">
|
||||
<Tabs class="tabs-panel" v-model="tab">
|
||||
<TabPane label="应用管理" name="apps"></TabPane>
|
||||
<TabPane label="科室管理" name="depts"></TabPane>
|
||||
</Tabs>
|
||||
|
||||
<!-- 应用管理 -->
|
||||
<div class="tab-body" v-show="tab === 'apps'">
|
||||
<div class="fix mb-12">
|
||||
<Button class="fl" type="primary" size="large" @click="load">刷新(同步学校池)</Button>
|
||||
<span class="fl" style="color: #808695; font-size: 12px; line-height: 40px; margin-left: 10px">
|
||||
应用清单来自本校已开通应用(UserBase 学校组开通,含学校别名);开启后可用于流程归属与筛选。
|
||||
新开通/改名在 UserBase 管理端操作后回本页刷新即可
|
||||
</span>
|
||||
</div>
|
||||
<div class="table-region" ref="appRegionRef">
|
||||
<Table :columns="columns" :data="rows" :loading="loading" class="link-table table-bottom-box"
|
||||
:height="appH || undefined" no-data-text="本校暂无已开通应用(请先在用户中心开通)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 科室管理 -->
|
||||
<div class="tab-body" v-show="tab === 'depts'">
|
||||
<div class="fix mb-12">
|
||||
<Button class="fl" type="primary" size="large" @click="onCreate">新建科室</Button>
|
||||
<Button class="fl" size="large" style="margin-left: 8px" @click="onGroupPreview">一键拉取教师组</Button>
|
||||
<span class="fl" style="color: #808695; font-size: 12px; line-height: 40px; margin-left: 10px">
|
||||
流程节点「按科室」办理的解析源;重复拉取=刷新组名与成员集(不重复建组)
|
||||
</span>
|
||||
</div>
|
||||
<div class="table-region" ref="deptRegionRef">
|
||||
<Table :columns="deptColumns" :data="depts" :loading="deptLoading" class="link-table table-bottom-box"
|
||||
:height="deptH || undefined" no-data-text="暂无科室(可一键拉取教师组或手工新建)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal v-model="createVisible" title="新建科室" :mask-closable="false">
|
||||
<Input v-model="createName" placeholder="科室名称,如 人事处" :maxlength="30" />
|
||||
<template #footer>
|
||||
@@ -343,15 +366,7 @@ onMounted(() => {
|
||||
|
||||
<Modal v-model="memberVisible" :title="`成员维护 - ${memberRow?.deptName || ''}`" :mask-closable="false" width="640">
|
||||
<div class="fix" style="margin-bottom: 10px">
|
||||
<UserSelectInput
|
||||
class="fl"
|
||||
style="width: 260px"
|
||||
:model-value="addUserId"
|
||||
:display-name="addUserName"
|
||||
@update:model-value="addUserId = $event"
|
||||
@update:display-name="addUserName = $event"
|
||||
/>
|
||||
<Button class="fl" type="primary" style="margin-left: 8px" @click="onMemberAdd">添加</Button>
|
||||
<Button class="fl" type="primary" icon="md-add" @click="onAddMemberShow">添加成员</Button>
|
||||
</div>
|
||||
<Table :columns="[
|
||||
{ title: '用户ID', key: 'userId', width: 100 },
|
||||
@@ -374,6 +389,9 @@ onMounted(() => {
|
||||
<Button type="primary" :loading="groupImporting" :disabled="!groupRows.length" @click="onGroupImport">导入</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
||||
<!-- 添加成员选人弹窗(多选,与 Notice 设置中心同款组件) -->
|
||||
<UserCheckModal ref="addMemberCheckRef" :sources="memberSources" @on-submit="onMemberAddSubmit" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// 回调管理(概览 §9.2):注册列表/启停/secret 重置 + 推送日志 + 挂起(持续重试可视/标记死信)+ 死信重推。
|
||||
// 规范骨架(bsch应用页规范 §1):tabs-wrapper + Tabs type=card,Tab 切换只 v-show 内容区;「重推选中」落在分页栏左侧批量操作位
|
||||
import { ref, onMounted } from "vue";
|
||||
import { Message } from "view-ui-plus";
|
||||
import { Message, Tag } from "view-ui-plus";
|
||||
import MyConfirm from "@/components/MyConfirm";
|
||||
import TablePageAlovaNew from "@/components/TablePageAlovaNew.vue";
|
||||
import { OperatorEnum } from "@/types";
|
||||
import { flowApi } from "@/api/module/flow";
|
||||
import { actionColumn } from "@/utils/tableActions";
|
||||
import Utils from "@/utils";
|
||||
import { useElementHeight } from "@/utils/hook/useElementHeight";
|
||||
|
||||
const LOG_STATUS: Record<number, string> = { 0: "待推/重试中", 1: "成功", 2: "死信" };
|
||||
const EVENT_OPTIONS = ["flow.submitted", "flow.task.created", "flow.task.handled", "flow.completed", "flow.rejected", "flow.withdrawn"];
|
||||
@@ -16,10 +16,11 @@ const EVENT_OPTIONS = ["flow.submitted", "flow.task.created", "flow.task.handled
|
||||
const tab = ref("regs");
|
||||
const loading = ref(false);
|
||||
|
||||
// tabs 页高度:在常规骨架上再扣 Tab 条;日志页含搜索区+分页,挂起页含提示条
|
||||
const regsTableHeight = ref(Utils.useTableHeight({ isTabs: true }));
|
||||
const logTableHeight = ref(Utils.useTableHeight({ isTabs: true, isSearch: true, isPage: true }));
|
||||
const hungTableHeight = ref(Utils.useTableHeight({ isTabs: true, otherH: 46 }));
|
||||
// 无分页 tab 的表格高度:实测各自 .table-region(flex:1),替代 useTableHeight 常量减法
|
||||
const regsRegionRef = ref<HTMLElement | null>(null);
|
||||
const hungRegionRef = ref<HTMLElement | null>(null);
|
||||
const regsH = useElementHeight(regsRegionRef);
|
||||
const hungH = useElementHeight(hungRegionRef);
|
||||
|
||||
// ---- 注册列表 ----
|
||||
const regs = ref<any[]>([]);
|
||||
@@ -29,7 +30,7 @@ const regColumns = [
|
||||
{ title: "流程 GUID", key: "flowGuid", width: 210 },
|
||||
{ title: "回调地址", key: "callbackUrl", minWidth: 240 },
|
||||
{ title: "订阅事件", key: "eventTypes", width: 200, render: (h: any, p: any) => h("span", p.row.eventTypes || "全部") },
|
||||
{ title: "状态", width: 80, align: "center", render: (h: any, p: any) => h("Tag", { color: p.row.status === 0 ? "green" : "gray" }, () => (p.row.status === 0 ? "启用" : "停用")) },
|
||||
{ title: "状态", width: 80, align: "center", render: (h: any, p: any) => h(Tag, { color: p.row.status === 0 ? "green" : "gray" }, () => (p.row.status === 0 ? "启用" : "停用")) },
|
||||
actionColumn(
|
||||
[
|
||||
{ key: "disable", label: "停用", icon: "icon-stop", on: (r: any) => onRegStatus(r, true), disabledWhen: (r: any) => r.status !== 0, danger: true },
|
||||
@@ -51,7 +52,7 @@ const logColumns = [
|
||||
{ title: "biz", width: 160, render: (h: any, p: any) => h("span", `${p.row.bizType}/${p.row.bizId}`) },
|
||||
{ title: "状态", width: 110, align: "center", render: (h: any, p: any) => {
|
||||
const c = p.row.status === 1 ? "green" : p.row.status === 2 ? "red" : "orange";
|
||||
return h("Tag", { color: c }, () => LOG_STATUS[p.row.status]);
|
||||
return h(Tag, { color: c }, () => LOG_STATUS[p.row.status]);
|
||||
} },
|
||||
{ title: "重试", key: "retryCount", width: 60, align: "center" },
|
||||
{ title: "末次结果", key: "lastError", minWidth: 200, render: (h: any, p: any) => h("span", p.row.lastError || p.row.lastHttpStatus || "-") },
|
||||
@@ -66,7 +67,7 @@ const hungColumns = [
|
||||
{ title: "事件", key: "event", width: 150 },
|
||||
{ title: "办件", key: "instanceId", width: 80 },
|
||||
{ title: "biz", width: 160, render: (h: any, p: any) => h("span", `${p.row.bizType}/${p.row.bizId}`) },
|
||||
{ title: "重试", key: "retryCount", width: 70, align: "center", render: (h: any, p: any) => h("Tag", { color: "orange" }, () => `${p.row.retryCount} 次`) },
|
||||
{ title: "重试", key: "retryCount", width: 70, align: "center", render: (h: any, p: any) => h(Tag, { color: "orange" }, () => `${p.row.retryCount} 次`) },
|
||||
{ title: "末次结果", key: "lastError", minWidth: 220, render: (h: any, p: any) => h("span", p.row.lastError || p.row.lastHttpStatus || "-") },
|
||||
{ title: "下次重推", width: 160, render: (h: any, p: any) => h("span", (p.row.nextRetryTime || "").replace("T", " ") || "-") },
|
||||
actionColumn([{ key: "markDead", label: "标记死信", icon: "icon-ashbin", on: (r: any) => onMarkDead(r), danger: true }], { mode: "text", width: 120, fixed: "right" }),
|
||||
@@ -175,48 +176,53 @@ onMounted(loadRegs);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="tabs-wrapper">
|
||||
<Tabs class="tabs-panel" :value="tab" @on-click="switchTab">
|
||||
<TabPane label="回调注册" name="regs" />
|
||||
<TabPane label="推送日志" name="logs" />
|
||||
<TabPane label="挂起中" name="hung" />
|
||||
</Tabs>
|
||||
<div class="tabs-wrapper yh-fill">
|
||||
<div class="main-container yh-tabs-card">
|
||||
<Tabs class="tabs-panel" :value="tab" @on-click="switchTab">
|
||||
<TabPane label="回调注册" name="regs" />
|
||||
<TabPane label="推送日志" name="logs" />
|
||||
<TabPane label="挂起中" name="hung" />
|
||||
</Tabs>
|
||||
|
||||
<!-- 回调注册:无分页 -->
|
||||
<div class="main-container" v-show="tab === 'regs'">
|
||||
<Table :columns="regColumns" :data="regs" :loading="loading" class="link-table table-bottom-box"
|
||||
:height="regsTableHeight" no-data-text="暂无数据" />
|
||||
</div>
|
||||
|
||||
<!-- 推送日志:搜索区 + 分页,重推选中落分页栏左侧批量操作位 -->
|
||||
<div class="main-container" v-show="tab === 'logs'">
|
||||
<div class="search-wrap fix">
|
||||
<Select v-model="logFilter.status" class="search-wrap_sel" clearable placeholder="状态" @on-change="onLogSearch">
|
||||
<Option :value="0" label="待推/重试中" />
|
||||
<Option :value="1" label="成功" />
|
||||
<Option :value="2" label="死信" />
|
||||
</Select>
|
||||
<Select v-model="logFilter.event" class="search-wrap_sel ml-12" clearable placeholder="事件" @on-change="onLogSearch">
|
||||
<Option v-for="e in EVENT_OPTIONS" :key="e" :value="e" :label="e" />
|
||||
</Select>
|
||||
<Input class="fr" v-model="logFilter.instanceId" placeholder="办件ID" search suffix="ios-search"
|
||||
style="width: 200px" @on-search="onLogSearch" @on-clear="onLogSearch" />
|
||||
<!-- 回调注册:无分页 -->
|
||||
<div class="tab-body" v-show="tab === 'regs'">
|
||||
<div class="table-region" ref="regsRegionRef">
|
||||
<Table :columns="regColumns" :data="regs" :loading="loading" class="link-table table-bottom-box"
|
||||
:height="regsH || undefined" no-data-text="暂无数据" />
|
||||
</div>
|
||||
</div>
|
||||
<TablePageAlovaNew ref="logTableRef" :dataApi="logApi" :columns="logColumns"
|
||||
:tableHeight="logTableHeight" :autoLoad="false">
|
||||
<template #default="{ checkList }">
|
||||
<Button size="small" type="primary" :disabled="!checkList.length" @click="onRepush(checkList)">重推选中</Button>
|
||||
</template>
|
||||
</TablePageAlovaNew>
|
||||
</div>
|
||||
|
||||
<!-- 挂起中:无分页 -->
|
||||
<div class="main-container" v-show="tab === 'hung'">
|
||||
<div class="tip">
|
||||
持续重试中的事件(消费方疑似停机;消费方恢复后自动追平,无需干预)。仅当人工判定事件已无意义时才标记死信。
|
||||
<!-- 推送日志:搜索区 + 分页,重推选中落分页栏左侧批量操作位 -->
|
||||
<div class="tab-body" v-show="tab === 'logs'">
|
||||
<div class="search-wrap fix">
|
||||
<Select v-model="logFilter.status" class="search-wrap_sel" clearable placeholder="状态" @on-change="onLogSearch">
|
||||
<Option :value="0" label="待推/重试中" />
|
||||
<Option :value="1" label="成功" />
|
||||
<Option :value="2" label="死信" />
|
||||
</Select>
|
||||
<Select v-model="logFilter.event" class="search-wrap_sel ml-12" clearable placeholder="事件" @on-change="onLogSearch">
|
||||
<Option v-for="e in EVENT_OPTIONS" :key="e" :value="e" :label="e" />
|
||||
</Select>
|
||||
<Input class="fr" v-model="logFilter.instanceId" placeholder="办件ID" search suffix="ios-search"
|
||||
style="width: 200px" @on-search="onLogSearch" @on-clear="onLogSearch" />
|
||||
</div>
|
||||
<TablePageAlovaNew ref="logTableRef" :dataApi="logApi" :columns="logColumns" :autoLoad="false">
|
||||
<template #default="{ checkList }">
|
||||
<Button size="small" type="primary" :disabled="!checkList.length" @click="onRepush(checkList)">重推选中</Button>
|
||||
</template>
|
||||
</TablePageAlovaNew>
|
||||
</div>
|
||||
|
||||
<!-- 挂起中:无分页 -->
|
||||
<div class="tab-body" v-show="tab === 'hung'">
|
||||
<div class="tip">
|
||||
持续重试中的事件(消费方疑似停机;消费方恢复后自动追平,无需干预)。仅当人工判定事件已无意义时才标记死信。
|
||||
</div>
|
||||
<div class="table-region" ref="hungRegionRef">
|
||||
<Table :columns="hungColumns" :data="hungs" :loading="hungLoading" class="link-table table-bottom-box"
|
||||
:height="hungH || undefined" no-data-text="暂无数据" />
|
||||
</div>
|
||||
</div>
|
||||
<Table :columns="hungColumns" :data="hungs" :loading="hungLoading" class="link-table table-bottom-box"
|
||||
:height="hungTableHeight" no-data-text="暂无数据" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
// 本页不再直接编辑 JSON 文本(编辑器内置"源码"高级模式兜底);行内「源码」为只读查看+复制。
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { Message } from "view-ui-plus";
|
||||
import { Message, Tag } from "view-ui-plus";
|
||||
import MyConfirm from "@/components/MyConfirm";
|
||||
import SourceDrawer from "@/views/flow/components/SourceDrawer.vue";
|
||||
import { flowApi } from "@/api/module/flow";
|
||||
import { actionColumn } from "@/utils/tableActions";
|
||||
import Utils from "@/utils";
|
||||
import { useElementHeight } from "@/utils/hook/useElementHeight";
|
||||
|
||||
const router = useRouter();
|
||||
const DEF_STATUS: Record<number, string> = { 0: "草稿", 1: "已发布", 2: "停用" };
|
||||
@@ -22,8 +22,9 @@ const versions = ref<any[]>([]);
|
||||
const sourceVisible = ref(false);
|
||||
const sourceText = ref("");
|
||||
const sourceTitle = ref("");
|
||||
// 操作按钮区 + 表格,无搜索、无分页
|
||||
const tableHeight = ref(Utils.useTableHeight({ isOperat: true }));
|
||||
// 操作按钮区 + 表格,无搜索、无分页:表格高度实测 .table-region(flex:1)
|
||||
const defsRegionRef = ref<HTMLElement | null>(null);
|
||||
const defsH = useElementHeight(defsRegionRef);
|
||||
// 按应用筛选(flw_def.app_key,2026-10-10):下拉数据源来自应用设置白名单(flw_app enabled=1)
|
||||
const apps = ref<{ appKey: string; appName: string }[]>([]);
|
||||
const appMap = ref<Record<string, string>>({});
|
||||
@@ -37,7 +38,7 @@ const columns = [
|
||||
{ title: "版本", key: "version", width: 70, align: "center" },
|
||||
{ title: "状态", width: 90, align: "center", 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);
|
||||
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", " ") || "-") },
|
||||
@@ -220,7 +221,7 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-wrapper">
|
||||
<div class="page-wrapper yh-fill">
|
||||
<div class="main-container">
|
||||
<!-- 操作按钮区:主操作靠左(bsch应用页规范 §1) -->
|
||||
<div class="fix mb-12">
|
||||
@@ -231,14 +232,16 @@ onMounted(() => {
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<Table :columns="columns" :data="rows" :loading="loading" class="link-table table-bottom-box"
|
||||
:height="tableHeight" no-data-text="暂无数据" />
|
||||
<div class="table-region" ref="defsRegionRef">
|
||||
<Table :columns="columns" :data="rows" :loading="loading" class="link-table table-bottom-box"
|
||||
:height="defsH || undefined" no-data-text="暂无数据" />
|
||||
</div>
|
||||
|
||||
<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: 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" no-data-text="暂无数据" />
|
||||
</Modal>
|
||||
@@ -269,3 +272,11 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 无分页脚:通道只对含 .page-panel 的卡片自动转纵向分栏,本页自声明保证 table-region 撑满 */
|
||||
.main-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
// 办件记录(管理端):全校办件查询;CONDITION 判断失败挂起的办件在此"重跑路由"恢复
|
||||
import { ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { Message } from "view-ui-plus";
|
||||
import { Message, Tag } from "view-ui-plus";
|
||||
import MyConfirm from "@/components/MyConfirm";
|
||||
import { OperatorEnum } from "@/types";
|
||||
import TablePageAlovaNew from "@/components/TablePageAlovaNew.vue";
|
||||
import { flowApi, INSTANCE_STATUS, INSTANCE_STATUS_COLOR } from "@/api/module/flow";
|
||||
import { actionColumn } from "@/utils/tableActions";
|
||||
import Utils from "@/utils";
|
||||
|
||||
const router = useRouter();
|
||||
const tableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||||
const tableHeight = ref(Utils.useTableHeight({ isSearch: true, isPage: true }));
|
||||
const dataParams = ref<{ status?: number; keyword?: string }>({ status: undefined, keyword: "" });
|
||||
|
||||
const columns = [
|
||||
@@ -20,7 +18,7 @@ const columns = [
|
||||
{ title: "办件标题", key: "bizTitle", minWidth: 220 },
|
||||
{ title: "业务", width: 170, render: (h: any, p: any) => h("span", `${p.row.bizType || "-"}/${p.row.bizId || "-"}`) },
|
||||
{ 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) },
|
||||
h(Tag, { color: INSTANCE_STATUS_COLOR[p.row.status] || "gray" }, () => INSTANCE_STATUS[p.row.status] || p.row.status) },
|
||||
{ title: "提交人", key: "submitterName", width: 100 },
|
||||
{ title: "提交时间", width: 160, render: (h: any, p: any) => h("span", (p.row.submitTime || "").replace("T", " ")) },
|
||||
actionColumn(
|
||||
@@ -61,7 +59,7 @@ function onSearch() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-wrapper">
|
||||
<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">
|
||||
@@ -73,7 +71,7 @@ function onSearch() {
|
||||
<Input class="fr" v-model="dataParams.keyword" placeholder="标题关键字" search suffix="ios-search"
|
||||
style="width: 200px" @on-search="onSearch" @on-clear="onSearch" />
|
||||
</div>
|
||||
<TablePageAlovaNew ref="tableRef" :dataApi="tableApi" :columns="columns" :tableHeight="tableHeight" />
|
||||
<TablePageAlovaNew ref="tableRef" :dataApi="tableApi" :columns="columns" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
// CONDITION 节点的 routerKey 必须命中启用中的注册(发布校验口径);basePath 是对端 context-path,
|
||||
// 漏填必 401(规范 §4.2 同款坑)——生产 notice 为 /notice,本地为空。
|
||||
import { ref, onMounted } from "vue";
|
||||
import { Message } from "view-ui-plus";
|
||||
import { Message, Tag } from "view-ui-plus";
|
||||
import MyConfirm from "@/components/MyConfirm";
|
||||
import { flowApi } from "@/api/module/flow";
|
||||
import { actionColumn } from "@/utils/tableActions";
|
||||
import Utils from "@/utils";
|
||||
import { useElementHeight } from "@/utils/hook/useElementHeight";
|
||||
|
||||
const loading = ref(false);
|
||||
const rows = ref<any[]>([]);
|
||||
const tableHeight = ref(Utils.useTableHeight({ isSearch: true, isOperat: true }));
|
||||
// 无搜索分页脚:表格高度实测 .table-region(flex:1)
|
||||
const routerRegionRef = ref<HTMLElement | null>(null);
|
||||
const routersH = useElementHeight(routerRegionRef);
|
||||
|
||||
const columns = [
|
||||
{ title: "序号", type: "index", width: 70, align: "center" },
|
||||
@@ -29,7 +31,7 @@ const columns = [
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h: any, p: any) =>
|
||||
h("Tag", { color: p.row.status === 1 ? "green" : "gray" }, () => (p.row.status === 1 ? "启用" : "停用")),
|
||||
h(Tag, { color: p.row.status === 1 ? "green" : "gray" }, () => (p.row.status === 1 ? "启用" : "停用")),
|
||||
},
|
||||
actionColumn(
|
||||
[
|
||||
@@ -160,7 +162,7 @@ onMounted(load);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-wrapper">
|
||||
<div class="page-wrapper yh-fill">
|
||||
<div class="main-container">
|
||||
<div class="fix mb-12">
|
||||
<Button class="fl" type="primary" size="large" @click="onAdd">新增注册</Button>
|
||||
@@ -174,8 +176,10 @@ onMounted(load);
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<Table :columns="columns" :data="rows" :loading="loading" class="link-table table-bottom-box"
|
||||
:height="tableHeight" no-data-text="暂无数据" />
|
||||
<div class="table-region" ref="routerRegionRef">
|
||||
<Table :columns="columns" :data="rows" :loading="loading" class="link-table table-bottom-box"
|
||||
:height="routersH || undefined" no-data-text="暂无数据" />
|
||||
</div>
|
||||
|
||||
<Modal v-model="saveVisible" title="新增/编辑判断服务" :mask-closable="false">
|
||||
<Form ref="formRef" :model="form" :rules="saveRules" :label-width="100">
|
||||
@@ -235,3 +239,11 @@ onMounted(load);
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 无分页脚:通道只对含 .page-panel 的卡片自动转纵向分栏,本页自声明保证 table-region 撑满 */
|
||||
.main-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user