|
|
@@ -153,43 +153,75 @@ const graceMax = computed(() => {
|
|
|
return max >= 2147483647 ? undefined : max;
|
|
|
});
|
|
|
|
|
|
-// ── S8-HANDLER-POOL-1:规则处理账号池 ──
|
|
|
-// 责任维度(谁负责这条规则),与「异常操作权限」的角色维度正交。
|
|
|
-// P1-D 会把它搬进四页签弹窗的 Tab3;本批先在既有抽屉里给出可用入口,
|
|
|
-// 否则新加的启用门禁会让所有规则都停在"请先配置处理账号"而无处可配。
|
|
|
-const handlerPool = ref<number[]>([]);
|
|
|
-const handlerPoolLoaded = ref(false);
|
|
|
-const handlerPoolInvalid = ref<S8HandlerUser[]>([]);
|
|
|
-const savingPool = ref(false);
|
|
|
+// ── S8-RESPONSIBILITY-POOL-1:规则的三个责任池 ──
|
|
|
+//
|
|
|
+// 责任维度(谁负责什么)与「异常操作权限」的角色维度正交:
|
|
|
+// 角色管"能做什么",责任池管"负责什么",状态机管"现在能不能做"。
|
|
|
+// 页面上只出现业务语言,不出现 Role / ApproverType / RecipientType 这类技术术语。
|
|
|
+type PoolKey = 'HANDLER' | 'REVIEWER' | 'ESCALATION';
|
|
|
+
|
|
|
+interface PoolState {
|
|
|
+ key: PoolKey;
|
|
|
+ title: string;
|
|
|
+ description: string;
|
|
|
+ /** 空池时的后果说明 —— 让管理员知道不配会怎样,而不是只看到一个红框。 */
|
|
|
+ emptyWarning: string;
|
|
|
+ members: number[];
|
|
|
+ invalid: S8HandlerUser[];
|
|
|
+ loaded: boolean;
|
|
|
+ saving: boolean;
|
|
|
+}
|
|
|
+
|
|
|
+function newPool(key: PoolKey, title: string, description: string, emptyWarning: string): PoolState {
|
|
|
+ return { key, title, description, emptyWarning, members: [], invalid: [], loaded: false, saving: false };
|
|
|
+}
|
|
|
+
|
|
|
+const pools = ref<PoolState[]>([
|
|
|
+ newPool('HANDLER', '处理人员', '以下账号负责处理该规则产生的异常。',
|
|
|
+ '未配置处理人员时该规则无法启用 —— 否则异常会源源不断建出来、没有人认领。'),
|
|
|
+ newPool('REVIEWER', '复核人员', '处理人提交复核时,只能从以下账号中选择复核人。',
|
|
|
+ '未配置复核人员时该规则无法启用 —— 否则处理人提交复核时选不到任何人,单据会卡住。'),
|
|
|
+ newPool('ESCALATION', '升级人员', '异常超时或触发升级时通知以下账号。',
|
|
|
+ '未配置升级人员时该规则无法启用 —— 否则异常超时后不会通知任何人。'),
|
|
|
+]);
|
|
|
+
|
|
|
const tenantUsers = ref<{ id: number; name: string; account?: string }[]>([]);
|
|
|
|
|
|
-async function loadHandlerPool(ruleId: number) {
|
|
|
- handlerPoolLoaded.value = false;
|
|
|
- handlerPoolInvalid.value = [];
|
|
|
- try {
|
|
|
- const [members, users] = await Promise.all([
|
|
|
- s8ConfigApi.handlerPool.get(ruleId),
|
|
|
- s8ExceptionApi.users(),
|
|
|
- ]);
|
|
|
- const list = (members as S8HandlerUser[]) ?? [];
|
|
|
- handlerPool.value = list.map((m) => Number(m.userId));
|
|
|
- // 失效成员不静默丢弃:管理员必须看见"这里有一个人已经不算数了"。
|
|
|
- handlerPoolInvalid.value = list.filter((m) => !m.valid);
|
|
|
- tenantUsers.value = (users as typeof tenantUsers.value) ?? [];
|
|
|
- } finally {
|
|
|
- handlerPoolLoaded.value = true;
|
|
|
- }
|
|
|
+function poolOf(key: PoolKey) {
|
|
|
+ return pools.value.find((p) => p.key === key)!;
|
|
|
}
|
|
|
|
|
|
-async function saveHandlerPool() {
|
|
|
+async function loadPools(ruleId: number) {
|
|
|
+ pools.value.forEach((p) => {
|
|
|
+ p.loaded = false;
|
|
|
+ p.invalid = [];
|
|
|
+ });
|
|
|
+ const [users] = await Promise.all([
|
|
|
+ s8ExceptionApi.users(),
|
|
|
+ ...pools.value.map(async (p) => {
|
|
|
+ try {
|
|
|
+ const r: any = await s8ConfigApi.responsibility.get(ruleId, p.key);
|
|
|
+ const list = (r?.members as S8HandlerUser[]) ?? [];
|
|
|
+ p.members = list.map((m) => Number(m.userId));
|
|
|
+ // 失效成员不静默丢弃:管理员必须看见"这里有一个人已经不算数了"。
|
|
|
+ p.invalid = list.filter((m) => !m.valid);
|
|
|
+ } finally {
|
|
|
+ p.loaded = true;
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ ]);
|
|
|
+ tenantUsers.value = (users as typeof tenantUsers.value) ?? [];
|
|
|
+}
|
|
|
+
|
|
|
+async function savePool(p: PoolState) {
|
|
|
if (!current.value) return;
|
|
|
- savingPool.value = true;
|
|
|
+ p.saving = true;
|
|
|
try {
|
|
|
- await s8ConfigApi.handlerPool.set(Number(current.value.id), handlerPool.value);
|
|
|
- handlerPoolInvalid.value = [];
|
|
|
- ElMessage.success(handlerPool.value.length ? '处理账号池已保存' : '已清空处理账号池(该规则将无法启用)');
|
|
|
+ await s8ConfigApi.responsibility.set(Number(current.value.id), p.key, p.members);
|
|
|
+ p.invalid = [];
|
|
|
+ ElMessage.success(p.members.length ? `${p.title}已保存` : `已清空${p.title}(该规则将无法启用)`);
|
|
|
} finally {
|
|
|
- savingPool.value = false;
|
|
|
+ p.saving = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -200,42 +232,36 @@ const reviewLoaded = ref(false);
|
|
|
const reviewStages = ref<any[]>([]);
|
|
|
const escalateRoles = ref<string[]>([]);
|
|
|
|
|
|
-// ── S8-NOTIFY-RECIPIENT-1:事件收件人配置 ──
|
|
|
+// ── S8-RESPONSIBILITY-POOL-1:通知设置(只回答「什么事件需要提醒」)──
|
|
|
+//
|
|
|
+// 提醒谁由后端按责任关系推导(处理池 / 当前处理人 / 当前复核人 / 升级池),
|
|
|
+// 前端只展示业务文案 + 一个开关。刻意不再让业务用户挑收件人类型:
|
|
|
+// 规则已经知道这些人是谁,再让人配一遍就多出一处会与责任池不一致的配置。
|
|
|
const notifyLoaded = ref(false);
|
|
|
const notifyEvents = ref<any[]>([]);
|
|
|
-const notifyTypes = ref<string[]>([]);
|
|
|
const savingNotify = ref('');
|
|
|
|
|
|
-/** 收件人类型的业务文案。刻意不出现「主管 / 总监」—— 系统里没有对应实体。 */
|
|
|
-const RECIPIENT_LABEL: Record<string, string> = {
|
|
|
- HANDLER_POOL: '该规则的处理账号池',
|
|
|
- ASSIGNEE: '当前处理人',
|
|
|
- REVIEWER: '当前实际审核人',
|
|
|
- SPECIFIC_USER: '指定账号',
|
|
|
-};
|
|
|
-
|
|
|
-async function loadNotifyRecipients(ruleId: number) {
|
|
|
+async function loadNotifyEvents(ruleId: number) {
|
|
|
notifyLoaded.value = false;
|
|
|
try {
|
|
|
- const r: any = await s8ConfigApi.watchRules.notifyRecipients(ruleId);
|
|
|
+ const r: any = await s8ConfigApi.watchRules.notifyEvents(ruleId);
|
|
|
notifyEvents.value = r?.events ?? [];
|
|
|
- notifyTypes.value = r?.recipientTypes ?? [];
|
|
|
} finally {
|
|
|
notifyLoaded.value = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-async function saveNotifyEvent(row: any) {
|
|
|
+async function toggleNotifyEvent(row: any) {
|
|
|
if (!current.value) return;
|
|
|
savingNotify.value = row.eventCode;
|
|
|
try {
|
|
|
- await s8ConfigApi.watchRules.setNotifyRecipients(Number(current.value.id), row.eventCode, {
|
|
|
- recipientTypes: row.recipientTypes ?? [],
|
|
|
- specificUserIds: row.specificUserIds ?? [],
|
|
|
- });
|
|
|
- ElMessage.success((row.recipientTypes?.length)
|
|
|
- ? `已保存「${row.displayName}」的收件人`
|
|
|
- : `「${row.displayName}」已清空收件人(将回落旧分层配置)`);
|
|
|
+ await s8ConfigApi.watchRules.setNotifyEvent(Number(current.value.id), row.eventCode, row.enabled);
|
|
|
+ ElMessage.success(row.enabled
|
|
|
+ ? `已开启「${row.displayName}」提醒,通知${row.recipientLabel}`
|
|
|
+ : `已关闭「${row.displayName}」提醒`);
|
|
|
+ } catch (e) {
|
|
|
+ row.enabled = !row.enabled; // 保存失败回滚开关,避免页面显示与实际配置不符
|
|
|
+ throw e;
|
|
|
} finally {
|
|
|
savingNotify.value = '';
|
|
|
}
|
|
|
@@ -272,9 +298,9 @@ function openDetail(row: S8WatchRuleConfigRow) {
|
|
|
preview.value = null;
|
|
|
drawerOpen.value = true;
|
|
|
activeTab.value = 'info';
|
|
|
- void loadHandlerPool(Number(row.id));
|
|
|
+ void loadPools(Number(row.id));
|
|
|
void loadReviewSource(Number(row.id));
|
|
|
- void loadNotifyRecipients(Number(row.id));
|
|
|
+ void loadNotifyEvents(Number(row.id));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -667,136 +693,139 @@ async function provision() {
|
|
|
</div>
|
|
|
</el-tab-pane>
|
|
|
|
|
|
- <!-- TAB 3 · 处理与审核:责任维度(可写)+ 审核来源(只读事实)。 -->
|
|
|
- <el-tab-pane label="处理与审核" name="people">
|
|
|
- <!-- S8-HANDLER-POOL-1:责任维度。谁负责这条规则,与「异常操作权限」的角色维度正交。 -->
|
|
|
- <el-card shadow="never" style="margin-bottom: 12px">
|
|
|
+ <!--
|
|
|
+ TAB 3 · 责任分配:业务用户只回答三个问题 ——
|
|
|
+ 谁处理、谁复核、超时找谁。三者都是 SysUser 多选,成员一律经
|
|
|
+ 同租户 + 启用校验。技术实现(审批流节点 / 审批人类型 / 角色编码)
|
|
|
+ 挪进「高级信息」折叠区,默认不展开、且只读。
|
|
|
+ -->
|
|
|
+ <el-tab-pane label="责任分配" name="people">
|
|
|
+ <el-card v-for="p in pools" :key="p.key" shadow="never" style="margin-bottom: 12px">
|
|
|
<template #header>
|
|
|
<div style="display: flex; justify-content: space-between; align-items: center">
|
|
|
- <span style="font-weight: 600">处理账号(该规则由谁负责)</span>
|
|
|
- <el-button type="primary" size="small" :loading="savingPool"
|
|
|
- :disabled="!handlerPoolLoaded" @click="saveHandlerPool">保存处理账号</el-button>
|
|
|
+ <div>
|
|
|
+ <span style="font-weight: 600">{{ p.title }}</span>
|
|
|
+ <span style="color: #909399; font-size: 12px; margin-left: 8px">{{ p.description }}</span>
|
|
|
+ </div>
|
|
|
+ <el-button type="primary" size="small" :loading="p.saving"
|
|
|
+ :disabled="!p.loaded" @click="savePool(p)">保存</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
- <el-alert v-if="handlerPoolLoaded && handlerPool.length === 0" type="warning"
|
|
|
+
|
|
|
+ <el-alert v-if="p.loaded && p.members.length === 0" type="warning"
|
|
|
:closable="false" show-icon style="margin-bottom: 10px">
|
|
|
- <template #title>该规则尚未配置处理账号</template>
|
|
|
- <div style="line-height: 1.9">
|
|
|
- 没有处理账号的规则<strong>无法启用</strong>:它会源源不断建出异常、却没有人能认领,
|
|
|
- 而调度器每一轮都报成功。
|
|
|
- </div>
|
|
|
+ <template #title>尚未配置{{ p.title }}</template>
|
|
|
+ <div style="line-height: 1.9">{{ p.emptyWarning }}</div>
|
|
|
</el-alert>
|
|
|
- <el-alert v-if="handlerPoolInvalid.length" type="error" :closable="false" show-icon
|
|
|
+
|
|
|
+ <el-alert v-if="p.invalid.length" type="error" :closable="false" show-icon
|
|
|
style="margin-bottom: 10px">
|
|
|
- <template #title>有 {{ handlerPoolInvalid.length }} 个已配置的账号当前不可用</template>
|
|
|
+ <template #title>有 {{ p.invalid.length }} 个已配置的账号当前不可用</template>
|
|
|
<div style="line-height: 1.9">
|
|
|
- 这些账号已停用或不在当前租户,<strong>不再具备认领资格</strong>。请重新选择后保存。
|
|
|
+ 这些账号已停用或不在当前租户,<strong>已不再算数</strong>。请重新选择后保存。
|
|
|
</div>
|
|
|
</el-alert>
|
|
|
- <el-select v-model="handlerPool" multiple filterable clearable collapse-tags collapse-tags-tooltip
|
|
|
- placeholder="选择负责该规则的系统账号" style="width: 100%" :loading="!handlerPoolLoaded">
|
|
|
+
|
|
|
+ <el-select v-model="p.members" multiple filterable clearable collapse-tags collapse-tags-tooltip
|
|
|
+ :placeholder="`选择${p.title}`" style="width: 100%" :loading="!p.loaded">
|
|
|
<el-option v-for="u in tenantUsers" :key="u.id" :label="u.name" :value="u.id">
|
|
|
<span>{{ u.name }} <span style="color: #999; font-size: 12px">{{ u.account ? '(' + u.account + ')' : '' }}</span></span>
|
|
|
</el-option>
|
|
|
</el-select>
|
|
|
+
|
|
|
<div style="color: #909399; font-size: 12px; margin-top: 6px">
|
|
|
- 池成员才能认领 / 被转派该规则产生的异常。能否认领还同时取决于账号是否拥有「认领」动作权限,
|
|
|
- 以及单据当前状态。
|
|
|
+ 当前有效:{{ p.members.length - p.invalid.length }} 人
|
|
|
+ <template v-if="p.key === 'HANDLER'">
|
|
|
+ · 分配方式:人员池认领(谁先认领归谁)
|
|
|
+ </template>
|
|
|
+ <template v-else-if="p.key === 'REVIEWER'">
|
|
|
+ · 复核人还需拥有「审核」操作权限才会出现在提交复核的候选里
|
|
|
+ </template>
|
|
|
</div>
|
|
|
</el-card>
|
|
|
|
|
|
<!--
|
|
|
- 审核区块**只读**。本批不新建 Rule 级 Reviewer Pool、不改 ApproverType、
|
|
|
- 不动流程节点、不改 owner/escalate 语义 —— 只如实说明当前审核人来自哪里。
|
|
|
- 此前这里显示的是「主管」,而系统里根本不存在组织主管关系
|
|
|
- (SysOrg.DirectorId 与 SysUser.ManagerUserId 实测填充率均为 0)。
|
|
|
+ 技术实现收进折叠区:业务用户不需要理解审批流。
|
|
|
+ 保留只读展示是为了排查 —— 出问题时要能看到任务实际发给了谁。
|
|
|
-->
|
|
|
- <el-card shadow="never" v-loading="!reviewLoaded">
|
|
|
- <template #header>
|
|
|
- <span style="font-weight: 600">审核来源(只读)</span>
|
|
|
- <span style="color: #909399; font-size: 12px; margin-left: 8px">当前审核人由下列机制决定,本页不修改它们</span>
|
|
|
- </template>
|
|
|
- <div v-for="st in reviewStages" :key="st.stage" style="margin-bottom: 14px">
|
|
|
- <div style="font-weight: 600; margin-bottom: 4px">{{ st.stage }}</div>
|
|
|
- <div style="color: #606266; line-height: 1.9">{{ st.decidedBy }}</div>
|
|
|
- <el-alert v-for="(w, wi) in st.warnings" :key="wi" type="warning" :closable="false" show-icon style="margin-top: 6px" :title="w" />
|
|
|
- <el-table v-if="st.nodes.length" :data="st.nodes" size="small" border style="margin-top: 8px">
|
|
|
- <el-table-column prop="nodeName" label="审批节点" width="150" />
|
|
|
- <el-table-column prop="approverType" label="审批人类型" width="130" />
|
|
|
- <el-table-column prop="approverIds" label="配置值" min-width="200" />
|
|
|
- <el-table-column label="本租户实际解析" min-width="240">
|
|
|
- <template #default="scope">
|
|
|
- <span v-if="scope.row.resolvedUsers.length">{{ scope.row.resolvedUsers.join('、') }}</span>
|
|
|
- <el-tag v-else type="danger" size="small">解析不出任何审批人</el-tag>
|
|
|
- <div v-if="scope.row.crossTenantRefs.length" style="color: #e6a23c; font-size: 12px; margin-top: 4px">越界引用:{{ scope.row.crossTenantRefs.join('、') }}</div>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </div>
|
|
|
- <el-divider v-if="escalateRoles.length" content-position="left">超时自动升级角色(来自异常类型配置)</el-divider>
|
|
|
- <div v-for="(r, ri) in escalateRoles" :key="ri" style="color: #606266; line-height: 1.9">{{ r }}</div>
|
|
|
- <div style="margin-top: 10px">
|
|
|
- <el-button link type="primary" @click="goApprovalConfig">查看 / 修改审批流程配置</el-button>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
+ <el-collapse>
|
|
|
+ <el-collapse-item name="diagnostics">
|
|
|
+ <template #title>
|
|
|
+ <span style="color: #909399">高级信息 / 流程诊断(一般不需要查看)</span>
|
|
|
+ </template>
|
|
|
+ <div v-loading="!reviewLoaded">
|
|
|
+ <el-alert type="info" :closable="false" show-icon style="margin-bottom: 10px">
|
|
|
+ <template #title>以下为审批流程的执行机制,<strong>只读</strong></template>
|
|
|
+ <div style="line-height: 1.9">
|
|
|
+ 复核人由上方「复核人员」决定;提交复核时选定的账号会成为审批任务的实际处理人。
|
|
|
+ 这里展示的是流程定义本身,用于排查"任务发给了谁"。
|
|
|
+ </div>
|
|
|
+ </el-alert>
|
|
|
+ <div v-for="st in reviewStages" :key="st.stage" style="margin-bottom: 14px">
|
|
|
+ <div style="font-weight: 600; margin-bottom: 4px">{{ st.stage }}</div>
|
|
|
+ <div style="color: #606266; line-height: 1.9">{{ st.decidedBy }}</div>
|
|
|
+ <el-alert v-for="(w, wi) in st.warnings" :key="wi" type="warning" :closable="false" show-icon style="margin-top: 6px" :title="w" />
|
|
|
+ <el-table v-if="st.nodes.length" :data="st.nodes" size="small" border style="margin-top: 8px">
|
|
|
+ <el-table-column prop="nodeName" label="审批节点" width="150" />
|
|
|
+ <el-table-column prop="approverType" label="审批人类型" width="130" />
|
|
|
+ <el-table-column prop="approverIds" label="配置值" min-width="200" />
|
|
|
+ <el-table-column label="本租户实际解析" min-width="240">
|
|
|
+ <template #default="scope">
|
|
|
+ <span v-if="scope.row.resolvedUsers.length">{{ scope.row.resolvedUsers.join('、') }}</span>
|
|
|
+ <el-tag v-else type="danger" size="small">解析不出任何审批人</el-tag>
|
|
|
+ <div v-if="scope.row.crossTenantRefs.length" style="color: #e6a23c; font-size: 12px; margin-top: 4px">越界引用:{{ scope.row.crossTenantRefs.join('、') }}</div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ <div style="margin-top: 10px">
|
|
|
+ <el-button link type="primary" @click="goApprovalConfig">查看 / 修改审批流程配置</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-collapse-item>
|
|
|
+ </el-collapse>
|
|
|
</el-tab-pane>
|
|
|
|
|
|
<!--
|
|
|
- TAB 4 · 通知与升级:P1-E 的 UI 容器。
|
|
|
- 刻意不铺 L1_OPERATOR / L2_MANAGER / L3_DIRECTOR ——
|
|
|
- 那三档在库里只有 L1 真正被用过,且「主管 / 总监」没有对应业务实体。
|
|
|
+ TAB 4 · 通知设置:只回答「什么事件需要提醒」。
|
|
|
+ 「谁负责升级」已经在 Tab 3 配置,这里不再重复;
|
|
|
+ 通知对象由责任关系推导,页面只读展示业务文案。
|
|
|
-->
|
|
|
- <el-tab-pane label="通知与升级" name="notify">
|
|
|
+ <el-tab-pane label="通知设置" name="notify">
|
|
|
<el-alert type="info" :closable="false" show-icon style="margin-bottom: 12px">
|
|
|
- <template #title>收件人按<strong>事件</strong>配置,最终都投递到系统账号</template>
|
|
|
+ <template #title>提醒对象由<strong>责任分配</strong>自动决定</template>
|
|
|
<div style="line-height: 1.9">
|
|
|
- 未配置的事件会回落到旧的「通知分层配置」(按场景 + 严重度 → 角色)。
|
|
|
- 一旦这里配了任意收件人,该事件就<strong>完全不再</strong>使用旧配置。
|
|
|
+ 不需要在这里再选一次人 —— 改「责任分配」里的三个池,这里的提醒对象会同步跟着变。
|
|
|
</div>
|
|
|
</el-alert>
|
|
|
|
|
|
<el-table :data="notifyEvents" v-loading="!notifyLoaded" border style="width: 100%">
|
|
|
- <el-table-column prop="displayName" label="事件" width="130">
|
|
|
- <template #default="scope">
|
|
|
- <span>{{ scope.row.displayName }}</span>
|
|
|
- <el-tag v-if="!(scope.row.recipientTypes || []).length" size="small" type="info" style="margin-left: 6px">回落旧配置</el-tag>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="triggerHint" label="触发时机" min-width="200">
|
|
|
+ <el-table-column prop="displayName" label="事件" width="140" />
|
|
|
+ <el-table-column prop="triggerHint" label="发生时机" min-width="200">
|
|
|
<template #default="scope">
|
|
|
<span style="color: #909399; font-size: 12px">{{ scope.row.triggerHint }}</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="通知谁" min-width="260">
|
|
|
- <template #default="scope">
|
|
|
- <el-select v-model="scope.row.recipientTypes" multiple collapse-tags collapse-tags-tooltip
|
|
|
- placeholder="未配置(回落旧分层配置)" style="width: 100%">
|
|
|
- <el-option v-for="t in notifyTypes" :key="t" :label="RECIPIENT_LABEL[t] || t" :value="t" />
|
|
|
- </el-select>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="指定账号" min-width="230">
|
|
|
+ <el-table-column label="通知对象" min-width="160">
|
|
|
<template #default="scope">
|
|
|
- <el-select v-if="(scope.row.recipientTypes || []).includes('SPECIFIC_USER')"
|
|
|
- v-model="scope.row.specificUserIds" multiple filterable collapse-tags collapse-tags-tooltip
|
|
|
- placeholder="选择账号" style="width: 100%">
|
|
|
- <el-option v-for="u in tenantUsers" :key="u.id" :label="u.name" :value="u.id" />
|
|
|
- </el-select>
|
|
|
- <span v-else style="color: #c0c4cc; font-size: 12px">仅「指定账号」需要</span>
|
|
|
+ <span>{{ scope.row.recipientLabel }}</span>
|
|
|
+ <el-tooltip v-if="!scope.row.matchesDerivedDefault" placement="top"
|
|
|
+ content="该事件存在历史手工配置,与默认推导不同。重新开关一次即可恢复默认。">
|
|
|
+ <el-tag size="small" type="warning" style="margin-left: 6px">自定义</el-tag>
|
|
|
+ </el-tooltip>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="操作" width="90" fixed="right">
|
|
|
+ <el-table-column label="是否提醒" width="110" fixed="right">
|
|
|
<template #default="scope">
|
|
|
- <el-button type="primary" link :loading="savingNotify === scope.row.eventCode"
|
|
|
- @click="saveNotifyEvent(scope.row)">保存</el-button>
|
|
|
+ <el-switch v-model="scope.row.enabled" :loading="savingNotify === scope.row.eventCode"
|
|
|
+ @change="toggleNotifyEvent(scope.row)" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
|
|
|
<div style="color: #909399; font-size: 12px; margin-top: 10px; line-height: 1.9">
|
|
|
- 「当前实际审核人」解析的是单据上已手选的检验人;尚未提交复核时回落到上方
|
|
|
- 「审核来源」列出的审批流审批人 —— 它不是一个新的审核人员池。<br />
|
|
|
- 可用渠道:站内信、SignalR。
|
|
|
+ 通知通过站内信与实时推送送达,两者随通知一起发出、目前不单独开关 ——
|
|
|
+ 给一个点了没有实际效果的渠道开关,比不给更糟。
|
|
|
</div>
|
|
|
</el-tab-pane>
|
|
|
|