后端:
- MessageSseService (emitter 注册表, 25s 心跳, pushNewMessage 仅 log 不抛)
- BizMessageSseController (独立 Controller, 避开 /{msgId} 路径抢匹配)
- BizMessageMapper.countUnread SQL 修复 (跟 limit 解耦, SSE 推真值)
- BizMessageServiceImpl.insert/markRead 成功后 pushNewMessage 触发 SSE
- BizNotifyService.expertAuditResult (#1: 审核结果通知专家本人)
- BizExpertServiceImpl.updateByPrimaryKey 比对旧 audit_status, 真变化才发通知
- PlaceholderConfig (Spring 7 严格 placeholder 兜底, ignoreUnresolvable=true)
前端:
- utils/sseClient.js (@microsoft/fetch-event-source 封装, Bearer 鉴权, 单例连接)
- 全局事件总线 onGlobal: SSE new_message 扇出到业务页面 (切路由不掉)
- AdminLayout 全局订阅 + bell 角标 (el-badge 显示 unreadCount)
- userStore.expertAuditApproved: doctor 审核状态实时跟 DB
- AdminLayout doctor menu 加 requireAuditApproved 过滤 (未通过审核隐藏 3 menu)
- doctor/Home: 待参加会议/待签协议 2 pannel 按 audit 状态显示; load() 仅审核通过才拉数据
- doctor/Home + doctor/Messages: 点列表弹详情 dialog + markMessageRead 真已读
- AdminLayout SSE 触发时: 刷新 unread + 重新拉 audit 状态 (审核通过瞬间可见)
业务规则:
- 专家注册不群发 manager (manager 群体可能 100+, 每条注册发 N 条浪费)
- 通过审核无需重新登录 (SSE 链路实时联动)
50 lines
1.5 KiB
JavaScript
50 lines
1.5 KiB
JavaScript
import { defineStore } from 'pinia'
|
|
|
|
export const useUserStore = defineStore('user', {
|
|
state: () => ({
|
|
token: localStorage.getItem('ry_token') || '',
|
|
user: JSON.parse(localStorage.getItem('ry_user') || 'null'),
|
|
/**
|
|
* 当前用户 (doctor 角色) 的专家审核状态
|
|
* true = 审核通过 (audit_status='2'), false = 待审核/被拒绝/未注册
|
|
* 用于侧栏 menu 和首页 pannel 的可见性控制
|
|
* 非 doctor 角色保持 false (无意义)
|
|
*/
|
|
expertAuditApproved: false
|
|
}),
|
|
getters: {
|
|
role: (s) => s.user?.role || '',
|
|
isLogin: (s) => !!s.user,
|
|
accountType: (s) => s.user?.accountType || 'MAIN',
|
|
parentUserId: (s) => s.user?.parentUserId || null,
|
|
isMain: (s) => (s.user?.accountType || 'MAIN') === 'MAIN',
|
|
isSub: (s) => s.user?.accountType === 'SUB'
|
|
},
|
|
actions: {
|
|
setLogin(token, user) {
|
|
this.token = token
|
|
this.user = user
|
|
localStorage.setItem('ry_token', token)
|
|
localStorage.setItem('ry_user', JSON.stringify(user))
|
|
},
|
|
setToken(token) {
|
|
this.token = token
|
|
localStorage.setItem('ry_token', token)
|
|
},
|
|
setUser(user) {
|
|
this.user = user
|
|
localStorage.setItem('ry_user', JSON.stringify(user))
|
|
},
|
|
setExpertAuditApproved(v) {
|
|
this.expertAuditApproved = !!v
|
|
},
|
|
logout() {
|
|
this.token = ''
|
|
this.user = null
|
|
this.expertAuditApproved = false
|
|
localStorage.removeItem('ry_token')
|
|
localStorage.removeItem('ry_user')
|
|
}
|
|
}
|
|
})
|