feat: 通知前端存量(审批状态/消息中心/详情流程入口等 2026-09-13/14 改动)
build / build (push) Successful in 3m19s

This commit is contained in:
chenxing
2026-09-16 01:21:46 +08:00
parent c3ff58fd94
commit 830f9088f4
7 changed files with 261 additions and 65 deletions
+9
View File
@@ -17,6 +17,7 @@ import type {
DictOption,
FlowOption,
FlowTraceVo,
FlowBindingVo,
DeptManageItem,
ContactGroupPage,
ContactUserPage,
@@ -122,6 +123,14 @@ class NoticeApi {
flowTrace(serid: number) {
return get<FlowTraceVo>(`${NOTICE}/flow/Trace`, { serid });
}
/** 应用级流程绑定(应用设置 > 流程绑定;发通知页据此判断「提交审核」还是「发送」) */
getFlowBinding() {
return get<FlowBindingVo>(`${NOTICE}/flow/Binding`);
}
/** 保存/解除绑定(flowGuid 空=解绑;仅本校管理员) */
saveFlowBinding(flowGuid: string) {
return postForm<FlowBindingVo>(`${NOTICE}/flow/Binding/Save`, { flowGuid });
}
// ========== 收件箱 ==========
/** 已收通知列表 */
+6 -5
View File
@@ -271,11 +271,12 @@ export default [
method: "get",
response: () =>
ok([
{ id: 1, modId: 1, name: "已收到", parentId: 0, page: "/", orderNumber: 1, usable: true, children: [] },
{ id: 2, modId: 2, name: "已发送", parentId: 0, page: "/list", orderNumber: 2, usable: true, children: [] },
{ id: 3, modId: 3, name: "全部通知", parentId: 0, page: "/noticelist", orderNumber: 3, usable: true, children: [] },
{ id: 4, modId: 4, name: "通知统计", parentId: 0, page: "/stats", orderNumber: 4, usable: true, children: [] },
{ id: 21, modId: 21, name: "应用设置", parentId: 0, page: "/setting", orderNumber: 5, usable: true, children: [] },
// 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: [] },
]),
},
{
+5 -19
View File
@@ -128,26 +128,12 @@ const childChange = (index: number) => {
}
};
/** 根据菜单项映射图标:优先按解析后的 page 判断(平台模块 id 不可依赖),
* 兜底保留旧版 modId 对照。图标为本地 bsch-icons(iconfont 掩码类,见 styles/icons.css) */
/** 菜单图标:读取用户中心模块管理配置的 YschIcons 图标名(GetUserMod 的 icon 字段,如 list → icon-list)。
* 本地 icons.css 即 ysch-icons 掩码版(基类 iconfont,类名 icon-<名称>);
* 平台约定留空不下发图标,此时返回空串由模板 v-if 不渲染 */
const getMenuIcon = (item?: any): string => {
const page: string = item?.page || "";
if (page === "/list/new") return "icon-xiugaijl";
if (page === "/list") return "icon-fasong";
if (page === "/" || page === "/accept") return "icon-sjx";
if (page === "/noticelist") return "icon-liebiao";
if (page === "/stats") return "icon-tongji";
if (page === "/setting") return "icon-shezhi";
switch (item?.modId ?? item?.id) {
case 1: return "icon-xiugaijl";
case 2: return "icon-fasong";
case 3: return "icon-sjx";
case 4: return "icon-liebiao";
case 5: return "icon-wenzhang";
case 21: return "icon-shezhi";
case 22: return "icon-xiugaijl";
default: return "";
}
const icon = String(item?.icon || "").trim();
return icon ? `icon-${icon}` : "";
};
function linkHomePage() {
+18 -2
View File
@@ -88,6 +88,18 @@ export interface FlowOption {
nodeSummary: string | null;
}
/** 应用级流程绑定视图(GET /api/notice/flow/Binding;应用设置 > 流程绑定 + 发通知页按钮显隐) */
export interface FlowBindingVo {
/** 本校是否已绑定审核流程(false=全部直发,现有功能不变) */
bound: boolean;
flowGuid: string | null;
flowName: string | null;
/** 流程中心是否接入(false 时设置页隐藏绑定入口) */
flowEnabled: boolean;
/** 当前用户是否可维护绑定(本校管理员;false 时设置页只读展示) */
canEdit?: boolean;
}
/** 审批进度(GET /api/notice/flow/Trace) */
export interface FlowTraceVo {
bound: boolean;
@@ -237,8 +249,7 @@ export interface NoticeRequest {
smsFlag?: number;
/** 转发源通知ID */
sourceId?: number;
/** 审核流程 GUID(非空=提交审核;空=直发) */
flowGuid?: string;
// 审核流程不由前端指定:绑定在「应用设置 > 流程绑定」,后端按「已绑定 + 通知对象=全部用户」判定
}
/** 通知列表查询参数(对齐 NoticeQuery.java + BasePageQuery.java) */
@@ -247,6 +258,11 @@ export interface NoticeQuery {
pageSize?: number;
keyword?: string;
status?: number;
/**
* 审核状态筛选(列表「状态」下拉):0 待提交 / 10 审批中 / 20 已通过 / 30 已驳回 / 40 已撤回;
* -1 = 无需审核(直发通知);不传不过滤
*/
auditStatus?: number;
type?: number;
/** 列表范围(管理端):"user" 只看自己发布的,不传=全部 */
scope?: string;
+58 -37
View File
@@ -6,7 +6,7 @@ import { Message, Modal } from "view-ui-plus";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import "@wangeditor/editor/dist/css/style.css";
import { noticeApi } from "@/api/module/notice";
import type { NoticeDetailVo, NoticeRequest, UpFileVo, FlowOption } from "@/types/notice";
import type { NoticeDetailVo, NoticeRequest, UpFileVo, FlowBindingVo } from "@/types/notice";
import UserCheckInput from "@/components/UserCheckInput.vue";
import NoticeUpload from "@/components/NoticeUpload.vue";
import config from "@/assets/config/host.config";
@@ -27,12 +27,28 @@ const form = reactive({
isShortMsg: false,
});
/* ============ 先审后发(审核流程绑定) ============ */
const flowOptions = ref<FlowOption[]>([]);
const flowGuid = ref(""); // 空=直发(原链路)
/* ============ 先审后发(应用设置 > 流程绑定,按学校生效) ============
规则(后端为单一事实源):已绑定 + 通知对象=全部用户 → 必须走审核,只显示「提交审核」,
隐藏「发送」与「定时发送」;指定人员与未绑定 → 原直发链路不变。 */
const flowBinding = ref<FlowBindingVo>({ bound: false, flowGuid: null, flowName: null, flowEnabled: true });
const noticeFlowGuid = ref(""); // 编辑回显:该通知自身的流程快照(决定沿用哪个流程重审)
const auditStatus = ref<number | null>(null); // 编辑回显的审核态
const auditResult = ref<{ result?: string; opinion?: string; rejectNode?: string } | null>(null);
const flowEnabled = computed(() => flowOptions.value.length > 0); // 流程中心不可用→隐藏选择器走直发
/** 通知对象是否「全部用户」(UserCheckInput 全部态 v-model 值为 "all") */
const isAllTarget = computed(() => {
const v = (form.rdoname || "").trim().toLowerCase();
return v === "" || v === "all";
});
/** 是否走审核(与后端 publish/edit 判定同式:已绑定 && 全部用户) */
const needAudit = computed(() => flowBinding.value.bound && isAllTarget.value);
/** 提示条展示的流程:优先该通知自身快照,其次应用绑定 */
const auditFlowGuid = computed(() => noticeFlowGuid.value || flowBinding.value.flowGuid || "");
const auditFlowName = computed(() => {
if (!noticeFlowGuid.value) return flowBinding.value.flowName || "";
return noticeFlowGuid.value === flowBinding.value.flowGuid ? flowBinding.value.flowName || "" : "";
});
const fileids = ref<number[]>([]);
const editFileList = ref<{ name: string; fileid: number }[]>([]);
const isSms = ref(false);
@@ -59,18 +75,21 @@ onMounted(async () => {
}
});
/* 审核流程下拉(流程中心不可用/未配置 → 空数组,选择器隐藏、提交按钮走"发送") */
/* 流程绑定(决定按钮显隐;流程中心未接入时 bound 恒为 false → 原直发界面) */
onMounted(async () => {
try {
flowOptions.value = (await noticeApi.getFlowOptions().send()) || [];
const view = await noticeApi.getFlowBinding().send();
if (view) flowBinding.value = view;
} catch {
flowOptions.value = [];
flowBinding.value = { bound: false, flowGuid: null, flowName: null, flowEnabled: false };
}
});
/** 流程图:flow-center 示意图深链(Notice 指定到人场景用人员视图) */
function openFlowDiagram() {
window.open(`${config.flowHost}/#/diagram?flowGuid=${flowGuid.value}&mode=user`, "_blank");
if (auditFlowGuid.value) {
window.open(`${config.flowHost}/#/diagram?flowGuid=${auditFlowGuid.value}&mode=user`, "_blank");
}
}
/* ============ 富文本编辑器(wangeditor v5 for vue3) ============ */
@@ -156,7 +175,7 @@ onMounted(async () => {
form.rdoname = detail.tlist === "all" || !Array.isArray(detail.tlist) ? "all" : detail.tlist.join(",");
if (detail.DsfsTime) timeForm.date1 = detail.DsfsTime;
// 审核绑定回显(驳回/撤回态显示意见与重提按钮)
flowGuid.value = detail.flowGuid || "";
noticeFlowGuid.value = detail.flowGuid || "";
auditStatus.value = detail.auditStatus ?? null;
auditResult.value = detail.flowResult || null;
} else {
@@ -202,7 +221,7 @@ async function doAdd(_type?: string) {
deptId: form.dept,
fileIds: fileids.value.join(","), //附件
smsFlag: form.isShortMsg ? 1 : 0, //是否发送短信
flowGuid: flowGuid.value || undefined, //绑流程→提交审核;空→直发
// 审核流程不再由前端指定:后端按「应用设置绑定 + 通知对象=全部用户」判定
};
if (isTime) {
//定时发送
@@ -237,13 +256,13 @@ async function doAdd(_type?: string) {
try {
if (!isEdit.value) {
await sendCreate(data);
Message.success(flowGuid.value ? "已提交审核,审核通过后自动发布" : "发送成功");
Message.success(needAudit.value ? "已提交审核,审核通过后自动发布" : "发送成功");
router.push("/list");
} else {
data.sourceId = serid.value;
if (data.title.indexOf("[修订稿]") == -1) data.title = "[修订稿]" + data.title;
// §3.6:已发布(audit=20)编辑告知——修改后重新走审批,期间对用户不可见
if (flowGuid.value && auditStatus.value === 20) {
// §3.6:审核轨道内已发布(audit=20)编辑告知——修改后重新走审批,期间对用户不可见
if (needAudit.value && auditStatus.value === 20) {
Modal.confirm({
title: "重新送审确认",
content: "该通知已发布,修改后将重新走审批流程,期间对用户不可见,确认继续?",
@@ -253,6 +272,17 @@ async function doAdd(_type?: string) {
});
return;
}
// 绑定生效后把存量通知(此前直发、无审核轨道)改为全部用户:保存即将转入待审核
if (needAudit.value && !noticeFlowGuid.value) {
Modal.confirm({
title: "转为待审核确认",
content: "本应用已绑定审核流程,发送全部用户需审核通过后发布。保存后该通知将进入待审核状态,审核期间对用户不可见,确认继续?",
onOk: async () => {
await saveEditAndLeave(data);
},
});
return;
}
await saveEditAndLeave(data);
}
} catch (e: any) {
@@ -262,16 +292,15 @@ async function doAdd(_type?: string) {
}
}
/* 编辑保存 + 离开(§3.6 抽出:audit=20 先 confirm 再走这里) */
/* 编辑保存 + 离开(§3.6 抽出:确认分支复用) */
async function saveEditAndLeave(data: NoticeRequest) {
await sendEdit(data);
// 编辑驳回/撤回态:后端 edit 内已自动重提(复用同办件 R4);待提交态由重提按钮处理
Message.success(flowGuid.value ? "已保存并提交审核" : "保存成功");
Message.success(needAudit.value ? "已保存并提交审核" : "保存成功");
router.push("/list");
}
/* 单独重提审核(待提交/驳回/撤回态;审批中按钮隐藏) */
async function doResubmit() {
/* 单独重提审核(待提交/驳回/撤回态;审批中按钮隐藏) */async function doResubmit() {
isLoading.value = true;
try {
await noticeApi.trySubmitFlow(serid.value).send();
@@ -304,19 +333,15 @@ async function doResubmit() {
<FormItem label="添加附件:">
<NoticeUpload v-model:fileids="fileids" :defaultList="editFileList"></NoticeUpload>
</FormItem>
<FormItem v-if="flowEnabled" label="审核流程:">
<div class="flow-select">
<Select v-model="flowGuid" clearable placeholder="不审核,直接发布">
<Option value="">不审核,直接发布</Option>
<Option v-for="f in flowOptions" :key="f.flowGuid" :value="f.flowGuid">
{{ f.name }}({{ f.nodeSummary || "—" }})
</Option>
</Select>
<Button v-if="flowGuid" size="small" @click="openFlowDiagram">流程图</Button>
</div>
</FormItem>
</Form>
<!-- 绑定了审核流程且通知对象=全部用户:告知需要审核(流程在「应用设置 > 流程绑定」维护) -->
<Alert v-if="needAudit" type="info" show-icon class="audit-alert">
本应用已绑定审核流程{{ auditFlowName ? `《${auditFlowName}》` : "" }}:发送全部用户需审核通过后发布
<template v-if="auditFlowGuid"> <Button type="text" size="small" @click="openFlowDiagram">查看流程图</Button></template>
<template v-if="isAllTarget"> 如需直接发送,可将通知对象改为「指定用户」</template>
</Alert>
<!-- 驳回/撤回意见提示(编辑驳回/撤回态) -->
<Alert v-if="isEdit && (auditStatus === 30 || auditStatus === 40)" type="warning" show-icon class="audit-alert">
审核{{ auditStatus === 30 ? "已驳回" : "已撤回" }}
@@ -338,17 +363,18 @@ async function doResubmit() {
<div class="bottom-btn">
<Button type="primary" :loading="isLoading" @click="doAdd()">
{{ isEdit ? (flowGuid ? "保存并重新提交审核" : "保存") : flowGuid ? "提交审核" : "发送" }}
{{ isEdit ? (needAudit ? "保存并重新提交审核" : "保存") : needAudit ? "提交审核" : "发送" }}
</Button>
<!-- 待提交态单独重提(提交流程中心失败后的幂等重推入口) -->
<Button
v-if="isEdit && flowGuid && auditStatus === 0"
v-if="isEdit && noticeFlowGuid && auditStatus === 0"
style="margin-left: 10px"
:loading="isLoading"
@click="doResubmit"
>重新提交审核</Button
>
<Button v-if="!isEdit" style="margin-left: 10px" @click="isModal.timiSend = true">定时发送</Button>
<!-- 定时发送与审核互斥:走审核时隐藏(后端同步清空定时时间兜底) -->
<Button v-if="!isEdit && !needAudit" style="margin-left: 10px" @click="isModal.timiSend = true">定时发送</Button>
</div>
<!-- 定时发送 -->
@@ -390,11 +416,6 @@ async function doResubmit() {
.audit-alert {
margin-bottom: 12px;
}
.flow-select {
display: flex;
gap: 8px;
align-items: center;
}
/* 页面超高时的滚动由 App.vue 的 .main-wrapper 统一承接 */
.myform {
:deep(.ivu-form-item) {
+22
View File
@@ -17,10 +17,21 @@ const isManage = computed(() => route.path === "/noticelist");
/* ============ 搜索条件(规范 §1:日期 fl + 下拉 fl + 关键字 fr 宽200 即搜) ============ */
const keyword = ref("");
const deptType = ref("");
const auditType = ref<number | "">(""); // 状态筛选(audit_status;-1=无需审核)
const startDt = ref("");
const endDt = ref("");
const { data: deptOptions } = useRequest(noticeApi.getSysDic());
/** 状态筛选选项(与列表「审核状态」列取值一一对应;-1 = 未走审核的直发通知) */
const auditStatusOptions = [
{ value: 0, label: "待提交" },
{ value: 10, label: "审批中" },
{ value: 20, label: "已通过" },
{ value: 30, label: "已驳回" },
{ value: 40, label: "已撤回" },
{ value: -1, label: "无需审核" },
];
function fmtDate(d: Date) {
const pad = (n: number) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
@@ -45,6 +56,7 @@ async function run() {
};
if (startDt.value) params.startTime = startDt.value;
if (endDt.value) params.endTime = endDt.value;
if (auditType.value !== "" && auditType.value !== null) params.auditStatus = Number(auditType.value);
if (!isManage.value) {
params.scope = "user";
}
@@ -90,6 +102,7 @@ watch(
pageNum.value = 1;
keyword.value = "";
deptType.value = "";
auditType.value = "";
if (!isManage.value) {
const start = new Date();
start.setMonth(start.getMonth() - 1);
@@ -215,6 +228,15 @@ const tableHeight = computed(() => Utils.useTableHeight({ isSearch: true, isOper
<Select v-model="deptType" class="search-wrap_sel ml-12" clearable placeholder="来源部门" @on-change="doSearch">
<Option v-for="d in deptOptions" :key="d.k" :value="d.k">{{ d.v }}</Option>
</Select>
<Select
v-model="auditType"
class="search-wrap_sel ml-12"
clearable
placeholder="状态"
@on-change="doSearch"
>
<Option v-for="s in auditStatusOptions" :key="s.value" :value="s.value">{{ s.label }}</Option>
</Select>
<Input
class="fr"
style="width: 200px"
+143 -2
View File
@@ -5,8 +5,9 @@ import draggable from "vuedraggable";
import MyConfirm from "@/components/MyConfirm";
import UserCheckModal from "@/components/UserCheckModal.vue";
import TypeSetBox from "@/components/TypeSetBox.vue";
import { settingApi, baseApi } from "@/api/module/notice";
import type { DeptManageItem, ContactGroupPage, ContactUserPage, SchoolTreeNode } from "@/types/notice";
import { settingApi, baseApi, noticeApi } from "@/api/module/notice";
import type { DeptManageItem, ContactGroupPage, ContactUserPage, SchoolTreeNode, FlowOption } from "@/types/notice";
import config from "@/assets/config/host.config";
import Utils from "@/utils";
/* ============ Tab 切换(规范 §1:tabs-wrapper + Tabs type=card,切换只 v-show 内容区) ============ */
@@ -18,9 +19,77 @@ function tabChange(name: string) {
getDeptList();
} else if (currentType.value === 3) {
getGroupList();
} else if (currentType.value === 2) {
loadFlowBinding();
}
}
/* ============ 流程绑定(应用设置 > 流程绑定) ============ */
const flowOptions = ref<FlowOption[]>([]);
const flowEnabled = ref(true);
const flowCanEdit = ref(false); // 仅本校管理员可维护绑定
const boundFlowGuid = ref(""); // 已保存的绑定(提交前的编辑值另用 selectedGuid)
const boundFlowName = ref("");
const selectedGuid = ref("");
const bindingSaving = ref(false);
async function loadFlowBinding() {
try {
const view = await noticeApi.getFlowBinding().send();
flowEnabled.value = view?.flowEnabled !== false;
flowCanEdit.value = view?.canEdit === true;
boundFlowGuid.value = view?.flowGuid || "";
boundFlowName.value = view?.flowName || "";
selectedGuid.value = boundFlowGuid.value;
} catch (e: any) {
Message.error(e.message || "获取流程绑定失败");
}
try {
flowOptions.value = (await noticeApi.getFlowOptions().send()) || [];
} catch {
flowOptions.value = [];
}
}
async function saveFlowBinding() {
bindingSaving.value = true;
try {
const view = await noticeApi.saveFlowBinding(selectedGuid.value).send();
boundFlowGuid.value = view?.flowGuid || "";
boundFlowName.value = view?.flowName || "";
selectedGuid.value = boundFlowGuid.value;
Message.success(boundFlowGuid.value ? "绑定成功" : "已解除绑定");
} catch (e: any) {
Message.error(e.message || "保存失败");
} finally {
bindingSaving.value = false;
}
}
function unbindFlow() {
MyConfirm({
title: "解除绑定",
msg: "确定解除流程绑定吗?",
info: "解除后发送全部用户将不再需要审核,直接发布",
async onOk() {
selectedGuid.value = "";
await saveFlowBinding();
},
});
}
/** 流程图(flow-center 示意图深链,与发通知页同一入口) */
function openFlowDiagram(guid: string) {
if (guid) window.open(`${config.flowHost}/#/diagram?flowGuid=${guid}`, "_blank");
}
/** 当前绑定流程的节点摘要(下拉里回显) */
const boundFlowSummary = computed(() => {
const hit = flowOptions.value.find((f) => f.flowGuid === boundFlowGuid.value);
return hit?.nodeSummary || "—";
});
/* ============ 发文部门(直接复用 UserBase 同源 TypeSetBox 卡片组件) ============ */
interface DeptItem {
SerID: number;
@@ -336,6 +405,7 @@ const groupTableHeight = computed(() => Utils.useTableHeight({ isTabs: true, isS
<Tabs class="tabs-panel" type="card" :value="String(currentType)" @on-click="tabChange">
<TabPane label="发文部门" name="1"></TabPane>
<TabPane label="自定义组" name="3"></TabPane>
<TabPane label="流程绑定" name="2"></TabPane>
</Tabs>
<!-- 发文部门 -->
@@ -407,6 +477,50 @@ const groupTableHeight = computed(() => Utils.useTableHeight({ isTabs: true, isS
</div>
</div>
<!-- 流程绑定(应用设置 > 流程绑定) -->
<div class="main-container" v-show="currentType === 2">
<Alert show-icon type="warning">
绑定说明:绑定后「发送全部用户」的通知必须审核通过才发布(发通知页只显示「提交审核」按钮,
隐藏发送与定时发送);「发送指定人员」不受影响,仍直接发布。未绑定则保持现有发送方式。
</Alert>
<div v-if="!flowEnabled" class="flow-binding-empty">流程中心未接入,暂不支持流程绑定。</div>
<template v-else>
<div class="flow-binding-form">
<span class="label">审核流程:</span>
<Select
v-model="selectedGuid"
clearable
:disabled="!flowCanEdit"
placeholder="不绑定,全部直发"
style="width: 360px"
>
<Option value="">不绑定,全部直发</Option>
<Option v-for="f in flowOptions" :key="f.flowGuid" :value="f.flowGuid">
{{ f.name }}({{ f.nodeSummary || "—" }})
</Option>
</Select>
<template v-if="flowCanEdit">
<Button type="primary" :loading="bindingSaving" @click="saveFlowBinding">保存绑定</Button>
<Button v-if="boundFlowGuid" @click="unbindFlow">解除绑定</Button>
</template>
<span v-else class="readonly-hint">仅本校管理员可修改流程绑定</span>
</div>
<div class="flow-binding-state">
当前状态:
<template v-if="boundFlowGuid">
已绑定
<Tag color="blue">{{ boundFlowName || boundFlowGuid }}</Tag>
<span class="node-summary">{{ boundFlowSummary }}</span>
<Button type="text" size="small" @click="openFlowDiagram(boundFlowGuid)">查看流程图</Button>
</template>
<template v-else>
<Tag>未绑定</Tag>
<span class="node-summary">发送全部用户与指定人员均直接发布</span>
</template>
</div>
</template>
</div>
<!-- 新增发文部门 Modal(编辑走 TypeSetBox 内联编辑) -->
<Modal v-model="deptModal" :mask-closable="false" width="450px" title="新增部门">
<Form ref="deptFormRef" :model="deptForm" :rules="deptRule" :label-width="110">
@@ -479,4 +593,31 @@ const groupTableHeight = computed(() => Utils.useTableHeight({ isTabs: true, isS
display: flex;
justify-content: flex-end;
}
/* 流程绑定面板 */
.flow-binding-form {
margin: 16px 0;
display: flex;
align-items: center;
gap: 10px;
}
.flow-binding-form .label {
color: #515a6e;
}
.flow-binding-state {
color: #515a6e;
display: flex;
align-items: center;
gap: 6px;
}
.flow-binding-state .node-summary {
color: #808695;
}
.readonly-hint {
color: #808695;
margin-left: 8px;
}
.flow-binding-empty {
margin-top: 16px;
color: #808695;
}
</style>