feat(msgcenter): /msg 换真实数据——服务端筛选+滚动分页、铃铛直跳、unreadCount 上提 store、WS 通知带应用名

- views/msg/index.vue:数据层整体替换(msgType 0/1/2 映射、isRead 1=已读、fmtTime 重写绝对时间);列表走 msgCenter/list 服务端筛选(msgType/appKey/isRead/keyword 防抖 300ms),滚动到底追加下一页,切视图/搜索重置第 1 页;左栏分类计数走 summary(旧版 UserMsg 缺字段降级显示 —),应用清单取 store 应用列表、计数同源 todos;点击卡片标已读、全部已读、去处理(showJump/jumpUrl)、审批直批(共享弹窗);失败态有重试;WS 新消息经 mittBus 自刷新
- components/Header.vue:铃铛直跳 /msg(移除 Poptip 浮层与 900 宽 Modal 及 columns/tableApi 死代码);unreadCount 上提 pinia store(角标与 /msg、LeftMenu 同源);WS Notice.info 标题带应用名(appKey 匹配 store 应用列表,缺失回退类型标签);壁纸/LOGO Modal 不动
- components/MsgApprovalModal.vue(新增):审批直批弹窗抽共享组件,逻辑照抄原 Header 内联实现(同意可选意见/拒绝必填校验/三种失败反馈)
- components/LeftMenu.vue:「消息」入口(url=/msg)未读角标(读 store,红底白字胶囊)
- store/index.ts:unreadCount + setUnreadCount/incUnread/decUnread
- api/BaseApi.ts:getMsgCenterList 参数类型放宽(服务端筛选项);getMsgCenterSummary 返回类型补分类计数字段(可缺省)
- assets/styles/header.scss:删除消息浮层死样式 .message-wrap 段
This commit is contained in:
chenxing
2026-09-30 12:37:30 +08:00
parent e91ce14408
commit 0f7101983e
7 changed files with 451 additions and 514 deletions
+89
View File
@@ -0,0 +1,89 @@
<template>
<!-- 消息卡片直批弹窗(B3 §2,消息对接 2026-09-30 抽共享):同意可选意见 / 拒绝意见必填;
身份(operatorId/schId/operatorName)服务端取会话。Header 铃铛域已无直批入口,
本组件供 /msg 消息中心页使用,逻辑照抄原 Header 内联实现。 -->
<Modal :model-value="visible" width="460" :mask-closable="false"
:title="action === 'approve' ? '同意办理' : '拒绝办理'" @on-cancel="close">
<div class="approval-body">
<p class="approval-title text-ellipsis">{{ title || "确认办理该待办?" }}</p>
<Input v-model="opinion" type="textarea" :rows="3" maxlength="200" show-word-limit
:placeholder="action === 'approve' ? '审批意见(可选)' : '请输入拒绝意见(必填)'" />
</div>
<template #footer>
<Button type="primary" :loading="submitting" @click="submit">
{{ action === "approve" ? "确认同意" : "确认拒绝" }}
</Button>
<Button @click="close">取消</Button>
</template>
</Modal>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
import { Notice } from "view-ui-plus";
import BaseApi from "@/api/BaseApi";
/**
* 审批直批弹窗(msgCenter/handle 代理)。
* 父组件 open({msgId, title, action}) 打开;成功(后端 ok)后 emit("handled", msgId),
* 失败/已被处理等场景只弹后端文案,不关弹窗(成功/失败/已被处理三种场景都有反馈)。
*/
const emit = defineEmits<{ (e: "handled", msgId: number): void }>();
const visible = ref(false);
const msgId = ref(0);
const title = ref("");
const action = ref<"approve" | "reject">("approve");
const opinion = ref("");
const submitting = ref(false);
function open(row: { msgId: number; title?: string }, act: "approve" | "reject") {
msgId.value = row.msgId;
action.value = act;
title.value = row.title ? String(row.title) : "";
opinion.value = "";
submitting.value = false;
visible.value = true;
}
function close() {
visible.value = false;
}
async function submit() {
if (submitting.value) return;
if (action.value === "reject" && !opinion.value.trim()) {
Notice.warning({ title: "拒绝必须填写意见", duration: 3 });
return;
}
submitting.value = true;
try {
const res: any = await BaseApi.handleMsg(msgId.value, action.value, opinion.value.trim());
if (res && res.ok) {
Notice.success({ title: "办理成功", duration: 3 });
visible.value = false;
emit("handled", msgId.value);
} else {
Notice.warning({ title: (res && res.message) || "办理失败", duration: 5 });
}
} catch (e) {
// flow-center 不可达等:降级为提示,不阻塞消息卡片其余功能
Notice.error({ title: "流程中心暂不可用,请稍后重试", duration: 5 });
} finally {
submitting.value = false;
}
}
defineExpose({ open });
</script>
<style scoped lang="scss">
.approval-body {
.approval-title {
font-size: 14px;
font-weight: 500;
color: #2c3138;
margin-bottom: 12px;
}
}
</style>