@robot-admin/naive-ui-components 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/C_NotificationCenter.css +114 -78
  3. package/dist/C_NotificationCenter.d.cts +2 -2
  4. package/dist/C_NotificationCenter.d.ts +2 -2
  5. package/dist/C_NotificationCenter2.cjs +1 -1
  6. package/dist/C_NotificationCenter2.js +1 -1
  7. package/dist/constants.d.cts +1 -1
  8. package/dist/constants.d.ts +1 -1
  9. package/dist/constants3.d.cts +73 -119
  10. package/dist/constants3.d.ts +73 -119
  11. package/dist/constants4.d.cts +2 -2
  12. package/dist/constants4.d.ts +2 -2
  13. package/dist/constants5.d.cts +4 -4
  14. package/dist/constants5.d.ts +4 -4
  15. package/dist/data.d.cts +9 -9
  16. package/dist/data.d.ts +9 -9
  17. package/dist/index.d.cts +2 -2
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.vue.d.cts +3 -3
  20. package/dist/index.vue.d.ts +3 -3
  21. package/dist/index10.vue.d.cts +3 -3
  22. package/dist/index10.vue.d.ts +1 -1
  23. package/dist/index11.vue.d.cts +1 -1
  24. package/dist/index11.vue.d.ts +2 -2
  25. package/dist/index12.vue.d.cts +2 -2
  26. package/dist/index13.vue.d.ts +2 -2
  27. package/dist/index14.vue.d.cts +2 -2
  28. package/dist/index14.vue.d.ts +7 -7
  29. package/dist/index15.vue.d.cts +7 -7
  30. package/dist/index15.vue.d.ts +1 -1
  31. package/dist/index16.vue.d.cts +1 -1
  32. package/dist/index16.vue.d.ts +1 -1
  33. package/dist/index17.vue.d.cts +1 -1
  34. package/dist/index17.vue.d.ts +2 -2
  35. package/dist/index18.vue.d.cts +2 -2
  36. package/dist/index18.vue.d.ts +4 -4
  37. package/dist/index19.vue.d.cts +4 -4
  38. package/dist/index19.vue.d.ts +1 -1
  39. package/dist/index2.vue.d.cts +2 -2
  40. package/dist/index2.vue.d.ts +2 -2
  41. package/dist/index20.vue.d.cts +2 -2
  42. package/dist/index20.vue.d.ts +2 -2
  43. package/dist/index21.vue.d.cts +1 -1
  44. package/dist/index21.vue.d.ts +1 -1
  45. package/dist/index22.vue.d.cts +2 -2
  46. package/dist/index22.vue.d.ts +2 -2
  47. package/dist/index23.vue.d.cts +1 -1
  48. package/dist/index23.vue.d.ts +1 -1
  49. package/dist/index25.vue.d.cts +3 -3
  50. package/dist/index25.vue.d.ts +3 -3
  51. package/dist/index27.vue.d.cts +3 -3
  52. package/dist/index27.vue.d.ts +3 -3
  53. package/dist/index28.vue.d.cts +3 -3
  54. package/dist/index28.vue.d.ts +3 -3
  55. package/dist/index3.vue.d.cts +3 -3
  56. package/dist/index3.vue.d.ts +3 -3
  57. package/dist/index4.vue.d.cts +1 -1
  58. package/dist/index6.vue.d.ts +2 -2
  59. package/dist/index7.vue.d.cts +2 -2
  60. package/dist/index9.vue.d.ts +3 -3
  61. package/dist/mapUtils.d.cts +3 -3
  62. package/dist/mapUtils.d.ts +3 -3
  63. package/dist/style.css +115 -79
  64. package/dist/useCalendarEvents.d.cts +1 -1
  65. package/dist/useCalendarEvents.d.ts +1 -1
  66. package/dist/useCollapsePanel.d.cts +1 -1
  67. package/dist/useCollapsePanel.d.ts +1 -1
  68. package/dist/useCropperCore.d.cts +6 -6
  69. package/dist/useCropperCore.d.ts +6 -6
  70. package/dist/useDraggableLayout.d.cts +3 -3
  71. package/dist/useDraggableLayout.d.ts +3 -3
  72. package/dist/useDynamicFormState.d.cts +2 -2
  73. package/dist/useDynamicFormState.d.ts +2 -2
  74. package/dist/useEdgeInteraction.d.cts +1 -1
  75. package/dist/useEdgeInteraction.d.ts +1 -1
  76. package/dist/useFullscreen.d.cts +2 -2
  77. package/dist/useFullscreen.d.ts +2 -2
  78. package/dist/useInfiniteScroll.d.cts +1 -1
  79. package/dist/useInfiniteScroll.d.ts +1 -1
  80. package/dist/useQRCode.d.cts +1 -1
  81. package/dist/useQRCode.d.ts +1 -1
  82. package/dist/useSearchState.d.cts +3 -3
  83. package/dist/useSearchState.d.ts +3 -3
  84. package/dist/useSignatureHistory.d.cts +4 -4
  85. package/dist/useSignatureHistory.d.ts +4 -4
  86. package/dist/useSplitResize.d.cts +6 -6
  87. package/dist/useSplitResize.d.ts +6 -6
  88. package/dist/useTableQuery.d.cts +1 -1
  89. package/dist/useTableQuery.d.ts +1 -1
  90. package/dist/useTimeSelection.d.cts +1 -1
  91. package/dist/useTimeSelection.d.ts +1 -1
  92. package/dist/useTreeOperations.d.cts +6 -6
  93. package/dist/useTreeOperations.d.ts +6 -6
  94. package/dist/useWorkflowValidation.d.cts +2 -2
  95. package/dist/useWorkflowValidation.d.ts +2 -2
  96. package/dist/verification.d.cts +1 -1
  97. package/dist/verification.d.ts +1 -1
  98. package/docs/components.en.md +5 -5
  99. package/docs/components.md +5 -5
  100. package/docs/guides/notification-center.md +95 -0
  101. package/package.json +1 -1
@@ -1 +1 @@
1
- import{t as e}from"./C_Icon2.js";import{t}from"./export-helper.js";import{t as n}from"./html.js";import{i as r,t as i}from"./storage.js";import{Fragment as a,Transition as o,computed as s,createBlock as c,createCommentVNode as l,createElementBlock as u,createElementVNode as d,createTextVNode as f,createVNode as p,defineComponent as m,normalizeClass as h,normalizeStyle as g,onBeforeUnmount as _,onMounted as v,openBlock as y,readonly as b,ref as x,renderList as S,resolveComponent as C,toDisplayString as w,unref as T,watch as E,withCtx as D,withModifiers as O}from"vue";import{NAvatar as k,NButton as A,NPopover as ee,NScrollbar as j,NSkeleton as M,NSpin as N,NTag as P,NTooltip as F}from"naive-ui";const I=99,L=20,R=6e4,z=`notification_center`,B=3e3,V=5,H=3e4,U=`ping`,W={system:{label:`系统通知`,icon:`mdi:cog-outline`,color:`info`},business:{label:`业务消息`,icon:`mdi:briefcase-outline`,color:`success`},alarm:{label:`告警预警`,icon:`mdi:alert-outline`,color:`warning`}},G=[{key:`all`,label:`全部`},{key:`system`,label:`系统通知`},{key:`business`,label:`业务消息`},{key:`alarm`,label:`告警预警`}],K={low:{label:`低`,type:`default`},normal:{label:`普通`,type:`info`},high:{label:`重要`,type:`warning`},urgent:{label:`紧急`,type:`error`}},q=[{id:`msg-001`,title:`系统维护通知`,summary:`系统将于今晚 22:00-23:00 进行例行维护升级,届时部分功能可能暂时不可用。`,content:`<p>尊敬的用户:</p><p>为了提升系统性能和稳定性,我们计划于 <strong>2026年2月27日 22:00-23:00</strong> 对系统进行例行维护升级。</p><p>维护期间,以下功能可能暂时不可用:</p><ul><li>报表导出</li><li>数据同步</li><li>定时任务</li></ul><p>请提前保存好未完成的工作,感谢您的理解与支持!</p>`,category:`system`,priority:`high`,status:`unread`,timestamp:new Date(Date.now()-15*6e4).toISOString(),sender:{name:`系统管理员`,avatar:``}},{id:`msg-002`,title:`审批流程待处理`,summary:`张三提交的《Q1 季度预算申请》需要您审批,请尽快处理。`,category:`business`,priority:`urgent`,status:`unread`,timestamp:new Date(Date.now()-30*6e4).toISOString(),sender:{name:`张三`,avatar:``},actionUrl:`/workflow/approval`,actionText:`去审批`},{id:`msg-003`,title:`服务器 CPU 使用率告警`,summary:`生产环境节点 prod-node-03 CPU 使用率持续超过 90%,已触发告警阈值。`,category:`alarm`,priority:`urgent`,status:`unread`,timestamp:new Date(Date.now()-2*6e4).toISOString(),sender:{name:`监控中心`},actionUrl:`/monitor/server`,actionText:`查看详情`},{id:`msg-004`,title:`新版本发布 v1.14.0`,summary:`系统已升级至 v1.14.0,新增通知中心、工作流增强等多项功能。`,category:`system`,priority:`normal`,status:`unread`,timestamp:new Date(Date.now()-3*36e5).toISOString(),sender:{name:`系统管理员`}},{id:`msg-005`,title:`项目交付提醒`,summary:`「Robot Admin 二期」项目交付截止日期为 3月15日,当前进度 78%。`,category:`business`,priority:`high`,status:`read`,timestamp:new Date(Date.now()-8*36e5).toISOString(),sender:{name:`项目管理系统`}},{id:`msg-006`,title:`数据库连接池告警`,summary:`数据库连接池使用率达到 85%,建议关注并适时扩容。`,category:`alarm`,priority:`high`,status:`read`,timestamp:new Date(Date.now()-12*36e5).toISOString(),sender:{name:`监控中心`}},{id:`msg-007`,title:`周报提交提醒`,summary:`本周周报提交截止时间为周五 18:00,请及时提交。`,category:`business`,priority:`normal`,status:`read`,timestamp:new Date(Date.now()-24*36e5).toISOString(),sender:{name:`OA 系统`}},{id:`msg-008`,title:`账号安全提醒`,summary:`检测到您的账号在新设备上登录,如非本人操作请及时修改密码。`,category:`system`,priority:`high`,status:`unread`,timestamp:new Date(Date.now()-45*6e4).toISOString(),sender:{name:`安全中心`}}];function J(e,t){let n=x(`disconnected`),r=null,i=0,a=null,o=null,s=null,c=0;function l(e){n.value=e,t?.(e)}function u(e){s=e,i=0,d(e)}function d(e){let t=++c;v();let n=f(e);l(`connecting`);try{r=new WebSocket(n)}catch{l(`disconnected`),m(e);return}let a=r;a.addEventListener(`open`,()=>{t!==c||a!==r||(l(`connected`),i=0,h(e))}),a.addEventListener(`message`,e=>{t!==c||a!==r||p(e.data)}),a.addEventListener(`close`,()=>{t!==c||a!==r||(r=null,g(),l(`disconnected`),e.autoReconnect!==!1&&m(e))}),a.addEventListener(`error`,()=>{})}function f(e){let t=e.getToken?.();if(t){let n=e.url.includes(`?`)?`&`:`?`;return`${e.url}${n}token=${encodeURIComponent(t)}`}return e.url}function p(t){if(typeof t==`string`&&t!==`pong`)try{let n=JSON.parse(t);n&&typeof n==`object`&&[`new_message`,`read_sync`,`count_update`].includes(String(n.type))&&`data`in n&&e(n)}catch{}}function m(e){if(s!==e||a)return;let t=Math.max(0,Math.trunc(e.maxReconnectAttempts??5));if(i>=t)return;i++,l(`reconnecting`);let n=Math.max(0,e.reconnectInterval??B),r=Math.min(6e4,n*2**(i-1)),o=c;a=setTimeout(()=>{a=null,!(o!==c||s!==e)&&d(e)},r)}function h(e){g();let t=e.heartbeatInterval??H;if(t<=0)return;let n=e.heartbeatMessage??U;o=setInterval(()=>{if(r?.readyState===WebSocket.OPEN)try{r.send(n)}catch{r.close()}},t)}function g(){o&&=(clearInterval(o),null)}function v(){g(),a&&=(clearTimeout(a),null),r&&=(r.close(),null)}function y(){s=null,c++,i=0,v(),l(`disconnected`)}function S(){s&&(i=0,d(s))}return _(()=>{s=null,c++,v()}),{status:b(n),connect:u,disconnect:y,reconnect:S}}function Y(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.id==`string`&&typeof t.title==`string`&&typeof t.summary==`string`&&typeof t.timestamp==`string`&&[`system`,`business`,`alarm`].includes(String(t.category))&&[`low`,`normal`,`high`,`urgent`].includes(String(t.priority))&&[`read`,`unread`,`archived`].includes(String(t.status))}function X(e,t={}){let n=x([]),a=x(`all`),o=x(!1),c=x(0),l=x(1),u=x(null),d=x(!1),f=x(`disconnected`),p=0,m=s(()=>n.value.filter(e=>e.status===`unread`).length),h=s(()=>{let e={system:0,business:0,alarm:0};for(let t of n.value)t.status===`unread`&&t.category in e&&e[t.category]++;return e}),g=s(()=>a.value===`all`?n.value:n.value.filter(e=>e.category===a.value)),y=s(()=>n.value.length<c.value),b=s(()=>e.storageKey??z);function S(){if(e.fetchNotifications)return;let t=i(b.value);if(Array.isArray(t?.readIds)){let e=new Set(t.readIds.filter(e=>typeof e==`string`));for(let t of n.value)e.has(t.id)&&t.status!==`archived`&&(t.status=`read`)}}let C=null;function w(){e.fetchNotifications||(C&&clearTimeout(C),C=setTimeout(()=>{let e=n.value.filter(e=>e.status===`read`).map(e=>e.id);r(b.value,{readIds:e,lastFetchTime:Date.now()}),C=null},300))}async function T(t=!1){let r=++p;t&&(l.value=1),o.value=!0;try{if(e.fetchNotifications){let i=a.value===`all`?void 0:a.value,o=e.pageSize??20,s=await e.fetchNotifications({category:i,page:l.value,pageSize:o});if(r!==p)return;let u=Array.isArray(s.list)?s.list.map(e=>({...e})):[];if(t)n.value=u;else{let e=new Set(n.value.map(e=>e.id));n.value.push(...u.filter(t=>!e.has(t.id)))}c.value=Math.max(n.value.length,Number(s.total)||0)}else E();r===p&&S()}catch(t){throw r===p&&e.onError?.(t,`fetch`),t}finally{r===p&&(o.value=!1)}}function E(){n.value=q.map(e=>({...e})),c.value=q.length}async function D(){if(!y.value||o.value)return;let e=l.value;l.value++;try{await T()}catch(t){throw l.value=e,t}}async function O(t){let r=new Set(t),i=new Map(n.value.filter(e=>r.has(e.id)).map(e=>[e.id,e.status]));for(let e of n.value)r.has(e.id)&&(e.status=`read`);if(w(),e.markAsRead)try{await e.markAsRead(t)}catch(t){for(let e of n.value){let t=i.get(e.id);t&&(e.status=t)}throw w(),e.onError?.(t,`mark-as-read`),t}}async function k(t){let r=t?n.value.filter(e=>e.category===t&&e.status===`unread`):n.value.filter(e=>e.status===`unread`);for(let e of r)e.status=`read`;if(w(),e.markAllRead)try{await e.markAllRead(t)}catch(t){for(let e of r)e.status=`unread`;throw w(),e.onError?.(t,`mark-all-as-read`),t}}async function A(t){let r=new Set(t),i=[...n.value],a=c.value;if(n.value=n.value.filter(e=>!r.has(e.id)),c.value=Math.max(0,c.value-(i.length-n.value.length)),w(),e.deleteNotification)try{await e.deleteNotification(t)}catch(t){throw n.value=i,c.value=a,w(),e.onError?.(t,`delete`),t}}async function ee(t){let r=[...n.value],i=c.value;if(t?n.value=n.value.filter(e=>e.category!==t):n.value=[],c.value=n.value.length,w(),e.clearNotifications)try{await e.clearNotifications(t)}catch(t){throw n.value=r,c.value=i,w(),e.onError?.(t,`clear`),t}}function j(e){switch(e.type){case`new_message`:{let r=e.data;if(!Y(r))return;n.value.some(e=>e.id===r.id)||(n.value.unshift(r),c.value++,w(),t.onNewMessage?.(r),F(r));break}case`read_sync`:{if(!Array.isArray(e.data))return;let t=e.data.filter(Y),r=new Set(t.map(e=>e.id));for(let e of n.value)r.has(e.id)&&(e.status=`read`);w();break}case`count_update`:break}}function M(e){f.value=e,t.onWSStatusChange?.(e)}let{connect:N,disconnect:P}=J(j,M);function F(t){e.desktopNotification&&(typeof window>`u`||!(`Notification`in window)||Notification.permission===`granted`&&L(t))}async function I(){return typeof window>`u`||!(`Notification`in window)?`unsupported`:Notification.requestPermission()}function L(e){let t=new Notification(e.title,{body:e.summary,icon:e.sender?.avatar||`/robot-avatar.png`,tag:e.id});t.addEventListener(`click`,()=>{window.focus(),U(e),t.close()}),setTimeout(()=>t.close(),5e3)}let B=null;function V(){H();let t=e.pollingInterval??R;t<=0||(B=setInterval(()=>{o.value||T(!0).catch(()=>void 0)},t))}function H(){B&&=(clearInterval(B),null)}function U(e){u.value=e,e.status===`unread`&&O([e.id]).catch(()=>void 0)}function W(){u.value=null}function G(t){a.value=t,u.value=null,e.fetchNotifications&&T(!0).catch(()=>void 0)}function K(){T(!0).catch(()=>void 0),V(),e.wsConfig&&N(e.wsConfig)}function X(){p++,H(),P(),C&&=(clearTimeout(C),null)}return v(K),_(X),{messages:n,activeCategory:a,loading:o,total:c,page:l,selectedMessage:u,popoverVisible:d,wsStatus:f,unreadCount:m,unreadByCategory:h,filteredMessages:g,hasMore:y,fetchMessages:T,loadMore:D,markAsRead:O,markAllAsRead:k,deleteMessages:A,clearMessages:ee,selectMessage:U,clearSelection:W,switchCategory:G,requestDesktopPermission:I,connectWS:N,disconnectWS:P}}const te={class:`notification-badge`},ne=[`aria-label`],re={key:0,class:`notification-badge__count`},ie={key:0,class:`notification-badge__pulse`};var ae=t(m({__name:`NotificationBadge`,props:{count:{default:0},maxCount:{default:99},hasUrgent:{type:Boolean,default:!1}},emits:[`click`],setup(t){let n=t,r=s(()=>n.count>n.maxCount?`${n.maxCount}+`:String(n.count));return(n,i)=>{let a=F;return y(),u(`div`,te,[p(a,{trigger:`hover`,placement:`bottom`},{trigger:D(()=>[d(`button`,{type:`button`,class:`notification-badge__trigger`,"aria-label":`消息通知${t.count>0?`(${t.count} 条未读)`:``}`,onClick:i[0]||=e=>n.$emit(`click`)},[p(e,{name:`mdi:bell-outline`,size:18,class:`notification-badge__icon`}),l(` 未读角标 `),p(o,{name:`badge-bounce`},{default:D(()=>[t.count>0?(y(),u(`span`,re,w(r.value),1)):l(`v-if`,!0)]),_:1}),l(` 脉冲动画(有紧急消息时) `),t.hasUrgent?(y(),u(`span`,ie)):l(`v-if`,!0)],8,ne)]),default:D(()=>[f(` 消息通知`+w(t.count>0?`(${t.count} 条未读)`:``),1)]),_:1})])}}}),[[`__scopeId`,`data-v-51516250`]]);const Z=6e4,oe=36e5,Q=864e5,se=7*Q,ce=30*Q;365*Q;let le=null;function $(){return le||=ue(),le}function ue(){function e(e){let r=new Date(e),i=Date.now()-r.getTime();if(i<0||i<Z)return`刚刚`;if(i<oe)return`${Math.floor(i/Z)}分钟前`;if(i<Q)return`${Math.floor(i/oe)}小时前`;let a=new Date;return a.setHours(0,0,0,0),r>=new Date(a.getTime()-Q)&&r<a?`昨天 ${n(r.getHours())}:${n(r.getMinutes())}`:i<se?`${Math.floor(i/Q)}天前`:i<ce?`${Math.floor(i/se)}周前`:i<31536e6?`${Math.floor(i/ce)}个月前`:t(r)}function t(e){return`${e.getFullYear()}-${n(e.getMonth()+1)}-${n(e.getDate())} ${n(e.getHours())}:${n(e.getMinutes())}`}function n(e){return e<10?`0${e}`:String(e)}return{formatRelativeTime:e,formatFullDate:t}}const de={class:`notification-item__indicator`},fe={class:`notification-item__avatar`},pe={class:`notification-item__body`},me={class:`notification-item__header`},he={class:`notification-item__title`},ge={class:`notification-item__summary`},_e={class:`notification-item__meta`},ve={class:`notification-item__time`},ye={key:0,class:`notification-item__sender`};var be=t(m({__name:`NotificationItem`,props:{message:{}},emits:[`click`,`read`,`delete`],setup(t){let n=t,{formatRelativeTime:r}=$(),i=s(()=>W[n.message.category]?.icon??`mdi:bell-outline`),a=s(()=>K[n.message.priority]??K.normal),o=s(()=>r(n.message.timestamp));return(n,r)=>{let s=k,m=P,g=F;return y(),u(`div`,{class:h([`notification-item`,{"notification-item--unread":t.message.status===`unread`,"notification-item--urgent":t.message.priority===`urgent`}]),onClick:r[3]||=e=>n.$emit(`click`,t.message)},[l(` 未读指示点 `),d(`div`,de,[t.message.status===`unread`?(y(),u(`span`,{key:0,class:h([`notification-item__dot`,`notification-item__dot--${t.message.priority}`])},null,2)):l(`v-if`,!0)]),l(` 头像 `),d(`div`,fe,[t.message.sender?.avatar?(y(),c(s,{key:0,src:t.message.sender.avatar,size:36,round:``},null,8,[`src`])):(y(),u(`div`,{key:1,class:h([`notification-item__avatar-placeholder`,`notification-item__avatar-placeholder--${t.message.category}`])},[p(e,{name:i.value,size:16},null,8,[`name`])],2))]),l(` 内容 `),d(`div`,pe,[d(`div`,me,[d(`span`,he,w(t.message.title),1),t.message.priority===`urgent`||t.message.priority===`high`?(y(),c(m,{key:0,type:a.value.type,size:`tiny`,bordered:!1,round:``},{default:D(()=>[f(w(a.value.label),1)]),_:1},8,[`type`])):l(`v-if`,!0)]),d(`div`,ge,w(t.message.summary),1),d(`div`,_e,[d(`span`,ve,w(o.value),1),t.message.sender?.name?(y(),u(`span`,ye,w(t.message.sender.name),1)):l(`v-if`,!0)])]),l(` 操作区 `),d(`div`,{class:`notification-item__actions`,onClick:r[2]||=O(()=>{},[`stop`])},[t.message.status===`unread`?(y(),c(g,{key:0,trigger:`hover`,placement:`top`},{trigger:D(()=>[d(`span`,{class:`notification-item__action`,onClick:r[0]||=e=>n.$emit(`read`,t.message.id)},[p(e,{name:`mdi:check`,size:16})])]),default:D(()=>[r[4]||=f(` 标记已读 `,-1)]),_:1})):l(`v-if`,!0),p(g,{trigger:`hover`,placement:`top`},{trigger:D(()=>[d(`span`,{class:`notification-item__action`,onClick:r[1]||=e=>n.$emit(`delete`,t.message.id)},[p(e,{name:`mdi:delete-outline`,size:16})])]),default:D(()=>[r[5]||=f(` 删除 `,-1)]),_:1})])],2)}}}),[[`__scopeId`,`data-v-2f1c8e96`]]);const xe={class:`notification-list`},Se={class:`notification-list__tabs`},Ce=[`onClick`],we={key:0,class:`notification-list__tab-count`},Te={key:0,class:`notification-list__toolbar`},Ee={class:`notification-list__skeleton-text`},De={class:`notification-list__items`},Oe={class:`notification-list__empty`};var ke=t(m({__name:`NotificationList`,props:{messages:{},activeCategory:{},unreadByCategory:{},unreadCount:{},loading:{type:Boolean},hasMore:{type:Boolean},scrollHeight:{default:420}},emits:[`switchCategory`,`itemClick`,`read`,`delete`,`markAllRead`,`clear`,`loadMore`],setup(t){let n=t,r=s(()=>n.activeCategory===`all`?n.unreadCount:n.unreadByCategory[n.activeCategory]??0);function i(e){return e===`all`?n.unreadCount:n.unreadByCategory[e]??0}return(n,o)=>{let s=A,m=M,_=N,v=j;return y(),u(`div`,xe,[l(` 分类 Tab `),d(`div`,Se,[(y(!0),u(a,null,S(T(G),e=>(y(),u(`div`,{key:e.key,class:h([`notification-list__tab`,{"notification-list__tab--active":t.activeCategory===e.key}]),onClick:t=>n.$emit(`switchCategory`,e.key)},[d(`span`,null,w(e.label),1),i(e.key)>0?(y(),u(`span`,we,w(i(e.key)),1)):l(`v-if`,!0)],10,Ce))),128))]),l(` 操作栏 `),t.messages.length>0?(y(),u(`div`,Te,[p(s,{text:``,size:`tiny`,disabled:r.value===0,onClick:o[0]||=e=>n.$emit(`markAllRead`)},{icon:D(()=>[p(e,{name:`mdi:check-all`,size:14})]),default:D(()=>[o[6]||=f(` 全部已读 `,-1)]),_:1},8,[`disabled`]),p(s,{text:``,size:`tiny`,onClick:o[1]||=e=>n.$emit(`clear`)},{icon:D(()=>[p(e,{name:`mdi:delete-sweep-outline`,size:14})]),default:D(()=>[o[7]||=f(` 清空 `,-1)]),_:1})])):l(`v-if`,!0),l(` 消息列表 `),p(v,{class:`notification-list__scroll`,style:g({maxHeight:`${t.scrollHeight}px`})},{default:D(()=>[t.loading&&t.messages.length===0?(y(),u(a,{key:0},[l(` 骨架屏 `),(y(),u(a,null,S(4,e=>d(`div`,{key:e,class:`notification-list__skeleton`},[p(m,{circle:``,width:36,height:36}),d(`div`,Ee,[p(m,{text:``,width:`60%`,height:14}),p(m,{text:``,width:`90%`,height:12}),p(m,{text:``,width:`40%`,height:10})])])),64))],64)):t.messages.length>0?(y(),u(a,{key:1},[d(`div`,De,[(y(!0),u(a,null,S(t.messages,e=>(y(),c(be,{key:e.id,message:e,onClick:o[2]||=e=>n.$emit(`itemClick`,e),onRead:o[3]||=e=>n.$emit(`read`,e),onDelete:o[4]||=e=>n.$emit(`delete`,e)},null,8,[`message`]))),128))]),l(` 加载更多 `),t.hasMore?(y(),u(`div`,{key:0,class:`notification-list__load-more`,onClick:o[5]||=e=>n.$emit(`loadMore`)},[t.loading?(y(),c(_,{key:0,size:14})):l(`v-if`,!0),d(`span`,null,w(t.loading?`加载中...`:`加载更多`),1)])):l(`v-if`,!0)],64)):(y(),u(a,{key:2},[l(` 空状态 `),d(`div`,Oe,[p(e,{name:`mdi:bell-off-outline`,size:48,class:`notification-list__empty-icon`}),o[8]||=d(`span`,{class:`notification-list__empty-text`},`暂无消息`,-1)])],2112))]),_:1},8,[`style`])])}}}),[[`__scopeId`,`data-v-d366768f`]]);function Ae(e){return e.includes(`\\`)||e.startsWith(`//`)||Array.from(e).some(e=>e.charCodeAt(0)<32)}function je(e){let t=e?.trim();if(!t||Ae(t))return null;if(/^https?:\/\//i.test(t))try{let e=new URL(t);return e.protocol!==`http:`&&e.protocol!==`https:`?null:{kind:`external`,url:e.href}}catch{return null}return/^[a-z][a-z\d+.-]*:/i.test(t)?null:{kind:`internal`,url:t}}const Me={class:`notification-detail`},Ne={class:`notification-detail__back`},Pe={class:`notification-detail__header`},Fe={class:`notification-detail__title`},Ie={class:`notification-detail__meta`},Le={class:`notification-detail__time`},Re={key:0,class:`notification-detail__sender`},ze=[`innerHTML`],Be={key:1,class:`notification-detail__body`},Ve={key:0,class:`notification-detail__footer`};var He=t(m({__name:`NotificationDetail`,props:{message:{},scrollHeight:{default:320}},emits:[`back`,`action`,`navigate`],setup(t,{emit:r}){let i=t,a=r,{formatRelativeTime:o}=$(),m=s(()=>W[i.message.category]??W.system),h=s(()=>K[i.message.priority]??K.normal),_=s(()=>o(i.message.timestamp)),v=s(()=>n(i.message.content||``));function b(){let e=je(i.message.actionUrl);e&&(a(`action`,e.url),e.kind===`external`?window.open(e.url,`_blank`,`noopener,noreferrer`):a(`navigate`,e.url))}return(n,r)=>{let i=A,a=P,o=k,s=j;return y(),u(`div`,Me,[l(` 返回栏 `),d(`div`,Ne,[p(i,{text:``,size:`small`,onClick:r[0]||=e=>n.$emit(`back`)},{icon:D(()=>[p(e,{name:`mdi:arrow-left`,size:16})]),default:D(()=>[r[1]||=f(` 返回列表 `,-1)]),_:1})]),l(` 消息头部 `),d(`div`,Pe,[d(`h3`,Fe,w(t.message.title),1),d(`div`,Ie,[p(a,{type:m.value.color,size:`tiny`,bordered:!1,round:``},{icon:D(()=>[p(e,{name:m.value.icon,size:12},null,8,[`name`])]),default:D(()=>[f(` `+w(m.value.label),1)]),_:1},8,[`type`]),t.message.priority===`urgent`||t.message.priority===`high`?(y(),c(a,{key:0,type:h.value.type,size:`tiny`,bordered:!1,round:``},{default:D(()=>[f(w(h.value.label),1)]),_:1},8,[`type`])):l(`v-if`,!0),d(`span`,Le,w(_.value),1)]),t.message.sender?(y(),u(`div`,Re,[t.message.sender.avatar?(y(),c(o,{key:0,src:t.message.sender.avatar,size:20,round:``},null,8,[`src`])):l(`v-if`,!0),d(`span`,null,w(t.message.sender.name),1)])):l(`v-if`,!0)]),l(` 消息内容 `),p(s,{class:`notification-detail__content`,style:g({maxHeight:`${t.scrollHeight}px`})},{default:D(()=>[t.message.content?(y(),u(`div`,{key:0,class:`notification-detail__body`,innerHTML:v.value},null,8,ze)):(y(),u(`div`,Be,w(t.message.summary),1))]),_:1},8,[`style`]),l(` 操作区 `),t.message.actionUrl?(y(),u(`div`,Ve,[p(i,{type:`primary`,size:`small`,onClick:b},{icon:D(()=>[p(e,{name:`mdi:arrow-right`,size:16})]),default:D(()=>[f(w(t.message.actionText||`查看详情`)+` `,1)]),_:1})])):l(`v-if`,!0)])}}}),[[`__scopeId`,`data-v-8e02b6cd`]]);const Ue={class:`c-notification-center`},We={class:`c-notification-center__panel`},Ge={class:`c-notification-center__header`},Ke={class:`c-notification-center__header-extra`};var qe=t(m({name:`C_NotificationCenter`,__name:`index`,props:{fetchNotifications:{},markAsRead:{},markAllRead:{},deleteNotification:{},clearNotifications:{},wsConfig:{},desktopNotification:{type:Boolean,default:!1},maxBadgeCount:{default:99},pollingInterval:{default:6e4},pageSize:{default:20},storageKey:{default:`notification_center`},onError:{}},emits:[`itemClick`,`read`,`allRead`,`delete`,`unreadChange`,`wsStatusChange`,`newMessage`,`navigate`],setup(e,{expose:t,emit:n}){let r=e,i=n,a=X(r,{onNewMessage:e=>i(`newMessage`,e),onWSStatusChange:e=>i(`wsStatusChange`,e)}),m=s(()=>a.messages.value.some(e=>e.status===`unread`&&e.priority===`urgent`)),g=s(()=>({connected:`已连接`,connecting:`连接中...`,disconnected:`未连接`,reconnecting:`重连中...`})[a.wsStatus.value]??`未知`);E(()=>a.unreadCount.value,e=>{i(`unreadChange`,e)});function _(){a.popoverVisible.value=!a.popoverVisible.value}function v(e){a.selectMessage(e),i(`itemClick`,e)}async function b(e){try{await a.markAsRead([e]),i(`read`,[e])}catch{}}async function x(e){try{await a.deleteMessages([e]),i(`delete`,[e])}catch{}}async function S(){let e=a.activeCategory.value===`all`?void 0:a.activeCategory.value;try{await a.markAllAsRead(e),i(`allRead`,e)}catch{}}async function C(){let e=a.activeCategory.value===`all`?void 0:a.activeCategory.value;try{await a.clearMessages(e)}catch{}}function O(){a.popoverVisible.value=!1}function k(){a.clearSelection()}return t({refresh:()=>a.fetchMessages(!0),connectWS:()=>{r.wsConfig&&a.connectWS(r.wsConfig)},disconnectWS:a.disconnectWS,getUnreadCount:()=>a.unreadCount.value,getMessages:()=>a.messages.value.map(e=>({...e})),markRead:e=>a.markAsRead(e),markAllAsRead:e=>a.markAllAsRead(e),requestDesktopPermission:a.requestDesktopPermission}),(e,t)=>{let n=F,s=ee;return y(),u(`div`,Ue,[p(s,{show:T(a).popoverVisible.value,"onUpdate:show":t[1]||=e=>T(a).popoverVisible.value=e,width:420,trigger:`manual`,placement:`bottom-end`,"show-arrow":!1,"content-class":`c-notification-center__popover`,onAfterLeave:k},{trigger:D(()=>[p(ae,{count:T(a).unreadCount.value,"max-count":r.maxBadgeCount,"has-urgent":m.value,onClick:_},null,8,[`count`,`max-count`,`has-urgent`])]),default:D(()=>[d(`div`,We,[l(` 头部标题 `),d(`div`,Ge,[t[2]||=d(`span`,{class:`c-notification-center__title`},`消息中心`,-1),d(`div`,Ke,[l(` WebSocket 连接状态 `),r.wsConfig?(y(),c(n,{key:0,trigger:`hover`,placement:`top`},{trigger:D(()=>[d(`span`,{class:h([`c-notification-center__ws-dot`,`c-notification-center__ws-dot--${T(a).wsStatus.value}`])},null,2)]),default:D(()=>[f(` `+w(g.value),1)]),_:1})):l(`v-if`,!0)])]),l(` 列表 / 详情切换 `),p(o,{name:`slide-fade`,mode:`out-in`},{default:D(()=>[T(a).selectedMessage.value?(y(),c(He,{key:T(a).selectedMessage.value.id,message:T(a).selectedMessage.value,onBack:T(a).clearSelection,onAction:O,onNavigate:t[0]||=e=>i(`navigate`,e)},null,8,[`message`,`onBack`])):(y(),c(ke,{key:1,messages:T(a).filteredMessages.value,"active-category":T(a).activeCategory.value,"unread-by-category":T(a).unreadByCategory.value,"unread-count":T(a).unreadCount.value,loading:T(a).loading.value,"has-more":T(a).hasMore.value,onSwitchCategory:T(a).switchCategory,onItemClick:v,onRead:b,onDelete:x,onMarkAllRead:S,onClear:C,onLoadMore:T(a).loadMore},null,8,[`messages`,`active-category`,`unread-by-category`,`unread-count`,`loading`,`has-more`,`onSwitchCategory`,`onLoadMore`]))]),_:1})])]),_:1},8,[`show`])])}}}),[[`__scopeId`,`data-v-a06c4b3a`]]);export{W as a,L as c,H as d,U as f,K as g,q as h,J as i,R as l,B as m,$ as n,G as o,V as p,X as r,I as s,qe as t,z as u};
1
+ import{t as e}from"./C_Icon2.js";import{t}from"./export-helper.js";import{t as n}from"./html.js";import{i as r,t as i}from"./storage.js";import{Fragment as a,Transition as o,computed as s,createBlock as c,createCommentVNode as l,createElementBlock as u,createElementVNode as d,createTextVNode as f,createVNode as p,defineComponent as m,getCurrentInstance as h,getCurrentScope as g,normalizeClass as _,normalizeStyle as v,onMounted as y,onScopeDispose as ee,openBlock as b,readonly as te,ref as x,renderList as S,resolveComponent as ne,shallowRef as re,toDisplayString as C,unref as w,watch as ie,withCtx as T,withModifiers as E}from"vue";import{NAvatar as D,NButton as ae,NPopover as O,NScrollbar as k,NSkeleton as A,NSpin as j,NTag as M,NTooltip as N}from"naive-ui";const P=99,F=20,oe=6e4,se=`notification_center`,I=3e3,L=5,R=3e4,z=`ping`,B={system:{label:`系统通知`,icon:`mdi:cog-outline`,color:`info`},business:{label:`业务消息`,icon:`mdi:briefcase-outline`,color:`success`},alarm:{label:`告警预警`,icon:`mdi:alert-outline`,color:`warning`}},V=[{key:`all`,label:`全部`},{key:`system`,label:`系统通知`},{key:`business`,label:`业务消息`},{key:`alarm`,label:`告警预警`}],H={low:{label:`低`,type:`default`},normal:{label:`普通`,type:`info`},high:{label:`重要`,type:`warning`},urgent:{label:`紧急`,type:`error`}},ce=[{id:`msg-001`,title:`系统维护通知`,summary:`系统将于今晚 22:00-23:00 进行例行维护升级,届时部分功能可能暂时不可用。`,content:`<p>尊敬的用户:</p><p>为了提升系统性能和稳定性,我们计划于 <strong>2026年2月27日 22:00-23:00</strong> 对系统进行例行维护升级。</p><p>维护期间,以下功能可能暂时不可用:</p><ul><li>报表导出</li><li>数据同步</li><li>定时任务</li></ul><p>请提前保存好未完成的工作,感谢您的理解与支持!</p>`,category:`system`,priority:`high`,status:`unread`,timestamp:new Date(Date.now()-15*6e4).toISOString(),sender:{name:`系统管理员`,avatar:``}},{id:`msg-002`,title:`审批流程待处理`,summary:`张三提交的《Q1 季度预算申请》需要您审批,请尽快处理。`,category:`business`,priority:`urgent`,status:`unread`,timestamp:new Date(Date.now()-30*6e4).toISOString(),sender:{name:`张三`,avatar:``},actionUrl:`/workflow/approval`,actionText:`去审批`},{id:`msg-003`,title:`服务器 CPU 使用率告警`,summary:`生产环境节点 prod-node-03 CPU 使用率持续超过 90%,已触发告警阈值。`,category:`alarm`,priority:`urgent`,status:`unread`,timestamp:new Date(Date.now()-2*6e4).toISOString(),sender:{name:`监控中心`},actionUrl:`/monitor/server`,actionText:`查看详情`},{id:`msg-004`,title:`新版本发布 v1.14.0`,summary:`系统已升级至 v1.14.0,新增通知中心、工作流增强等多项功能。`,category:`system`,priority:`normal`,status:`unread`,timestamp:new Date(Date.now()-3*36e5).toISOString(),sender:{name:`系统管理员`}},{id:`msg-005`,title:`项目交付提醒`,summary:`「Robot Admin 二期」项目交付截止日期为 3月15日,当前进度 78%。`,category:`business`,priority:`high`,status:`read`,timestamp:new Date(Date.now()-8*36e5).toISOString(),sender:{name:`项目管理系统`}},{id:`msg-006`,title:`数据库连接池告警`,summary:`数据库连接池使用率达到 85%,建议关注并适时扩容。`,category:`alarm`,priority:`high`,status:`read`,timestamp:new Date(Date.now()-12*36e5).toISOString(),sender:{name:`监控中心`}},{id:`msg-007`,title:`周报提交提醒`,summary:`本周周报提交截止时间为周五 18:00,请及时提交。`,category:`business`,priority:`normal`,status:`read`,timestamp:new Date(Date.now()-24*36e5).toISOString(),sender:{name:`OA 系统`}},{id:`msg-008`,title:`账号安全提醒`,summary:`检测到您的账号在新设备上登录,如非本人操作请及时修改密码。`,category:`system`,priority:`high`,status:`unread`,timestamp:new Date(Date.now()-45*6e4).toISOString(),sender:{name:`安全中心`}}];function le(e,t){let n=x(`disconnected`),r=null,i=0,a=null,o=null,s=null,c=null,l=0;function u(e){n.value=e,t?.(e)}function d(e){c=e,i=0,f(e)}function f(e){let t=++l;y(),u(`connecting`);try{r=new WebSocket(p(e))}catch{u(`disconnected`),e.autoReconnect!==!1&&h(e);return}let n=r;n.addEventListener(`open`,()=>{t!==l||n!==r||(u(`connected`),i=0,_(e))}),n.addEventListener(`message`,e=>{t!==l||n!==r||m(e.data)}),n.addEventListener(`close`,()=>{t!==l||n!==r||(r=null,v(),u(`disconnected`),e.autoReconnect!==!1&&h(e))}),n.addEventListener(`error`,()=>{})}function p(e){let t=e.getToken?.();if(t){let n=e.url.includes(`?`)?`&`:`?`;return`${e.url}${n}token=${encodeURIComponent(t)}`}return e.url}function m(t){if(typeof t==`string`){if(t===`pong`){s&&clearTimeout(s),s=null;return}try{let n=JSON.parse(t);n&&typeof n==`object`&&[`new_message`,`read_sync`,`count_update`].includes(String(n.type))&&`data`in n&&e(n)}catch{}}}function h(e){if(c!==e||a)return;let t=Math.max(0,Math.trunc(e.maxReconnectAttempts??5));if(i>=t)return;i++,u(`reconnecting`);let n=Math.max(0,e.reconnectInterval??I),r=Math.min(6e4,n*2**(i-1)),o=l;a=setTimeout(()=>{a=null,!(o!==l||c!==e)&&f(e)},r)}function _(e){v();let t=e.heartbeatInterval??R;if(t<=0)return;let n=e.heartbeatMessage??z;o=setInterval(()=>{if(r?.readyState===WebSocket.OPEN&&!s)try{r.send(n);let t=e.heartbeatTimeout??0;if(t>0){let e=r;s=setTimeout(()=>{s=null,e===r&&e.close()},t)}}catch{r.close()}},t)}function v(){s&&clearTimeout(s),s=null,o&&=(clearInterval(o),null)}function y(){v(),a&&=(clearTimeout(a),null),r&&=(r.close(),null)}function b(){c=null,l++,i=0,y(),u(`disconnected`)}function S(){c&&(i=0,f(c))}return g()&&ee(b),{status:te(n),connect:d,disconnect:b,reconnect:S}}const U=[`system`,`business`,`alarm`],ue=()=>({list:[],known:new Map,total:0,unread:0,categories:{},statisticsVersion:0,queryCategory:`all`});function W(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.id==`string`&&t.id.length>0&&typeof t.title==`string`&&typeof t.summary==`string`&&typeof t.timestamp==`string`&&Number.isFinite(Date.parse(t.timestamp))&&U.includes(t.category)&&[`low`,`normal`,`high`,`urgent`].includes(String(t.priority))&&[`read`,`unread`,`archived`].includes(String(t.status))}function G(e){return{...e,...e.sender?{sender:{...e.sender}}:{},...e.extra?{extra:{...e.extra}}:{}}}function de(e){let t={system:0,business:0,alarm:0};for(let n of e)n.status===`unread`&&t[n.category]++;return t}function fe(e){return typeof e==`number`&&Number.isSafeInteger(e)&&e>=0}function pe(e){let t={};if(e&&typeof e==`object`)for(let n of U){let r=e[n];fe(r)&&(t[n]=r)}return t}function me(e,t,n){let r=new Map(e);for(let e of t)n?r.delete(e.id):e.status===`unread`&&r.set(e.id,{...e,status:`read`});return r}function he(e,t,n){if(t.kind!==`delete`&&t.kind!==`clear`)return e.total;let r=e.queryCategory===t.queryCategory?t.unknownTotal:0;return Math.max(0,e.total-n-r)}function ge(e,t){let n=new Set(t.ids),r=[...e.known.values()].filter(e=>n.has(e.id)),i=e.list.filter(e=>n.has(e.id)),a=r.filter(e=>e.status===`unread`),o=t.kind===`delete`||t.kind===`clear`,s=o?e.list.filter(e=>!n.has(e.id)):e.list.map(e=>n.has(e.id)&&e.status===`unread`?{...e,status:`read`}:e),c={...e.categories},l=me(e.known,r,o),u=e.statisticsVersion===t.statisticsVersion;for(let e of U){let n=c[e];if(n===void 0||!u)continue;let r=a.filter(t=>t.category===e).length;c[e]=Math.max(0,n-r-(t.unknownCategories[e]??0))}return{list:s,known:l,total:he(e,t,i.length),unread:u?Math.max(0,e.unread-a.length-t.unknownUnread):e.unread,categories:c,statisticsVersion:e.statisticsVersion,queryCategory:e.queryCategory}}function _e(e,t,n,r){if(!Array.isArray(e?.list)||!e.list.every(W)||!fe(e.total)||!fe(e.unreadCount))throw Error(`消息接口返回的数据或统计无效`);let i=new Map,a=new Map(t.known);if(!n)for(let e of t.list)i.set(e.id,e);for(let t of e.list){let e=G(t);i.set(t.id,e),a.set(t.id,e)}return{list:[...i.values()],known:a,total:e.total,unread:e.unreadCount,categories:pe(e.unreadByCategory),statisticsVersion:t.statisticsVersion,queryCategory:r}}function ve(e,t,n){let r=de(t),i={},a=n?[n]:U;for(let t of a){let n=e.categories[t];n!==void 0&&(i[t]=Math.max(0,n-r[t]))}let o=n?e.categories[n]:e.unread;return{unknownCategories:i,unknownUnread:o===void 0?0:Math.max(0,o-t.filter(e=>e.status===`unread`).length)}}function K(e,t={}){let n=s(()=>e.dataMode??(e.fetchNotifications?`remote`:`demo`)),a=re(ue()),o=re([]),c=s(()=>o.value.reduce(ge,a.value)),l=s(()=>c.value.list),u=x(`all`),d=x(!1),f=x(1),p=x(null),m=x(!1),_=x(`disconnected`),v=x(null),b=s(()=>c.value.unread),te=s(()=>c.value.categories),S=s(()=>u.value===`all`?l.value:l.value.filter(e=>e.category===u.value)),ne=s(()=>n.value===`demo`?S.value.length:c.value.total),C=s(()=>n.value===`remote`&&S.value.length<ne.value),w=s(()=>o.value.length>0),T=s(()=>[...new Set(o.value.flatMap(e=>e.ids))]),E=0,D=0,ae=0,O=0,k=!1,A=!1,j=[],M=null,N=!1,P,F=new Set;function I(t,n){v.value=t instanceof Error?t.message:`消息操作失败,请重试`,e.onError?.(t,n)}function L(){v.value=null}function R(e){let t=new Set([...e.list.map(e=>e.id),...o.value.flatMap(e=>e.ids)]),n=new Map,r=0;for(let[i,a]of[...e.known].reverse()){let e=t.has(i);(e||r<256)&&(n.set(i,a),e||r++)}return{...e,known:new Map([...n].reverse())}}function z(e){let t=de(e);return{list:e,known:new Map(e.map(e=>[e.id,e])),total:e.length,unread:Object.values(t).reduce((e,t)=>e+t,0),categories:t,statisticsVersion:0,queryCategory:`all`}}function B(){let t=i(e.storageKey??se);if(t?.version===2&&Array.isArray(t.messages)){a.value=z(t.messages.filter(W).map(G));return}let n=new Set(Array.isArray(t?.readIds)?t.readIds:[]);a.value=z(ce.map(e=>({...G(e),status:n.has(e.id)?`read`:e.status})))}function V(){n.value===`demo`&&r(e.storageKey??se,{version:2,messages:a.value.list.map(G)})}function H(e){let t=++D;d.value&&j.push({...e,version:t})}function U(e){return n.value===`demo`||u.value===`all`||u.value===e.category}function me(e,t,n=!1){if(e.list.some(e=>e.id===t.id)||!n&&e.known.has(t.id))return e;let r=U(t),i={...e.categories};return t.status===`unread`&&i[t.category]!==void 0&&i[t.category]++,{list:r?[G(t),...e.list]:e.list,known:new Map([...e.known,[t.id,G(t)]]),total:e.total+(r?1:0),unread:e.unread+(t.status===`unread`?1:0),categories:i,statisticsVersion:e.statisticsVersion,queryCategory:e.queryCategory}}function he(e,t){return`operation`in t?ge(e,{...t.operation,statisticsVersion:e.statisticsVersion}):`message`in t?me(e,t.message,!0):{...e,unread:t.counts.unreadCount,categories:{...e.categories,...pe(t.counts.unreadByCategory)},statisticsVersion:e.statisticsVersion+1}}function K(e,t){return!A&&t===O&&e===E}async function ye(t,n){if(!e.fetchNotifications)throw Error(`远程消息模式未配置 fetchNotifications`);return e.fetchNotifications({category:n===`all`?void 0:n,page:t,pageSize:e.pageSize??20})}function be(e,t){let n=e;for(let e of j)e.version>t&&(n=he(n,e));return n}async function xe(e,t){let r=++E,i=D,o=u.value,s=O;d.value=!0,L();try{if(n.value===`demo`){B(),f.value=1;return}let c=await ye(e,o);if(!K(r,s))return;a.value=R(be(_e(c,a.value,t,o),i)),f.value=e}catch(n){throw K(r,s)&&(P=()=>xe(e,t),I(n,`fetch`)),n}finally{K(r,s)&&(d.value=!1,j=[])}}async function q(e=!1){await xe(e?1:f.value,e)}async function Se(){d.value||!C.value||await xe(f.value+1,!1)}function J(e,t,n){let r={id:++ae,kind:e,ids:[...new Set(t)],category:n,unknownUnread:0,unknownCategories:{},unknownTotal:0,statisticsVersion:a.value.statisticsVersion,queryCategory:u.value};if(e!==`read-all`&&e!==`clear`)return r;let i=[...a.value.known.values()].filter(e=>!n||e.category===n);Object.assign(r,ve(a.value,i,n));let o=!n||u.value===n;return e===`clear`&&o&&(r.unknownTotal=Math.max(0,a.value.total-a.value.list.filter(e=>!n||e.category===n).length)),r}async function Y(e,t,r){if(L(),n.value===`remote`&&!t){let n=Error(`远程消息模式未配置 `+r+` 接口`);throw P=()=>Y(e,t,r),I(n,r),n}let i=O;o.value=[...o.value,e];try{if(n.value===`remote`&&await t(),A||i!==O){let e=Error(`消息作用域已失效`);throw e.name=`AbortError`,e}a.value=ge(a.value,e),H({operation:e}),V()}catch(n){throw!A&&i===O&&(P=()=>Y(e,t,r),I(n,r)),n}finally{i===O&&(o.value=o.value.filter(t=>t.id!==e.id),a.value=R(a.value))}}async function X(t){await Y(J(`read`,t),e.markAsRead?()=>e.markAsRead(t):void 0,`mark-as-read`)}async function Ce(t){await Y(J(`read-all`,[...a.value.known.values()].filter(e=>!t||e.category===t).map(e=>e.id),t),e.markAllRead?()=>e.markAllRead(t):void 0,`mark-all-as-read`)}async function we(t){await Y(J(`delete`,t),e.deleteNotification?()=>e.deleteNotification(t):void 0,`delete`),p.value&&t.includes(p.value.id)&&Q()}async function Te(t){await Y(J(`clear`,[...a.value.known.values()].filter(e=>!t||e.category===t).map(e=>e.id),t),e.clearNotifications?()=>e.clearNotifications(t):void 0,`clear`),p.value&&(!t||p.value.category===t)&&Q()}let Z=new Set;function Ee(e){if(!W(e))return;let n=e;Z.has(n.id)||a.value.known.has(n.id)||(Z.add(n.id),Z.size>2e3&&Z.delete(Z.values().next().value),a.value=me(a.value,n),H({message:G(n)}),V(),t.onNewMessage?.(n),Pe(n))}function De(e){if(!Array.isArray(e))return;let t=J(`read`,e.filter(W).map(e=>e.id));a.value=ge(a.value,t),H({operation:t}),V()}function Oe(e){if(e&&typeof e==`object`&&`unreadCount`in e&&fe(e.unreadCount)){let t=e;a.value=he(a.value,{version:0,counts:t}),H({counts:t})}}function ke(e){if(!A)switch(e.type){case`new_message`:Ee(e.data);break;case`read_sync`:De(e.data);break;case`count_update`:Oe(e.data);break}}function Ae(e){_.value=e,t.onWSStatusChange?.(e),e===`connected`&&(N&&n.value===`remote`&&q(!0).catch(()=>void 0),N=!0)}let je=le(ke,Ae);function Me(t=e.wsConfig){t&&je.connect(t)}function Ne(){je.disconnect()}function Pe(t){if(!e.desktopNotification||typeof window>`u`||!(`Notification`in window)||Notification.permission!==`granted`)return;let n=new Notification(t.title,{body:t.summary,icon:t.sender?.avatar,tag:t.id});n.addEventListener(`click`,()=>{window.focus(),Ie(t),n.close()});let r=setTimeout(()=>{n.close(),F.delete(r)},5e3);F.add(r)}async function Fe(){return typeof window>`u`||!(`Notification`in window)?`unsupported`:Notification.requestPermission()}function Ie(e){p.value=e,e.status===`unread`&&X([e.id]).catch(()=>void 0)}function Q(){p.value=null}function Le(e){u.value!==e&&(u.value=e,Q(),n.value===`remote`&&(a.value={...a.value,list:[],total:0,queryCategory:e},f.value=1,q(!0).catch(()=>void 0)))}function $(){if(k)return;k=!0,A=!1,q(!0).catch(()=>void 0);let t=e.pollingInterval??oe;n.value===`remote`&&t>0&&(M=setInterval(()=>{d.value||q(!0).catch(()=>void 0)},t)),Me()}function Re(){k=!1,A=!0,O++,E++,d.value=!1,o.value=[],j=[],P=void 0,Z.clear(),N=!1,M&&clearInterval(M),M=null;for(let e of F)clearTimeout(e);F.clear(),Ne()}async function ze(){P?await P():await q(!0)}return g()&&ee(Re),e.autoStart!==!1&&(h()?y($):$()),ie(l,e=>{let t=p.value?.id;t&&(p.value=e.find(e=>e.id===t)??null)}),ie(()=>[n.value,e.storageKey],()=>{let e=k;Re(),a.value=ue(),u.value=`all`,p.value=null,m.value=!1,v.value=null,e&&$()}),{messages:l,activeCategory:u,loading:d,total:ne,page:f,selectedMessage:p,popoverVisible:m,wsStatus:_,unreadCount:b,unreadByCategory:te,filteredMessages:S,hasMore:C,error:v,busy:w,pendingIds:T,fetchMessages:q,loadMore:Se,markAsRead:X,markAllAsRead:Ce,deleteMessages:we,clearMessages:Te,selectMessage:Ie,clearSelection:Q,switchCategory:Le,clearError:L,retry:ze,requestDesktopPermission:Fe,connectWS:Me,disconnectWS:Ne,initialize:$,dispose:Re}}const ye={class:`notification-badge`},be=[`aria-label`],xe={key:0,class:`notification-badge__count`},q={key:0,class:`notification-badge__pulse`};var Se=t(m({__name:`NotificationBadge`,props:{count:{default:0},maxCount:{default:99},hasUrgent:{type:Boolean,default:!1}},emits:[`click`],setup(t){let n=t,r=s(()=>n.count>n.maxCount?`${n.maxCount}+`:String(n.count));return(n,i)=>{let a=N;return b(),u(`div`,ye,[p(a,{trigger:`hover`,placement:`bottom`},{trigger:T(()=>[d(`button`,{type:`button`,class:`notification-badge__trigger`,"aria-label":`消息通知${t.count>0?`(${t.count} 条未读)`:``}`,onClick:i[0]||=e=>n.$emit(`click`)},[p(e,{name:`mdi:bell-outline`,size:18,class:`notification-badge__icon`}),l(` 未读角标 `),p(o,{name:`badge-bounce`},{default:T(()=>[t.count>0?(b(),u(`span`,xe,C(r.value),1)):l(`v-if`,!0)]),_:1}),l(` 脉冲动画(有紧急消息时) `),t.hasUrgent?(b(),u(`span`,q)):l(`v-if`,!0)],8,be)]),default:T(()=>[f(` 消息通知`+C(t.count>0?`(${t.count} 条未读)`:``),1)]),_:1})])}}}),[[`__scopeId`,`data-v-51516250`]]);const J=6e4,Y=36e5,X=864e5,Ce=7*X,we=30*X;365*X;let Te=null;function Z(){return Te||=Ee(),Te}function Ee(){function e(e){let r=new Date(e),i=Date.now()-r.getTime();if(i<0||i<J)return`刚刚`;if(i<Y)return`${Math.floor(i/J)}分钟前`;if(i<X)return`${Math.floor(i/Y)}小时前`;let a=new Date;return a.setHours(0,0,0,0),r>=new Date(a.getTime()-X)&&r<a?`昨天 ${n(r.getHours())}:${n(r.getMinutes())}`:i<Ce?`${Math.floor(i/X)}天前`:i<we?`${Math.floor(i/Ce)}周前`:i<31536e6?`${Math.floor(i/we)}个月前`:t(r)}function t(e){return`${e.getFullYear()}-${n(e.getMonth()+1)}-${n(e.getDate())} ${n(e.getHours())}:${n(e.getMinutes())}`}function n(e){return e<10?`0${e}`:String(e)}return{formatRelativeTime:e,formatFullDate:t}}const De={class:`notification-item__indicator`},Oe={class:`notification-item__avatar`},ke={class:`notification-item__body`},Ae={class:`notification-item__header`},je={class:`notification-item__title`},Me={class:`notification-item__summary`},Ne={class:`notification-item__meta`},Pe={class:`notification-item__time`},Fe={key:0,class:`notification-item__sender`},Ie=[`disabled`],Q=[`disabled`];var Le=t(m({__name:`NotificationItem`,props:{message:{},busy:{type:Boolean}},emits:[`click`,`read`,`delete`],setup(t){let n=t,{formatRelativeTime:r}=Z(),i=s(()=>B[n.message.category]?.icon??`mdi:bell-outline`),a=s(()=>H[n.message.priority]??H.normal),o=s(()=>r(n.message.timestamp));return(n,r)=>{let s=D,m=M,h=N;return b(),u(`div`,{class:_([`notification-item`,{"notification-item--unread":t.message.status===`unread`,"notification-item--urgent":t.message.priority===`urgent`}]),onClick:r[3]||=e=>n.$emit(`click`,t.message)},[l(` 未读指示点 `),d(`div`,De,[t.message.status===`unread`?(b(),u(`span`,{key:0,class:_([`notification-item__dot`,`notification-item__dot--${t.message.priority}`])},null,2)):l(`v-if`,!0)]),l(` 头像 `),d(`div`,Oe,[t.message.sender?.avatar?(b(),c(s,{key:0,src:t.message.sender.avatar,size:36,round:``},null,8,[`src`])):(b(),u(`div`,{key:1,class:_([`notification-item__avatar-placeholder`,`notification-item__avatar-placeholder--${t.message.category}`])},[p(e,{name:i.value,size:16},null,8,[`name`])],2))]),l(` 内容 `),d(`div`,ke,[d(`div`,Ae,[d(`span`,je,C(t.message.title),1),t.message.priority===`urgent`||t.message.priority===`high`?(b(),c(m,{key:0,type:a.value.type,size:`tiny`,bordered:!1,round:``},{default:T(()=>[f(C(a.value.label),1)]),_:1},8,[`type`])):l(`v-if`,!0)]),d(`div`,Me,C(t.message.summary),1),d(`div`,Ne,[d(`span`,Pe,C(o.value),1),t.message.sender?.name?(b(),u(`span`,Fe,C(t.message.sender.name),1)):l(`v-if`,!0)])]),l(` 操作区 `),d(`div`,{class:`notification-item__actions`,onClick:r[2]||=E(()=>{},[`stop`])},[t.message.status===`unread`?(b(),c(h,{key:0,trigger:`hover`,placement:`top`},{trigger:T(()=>[d(`button`,{class:`notification-item__action`,type:`button`,disabled:t.busy,"aria-label":`标记已读`,onClick:r[0]||=e=>n.$emit(`read`,t.message.id)},[p(e,{name:`mdi:check`,size:16})],8,Ie)]),default:T(()=>[r[4]||=f(` 标记已读 `,-1)]),_:1})):l(`v-if`,!0),p(h,{trigger:`hover`,placement:`top`},{trigger:T(()=>[d(`button`,{class:`notification-item__action`,type:`button`,disabled:t.busy,"aria-label":`删除消息`,onClick:r[1]||=e=>n.$emit(`delete`,t.message.id)},[p(e,{name:`mdi:delete-outline`,size:16})],8,Q)]),default:T(()=>[r[5]||=f(` 删除 `,-1)]),_:1})])],2)}}}),[[`__scopeId`,`data-v-8a4522f3`]]);const $={class:`notification-list`},Re={class:`notification-list__tabs`},ze=[`aria-pressed`,`onClick`],Be={key:0,class:`notification-list__tab-count`},Ve={key:0,class:`notification-list__toolbar`},He={class:`notification-list__skeleton-text`},Ue={class:`notification-list__items`},We=[`disabled`],Ge={class:`notification-list__empty`};var Ke=t(m({__name:`NotificationList`,props:{messages:{},activeCategory:{},unreadByCategory:{},busy:{type:Boolean,default:!1},pendingIds:{default:()=>[]},unreadCount:{},loading:{type:Boolean},hasMore:{type:Boolean},scrollHeight:{default:420}},emits:[`switchCategory`,`itemClick`,`read`,`delete`,`markAllRead`,`clear`,`loadMore`],setup(t){let n=t,r=s(()=>n.activeCategory===`all`?n.unreadCount:n.unreadByCategory[n.activeCategory]);function i(e){return e===`all`?n.unreadCount:n.unreadByCategory[e]??0}return(n,o)=>{let s=ae,m=A,h=j,g=k;return b(),u(`div`,$,[l(` 分类 Tab `),d(`div`,Re,[(b(!0),u(a,null,S(w(V),e=>(b(),u(`button`,{key:e.key,class:_([`notification-list__tab`,{"notification-list__tab--active":t.activeCategory===e.key}]),type:`button`,"aria-pressed":t.activeCategory===e.key,onClick:t=>n.$emit(`switchCategory`,e.key)},[d(`span`,null,C(e.label),1),i(e.key)>0?(b(),u(`span`,Be,C(i(e.key)),1)):l(`v-if`,!0)],10,ze))),128))]),l(` 操作栏 `),t.messages.length>0?(b(),u(`div`,Ve,[p(s,{text:``,size:`tiny`,disabled:t.busy||r.value!==void 0&&r.value===0,loading:t.busy,onClick:o[0]||=e=>n.$emit(`markAllRead`)},{icon:T(()=>[p(e,{name:`mdi:check-all`,size:14})]),default:T(()=>[o[6]||=f(` 全部已读 `,-1)]),_:1},8,[`disabled`,`loading`]),p(s,{text:``,size:`tiny`,disabled:t.busy,onClick:o[1]||=e=>n.$emit(`clear`)},{icon:T(()=>[p(e,{name:`mdi:delete-sweep-outline`,size:14})]),default:T(()=>[o[7]||=f(` 清空 `,-1)]),_:1},8,[`disabled`])])):l(`v-if`,!0),l(` 消息列表 `),p(g,{class:`notification-list__scroll`,style:v({maxHeight:`${t.scrollHeight}px`})},{default:T(()=>[t.loading&&t.messages.length===0?(b(),u(a,{key:0},[l(` 骨架屏 `),(b(),u(a,null,S(4,e=>d(`div`,{key:e,class:`notification-list__skeleton`},[p(m,{circle:``,width:36,height:36}),d(`div`,He,[p(m,{text:``,width:`60%`,height:14}),p(m,{text:``,width:`90%`,height:12}),p(m,{text:``,width:`40%`,height:10})])])),64))],64)):t.messages.length>0?(b(),u(a,{key:1},[d(`div`,Ue,[(b(!0),u(a,null,S(t.messages,e=>(b(),c(Le,{key:e.id,message:e,busy:t.busy||t.pendingIds.includes(e.id),onClick:o[2]||=e=>n.$emit(`itemClick`,e),onRead:o[3]||=e=>n.$emit(`read`,e),onDelete:o[4]||=e=>n.$emit(`delete`,e)},null,8,[`message`,`busy`]))),128))]),l(` 加载更多 `),t.hasMore?(b(),u(`button`,{key:0,class:`notification-list__load-more`,type:`button`,disabled:t.loading,onClick:o[5]||=e=>n.$emit(`loadMore`)},[t.loading?(b(),c(h,{key:0,size:14})):l(`v-if`,!0),d(`span`,null,C(t.loading?`加载中...`:`加载更多`),1)],8,We)):l(`v-if`,!0)],64)):(b(),u(a,{key:2},[l(` 空状态 `),d(`div`,Ge,[p(e,{name:`mdi:bell-off-outline`,size:48,class:`notification-list__empty-icon`}),o[8]||=d(`span`,{class:`notification-list__empty-text`},`暂无消息`,-1)])],2112))]),_:1},8,[`style`])])}}}),[[`__scopeId`,`data-v-63a2d867`]]);function qe(e){return e.includes(`\\`)||e.startsWith(`//`)||Array.from(e).some(e=>e.charCodeAt(0)<32)}function Je(e){let t=e?.trim();if(!t||qe(t))return null;if(/^https?:\/\//i.test(t))try{let e=new URL(t);return e.protocol!==`http:`&&e.protocol!==`https:`?null:{kind:`external`,url:e.href}}catch{return null}return/^[a-z][a-z\d+.-]*:/i.test(t)?null:{kind:`internal`,url:t}}const Ye={class:`notification-detail`},Xe={class:`notification-detail__back`},Ze={class:`notification-detail__header`},Qe={class:`notification-detail__title`},$e={class:`notification-detail__meta`},et={class:`notification-detail__time`},tt={key:0,class:`notification-detail__sender`},nt=[`innerHTML`],rt={key:1,class:`notification-detail__body`},it={key:0,class:`notification-detail__footer`};var at=t(m({__name:`NotificationDetail`,props:{message:{},scrollHeight:{default:320}},emits:[`back`,`action`,`navigate`],setup(t,{emit:r}){let i=t,a=r,{formatRelativeTime:o}=Z(),m=s(()=>B[i.message.category]??B.system),h=s(()=>H[i.message.priority]??H.normal),g=s(()=>o(i.message.timestamp)),_=s(()=>n(i.message.content||``));function y(){let e=Je(i.message.actionUrl);e&&(a(`action`,e.url),e.kind===`external`?window.open(e.url,`_blank`,`noopener,noreferrer`):a(`navigate`,e.url))}return(n,r)=>{let i=ae,a=M,o=D,s=k;return b(),u(`div`,Ye,[l(` 返回栏 `),d(`div`,Xe,[p(i,{text:``,size:`small`,onClick:r[0]||=e=>n.$emit(`back`)},{icon:T(()=>[p(e,{name:`mdi:arrow-left`,size:16})]),default:T(()=>[r[1]||=f(` 返回列表 `,-1)]),_:1})]),l(` 消息头部 `),d(`div`,Ze,[d(`h3`,Qe,C(t.message.title),1),d(`div`,$e,[p(a,{type:m.value.color,size:`tiny`,bordered:!1,round:``},{icon:T(()=>[p(e,{name:m.value.icon,size:12},null,8,[`name`])]),default:T(()=>[f(` `+C(m.value.label),1)]),_:1},8,[`type`]),t.message.priority===`urgent`||t.message.priority===`high`?(b(),c(a,{key:0,type:h.value.type,size:`tiny`,bordered:!1,round:``},{default:T(()=>[f(C(h.value.label),1)]),_:1},8,[`type`])):l(`v-if`,!0),d(`span`,et,C(g.value),1)]),t.message.sender?(b(),u(`div`,tt,[t.message.sender.avatar?(b(),c(o,{key:0,src:t.message.sender.avatar,size:20,round:``},null,8,[`src`])):l(`v-if`,!0),d(`span`,null,C(t.message.sender.name),1)])):l(`v-if`,!0)]),l(` 消息内容 `),p(s,{class:`notification-detail__content`,style:v({maxHeight:`${t.scrollHeight}px`})},{default:T(()=>[t.message.content?(b(),u(`div`,{key:0,class:`notification-detail__body`,innerHTML:_.value},null,8,nt)):(b(),u(`div`,rt,C(t.message.summary),1))]),_:1},8,[`style`]),l(` 操作区 `),t.message.actionUrl?(b(),u(`div`,it,[p(i,{type:`primary`,size:`small`,onClick:y},{icon:T(()=>[p(e,{name:`mdi:arrow-right`,size:16})]),default:T(()=>[f(C(t.message.actionText||`查看详情`)+` `,1)]),_:1})])):l(`v-if`,!0)])}}}),[[`__scopeId`,`data-v-8e02b6cd`]]);const ot={class:`c-notification-center`},st={class:`c-notification-center__panel`},ct={class:`c-notification-center__header`},lt={class:`c-notification-center__header-extra`},ut={key:0,class:`c-notification-center__error`,role:`alert`},dt={class:`c-notification-center__footer`};var ft=t(m({name:`C_NotificationCenter`,__name:`index`,props:{dataMode:{},controller:{},autoStart:{type:Boolean,default:!0},fetchNotifications:{},markAsRead:{},markAllRead:{},deleteNotification:{},clearNotifications:{},wsConfig:{},desktopNotification:{type:Boolean,default:!1},maxBadgeCount:{default:99},pollingInterval:{default:6e4},pageSize:{default:20},storageKey:{default:`notification_center`},onError:{}},emits:[`itemClick`,`read`,`allRead`,`delete`,`unreadChange`,`wsStatusChange`,`newMessage`,`navigate`,`viewAll`],setup(e,{expose:t,emit:n}){let r=e,i=n,a=r.controller??K(r,{onNewMessage:e=>i(`newMessage`,e),onWSStatusChange:e=>i(`wsStatusChange`,e)}),m=s(()=>a.messages.value.some(e=>e.status===`unread`&&e.priority===`urgent`)),h=s(()=>({connected:`已连接`,connecting:`连接中...`,disconnected:`未连接`,reconnecting:`重连中...`})[a.wsStatus.value]??`未知`);ie(()=>a.unreadCount.value,e=>{i(`unreadChange`,e)});function g(){a.popoverVisible.value=!a.popoverVisible.value}async function v(){try{a.retry?await a.retry():await a.fetchMessages(!0)}catch{}}async function y(){try{await a.loadMore()}catch{}}function ee(){a.popoverVisible.value=!1,i(`viewAll`)}function te(e){a.selectMessage(e),i(`itemClick`,e)}async function x(e){try{await a.markAsRead([e]),i(`read`,[e])}catch{}}async function S(e){try{await a.deleteMessages([e]),i(`delete`,[e])}catch{}}async function ne(){let e=a.activeCategory.value===`all`?void 0:a.activeCategory.value;try{await a.markAllAsRead(e),i(`allRead`,e)}catch{}}async function re(){let e=a.activeCategory.value===`all`?void 0:a.activeCategory.value;try{await a.clearMessages(e)}catch{}}function E(){a.popoverVisible.value=!1}function D(){a.clearSelection()}return t({refresh:()=>a.fetchMessages(!0),connectWS:()=>{r.wsConfig&&a.connectWS(r.wsConfig)},disconnectWS:a.disconnectWS,getUnreadCount:()=>a.unreadCount.value,getMessages:()=>a.messages.value.map(e=>({...e})),markRead:e=>a.markAsRead(e),markAllAsRead:e=>a.markAllAsRead(e),requestDesktopPermission:a.requestDesktopPermission}),(e,t)=>{let n=N,s=ae,ie=O;return b(),u(`div`,ot,[p(ie,{show:w(a).popoverVisible.value,"onUpdate:show":t[1]||=e=>w(a).popoverVisible.value=e,width:420,trigger:`manual`,placement:`bottom-end`,"show-arrow":!1,"content-class":`c-notification-center__popover`,onAfterLeave:D},{trigger:T(()=>[p(Se,{count:w(a).unreadCount.value,"max-count":r.maxBadgeCount,"has-urgent":m.value,onClick:g},null,8,[`count`,`max-count`,`has-urgent`])]),default:T(()=>[d(`div`,st,[l(` 头部标题 `),d(`div`,ct,[t[2]||=d(`span`,{class:`c-notification-center__title`},`消息中心`,-1),d(`div`,lt,[l(` WebSocket 连接状态 `),r.wsConfig||w(a).wsStatus.value!==`disconnected`?(b(),c(n,{key:0,trigger:`hover`,placement:`top`},{trigger:T(()=>[d(`span`,{class:_([`c-notification-center__ws-dot`,`c-notification-center__ws-dot--${w(a).wsStatus.value}`])},null,2)]),default:T(()=>[f(` `+C(h.value),1)]),_:1})):l(`v-if`,!0)])]),w(a).error.value?(b(),u(`div`,ut,[d(`span`,null,C(w(a).error.value),1),p(s,{size:`tiny`,loading:w(a).loading.value,onClick:v},{default:T(()=>[...t[3]||=[f(`重试`,-1)]]),_:1},8,[`loading`])])):l(`v-if`,!0),l(` 列表 / 详情切换 `),p(o,{name:`slide-fade`,mode:`out-in`},{default:T(()=>[w(a).selectedMessage.value?(b(),c(at,{key:w(a).selectedMessage.value.id,message:w(a).selectedMessage.value,onBack:w(a).clearSelection,onAction:E,onNavigate:t[0]||=e=>i(`navigate`,e)},null,8,[`message`,`onBack`])):(b(),c(Ke,{key:1,messages:w(a).filteredMessages.value,"active-category":w(a).activeCategory.value,"unread-by-category":w(a).unreadByCategory.value,"unread-count":w(a).unreadCount.value,loading:w(a).loading.value,"has-more":w(a).hasMore.value,busy:w(a).busy.value,"pending-ids":w(a).pendingIds.value,onSwitchCategory:w(a).switchCategory,onItemClick:te,onRead:x,onDelete:S,onMarkAllRead:ne,onClear:re,onLoadMore:y},null,8,[`messages`,`active-category`,`unread-by-category`,`unread-count`,`loading`,`has-more`,`busy`,`pending-ids`,`onSwitchCategory`]))]),_:1}),d(`div`,dt,[p(s,{text:``,type:`primary`,size:`small`,onClick:ee},{default:T(()=>[...t[4]||=[f(`查看全部消息`,-1)]]),_:1})])])]),_:1},8,[`show`])])}}}),[[`__scopeId`,`data-v-21f127ad`]]);export{B as a,F as c,R as d,z as f,H as g,ce as h,le as i,oe as l,I as m,Z as n,V as o,L as p,K as r,P as s,ft as t,se as u};
@@ -117,8 +117,8 @@ declare const __VLS_export: vue.DefineComponent<CronProps, CronExpose, {}, {}, {
117
117
  "onValidation-change"?: ((result: CronValidation) => any) | undefined;
118
118
  }>, {
119
119
  disabled: boolean;
120
- showTemplates: boolean;
121
120
  showPreview: boolean;
121
+ showTemplates: boolean;
122
122
  showSecond: boolean;
123
123
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
124
124
  declare const _default: typeof __VLS_export;
@@ -117,8 +117,8 @@ declare const __VLS_export: vue.DefineComponent<CronProps, CronExpose, {}, {}, {
117
117
  "onValidation-change"?: ((result: CronValidation) => any) | undefined;
118
118
  }>, {
119
119
  disabled: boolean;
120
- showTemplates: boolean;
121
120
  showPreview: boolean;
121
+ showTemplates: boolean;
122
122
  showSecond: boolean;
123
123
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
124
124
  declare const _default: typeof __VLS_export;
@@ -1,6 +1,11 @@
1
1
  import * as vue from "vue";
2
+ import { Ref } from "vue";
2
3
 
3
4
  //#region src/components/C_NotificationCenter/types.d.ts
5
+ /** 远程模式缺少接口时明确报错,不回退演示数据。 */
6
+ type NotificationDataMode = 'demo' | 'remote';
7
+ /** 未返回的分类计数保持未知,避免把当前页误当成完整统计。 */
8
+ type NotificationUnreadByCategory = Partial<Record<NotificationCategory, number>>;
4
9
  /** 消息类别 */
5
10
  type NotificationCategory = 'system' | 'business' | 'alarm';
6
11
  /** 消息优先级 */
@@ -42,16 +47,19 @@ interface NotificationSender {
42
47
  avatar?: string;
43
48
  }
44
49
  /** 拉取消息列表函数 */
50
+ interface FetchNotificationsResult {
51
+ list: NotificationMessage[];
52
+ total: number;
53
+ /** 全局未读总数,与当前分类和页码无关。 */
54
+ unreadCount: number;
55
+ unreadByCategory?: NotificationUnreadByCategory;
56
+ }
45
57
  type FetchNotificationsFn = (params: {
46
58
  category?: NotificationCategory;
47
59
  status?: NotificationStatus;
48
60
  page?: number;
49
61
  pageSize?: number;
50
- }) => Promise<{
51
- list: NotificationMessage[];
52
- total: number;
53
- unreadCount: number;
54
- }>;
62
+ }) => Promise<FetchNotificationsResult>;
55
63
  /** 标记已读函数 */
56
64
  type MarkAsReadFn = (ids: string[]) => Promise<void>;
57
65
  /** 标记全部已读函数 */
@@ -74,6 +82,8 @@ interface NotificationWSConfig {
74
82
  heartbeatInterval?: number;
75
83
  /** 心跳消息内容 */
76
84
  heartbeatMessage?: string;
85
+ /** 等待 pong 的超时(ms);0 保持仅发送心跳的兼容行为。 */
86
+ heartbeatTimeout?: number;
77
87
  /** 鉴权 token 获取函数 */
78
88
  getToken?: () => string | undefined;
79
89
  }
@@ -86,10 +96,53 @@ interface WSNotificationPayload {
86
96
  /** 推送的消息数据 */
87
97
  data: NotificationMessage | NotificationMessage[] | {
88
98
  unreadCount: number;
99
+ unreadByCategory?: NotificationUnreadByCategory;
89
100
  };
90
101
  }
102
+ /**
103
+ * 可共享的通知数据源。组件只消费状态与操作,不拥有外部控制器的生命周期。
104
+ * Ref 支持 computed 投影,便于应用将顶部消息与完整消息中心接到同一 Store。
105
+ */
106
+ interface NotificationCenterController {
107
+ messages: Readonly<Ref<NotificationMessage[]>>;
108
+ activeCategory: Ref<NotificationCategory | 'all'>;
109
+ loading: Readonly<Ref<boolean>>;
110
+ total: Readonly<Ref<number>>;
111
+ page: Readonly<Ref<number>>;
112
+ selectedMessage: Ref<NotificationMessage | null>;
113
+ popoverVisible: Ref<boolean>;
114
+ wsStatus: Readonly<Ref<WSConnectionStatus>>;
115
+ unreadCount: Readonly<Ref<number>>;
116
+ unreadByCategory: Readonly<Ref<NotificationUnreadByCategory>>;
117
+ filteredMessages: Readonly<Ref<NotificationMessage[]>>;
118
+ hasMore: Readonly<Ref<boolean>>;
119
+ error: Readonly<Ref<string | null>>;
120
+ busy: Readonly<Ref<boolean>>;
121
+ pendingIds: Readonly<Ref<readonly string[]>>;
122
+ fetchMessages: (reset?: boolean) => Promise<void>;
123
+ loadMore: () => Promise<void>;
124
+ markAsRead: (ids: string[]) => Promise<void>;
125
+ markAllAsRead: (category?: NotificationCategory) => Promise<void>;
126
+ deleteMessages: (ids: string[]) => Promise<void>;
127
+ clearMessages: (category?: NotificationCategory) => Promise<void>;
128
+ selectMessage: (message: NotificationMessage) => void;
129
+ clearSelection: () => void;
130
+ switchCategory: (category: NotificationCategory | 'all') => void;
131
+ clearError: () => void;
132
+ /** 重试最近失败的操作;未实现时组件退回刷新列表。 */
133
+ retry?: () => Promise<void>;
134
+ connectWS: (config?: NotificationWSConfig) => void;
135
+ disconnectWS: () => void;
136
+ requestDesktopPermission: () => Promise<NotificationPermission | 'unsupported'>;
137
+ }
91
138
  /** 组件 Props */
92
139
  interface NotificationCenterProps {
140
+ /** 不传时根据 fetchNotifications 推断,保留无接口演示兼容性。 */
141
+ dataMode?: NotificationDataMode;
142
+ /** 外部共享控制器;传入后不再初始化本地数据、轮询或 WebSocket。 */
143
+ controller?: NotificationCenterController;
144
+ /** 独立 core 是否自动初始化,默认 true。 */
145
+ autoStart?: boolean;
93
146
  /** 拉取消息列表 */
94
147
  fetchNotifications?: FetchNotificationsFn;
95
148
  /** 标记已读 */
@@ -117,6 +170,7 @@ interface NotificationCenterProps {
117
170
  }
118
171
  /** 组件 Emits */
119
172
  interface NotificationCenterEmits {
173
+ viewAll: [];
120
174
  /** 点击消息 */
121
175
  itemClick: [message: NotificationMessage];
122
176
  /** 消息已读 */
@@ -154,29 +208,32 @@ interface NotificationCenterExpose {
154
208
  //#endregion
155
209
  //#region src/components/C_NotificationCenter/index.vue.d.ts
156
210
  declare const __VLS_export: vue.DefineComponent<NotificationCenterProps, NotificationCenterExpose, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
157
- read: (ids: string[]) => any;
158
211
  delete: (ids: string[]) => any;
159
212
  itemClick: (message: NotificationMessage) => any;
213
+ read: (ids: string[]) => any;
160
214
  allRead: (category?: NotificationCategory | undefined) => any;
161
215
  unreadChange: (count: number) => any;
162
216
  wsStatusChange: (status: WSConnectionStatus) => any;
163
217
  newMessage: (message: NotificationMessage) => any;
164
218
  navigate: (url: string) => any;
219
+ viewAll: () => any;
165
220
  }, string, vue.PublicProps, Readonly<NotificationCenterProps> & Readonly<{
166
- onRead?: ((ids: string[]) => any) | undefined;
167
221
  onDelete?: ((ids: string[]) => any) | undefined;
168
222
  onItemClick?: ((message: NotificationMessage) => any) | undefined;
223
+ onRead?: ((ids: string[]) => any) | undefined;
169
224
  onAllRead?: ((category?: NotificationCategory | undefined) => any) | undefined;
170
225
  onUnreadChange?: ((count: number) => any) | undefined;
171
226
  onWsStatusChange?: ((status: WSConnectionStatus) => any) | undefined;
172
227
  onNewMessage?: ((message: NotificationMessage) => any) | undefined;
173
228
  onNavigate?: ((url: string) => any) | undefined;
229
+ onViewAll?: (() => any) | undefined;
174
230
  }>, {
231
+ pageSize: number;
232
+ storageKey: string;
233
+ autoStart: boolean;
175
234
  desktopNotification: boolean;
176
235
  maxBadgeCount: number;
177
236
  pollingInterval: number;
178
- pageSize: number;
179
- storageKey: string;
180
237
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
181
238
  declare const _default: typeof __VLS_export;
182
239
  //#endregion
@@ -185,117 +242,14 @@ interface NotificationCoreEvents {
185
242
  onNewMessage?: (message: NotificationMessage) => void;
186
243
  onWSStatusChange?: (status: WSConnectionStatus) => void;
187
244
  }
245
+ /** 验证查询与推送中的消息边界,拒绝畸形事件。 */
188
246
  /**
189
- * 通知中心核心状态管理
190
- *
191
- * 统一管理消息列表、未读数、分类过滤、已读标记、
192
- * API 交互、WebSocket 桥接、轮询调度和本地缓存。
247
+ * 独立组件与应用 Store 共用的无后端依赖控制器。
248
+ * 未指定模式时兼容旧接入:有查询接口为 remote,否则为 demo。
193
249
  */
194
- declare function useNotificationCore(props: NotificationCenterProps, events?: NotificationCoreEvents): {
195
- messages: vue.Ref<{
196
- id: string;
197
- title: string;
198
- summary: string;
199
- content?: string | undefined;
200
- category: NotificationCategory;
201
- priority: NotificationPriority;
202
- status: NotificationStatus;
203
- timestamp: string;
204
- sender?: {
205
- name: string;
206
- avatar?: string | undefined;
207
- } | undefined;
208
- actionUrl?: string | undefined;
209
- actionText?: string | undefined;
210
- extra?: Record<string, unknown> | undefined;
211
- }[], NotificationMessage[] | {
212
- id: string;
213
- title: string;
214
- summary: string;
215
- content?: string | undefined;
216
- category: NotificationCategory;
217
- priority: NotificationPriority;
218
- status: NotificationStatus;
219
- timestamp: string;
220
- sender?: {
221
- name: string;
222
- avatar?: string | undefined;
223
- } | undefined;
224
- actionUrl?: string | undefined;
225
- actionText?: string | undefined;
226
- extra?: Record<string, unknown> | undefined;
227
- }[]>;
228
- activeCategory: vue.Ref<NotificationCategory | "all", NotificationCategory | "all">;
229
- loading: vue.Ref<boolean, boolean>;
230
- total: vue.Ref<number, number>;
231
- page: vue.Ref<number, number>;
232
- selectedMessage: vue.Ref<{
233
- id: string;
234
- title: string;
235
- summary: string;
236
- content?: string | undefined;
237
- category: NotificationCategory;
238
- priority: NotificationPriority;
239
- status: NotificationStatus;
240
- timestamp: string;
241
- sender?: {
242
- name: string;
243
- avatar?: string | undefined;
244
- } | undefined;
245
- actionUrl?: string | undefined;
246
- actionText?: string | undefined;
247
- extra?: Record<string, unknown> | undefined;
248
- } | null, NotificationMessage | {
249
- id: string;
250
- title: string;
251
- summary: string;
252
- content?: string | undefined;
253
- category: NotificationCategory;
254
- priority: NotificationPriority;
255
- status: NotificationStatus;
256
- timestamp: string;
257
- sender?: {
258
- name: string;
259
- avatar?: string | undefined;
260
- } | undefined;
261
- actionUrl?: string | undefined;
262
- actionText?: string | undefined;
263
- extra?: Record<string, unknown> | undefined;
264
- } | null>;
265
- popoverVisible: vue.Ref<boolean, boolean>;
266
- wsStatus: vue.Ref<WSConnectionStatus, WSConnectionStatus>;
267
- unreadCount: vue.ComputedRef<number>;
268
- unreadByCategory: vue.ComputedRef<Record<string, number>>;
269
- filteredMessages: vue.ComputedRef<{
270
- id: string;
271
- title: string;
272
- summary: string;
273
- content?: string | undefined;
274
- category: NotificationCategory;
275
- priority: NotificationPriority;
276
- status: NotificationStatus;
277
- timestamp: string;
278
- sender?: {
279
- name: string;
280
- avatar?: string | undefined;
281
- } | undefined;
282
- actionUrl?: string | undefined;
283
- actionText?: string | undefined;
284
- extra?: Record<string, unknown> | undefined;
285
- }[]>;
286
- hasMore: vue.ComputedRef<boolean>;
287
- fetchMessages: (reset?: boolean) => Promise<void>;
288
- loadMore: () => Promise<void>;
289
- markAsRead: (ids: string[]) => Promise<void>;
290
- markAllAsRead: (category?: NotificationCategory) => Promise<void>;
291
- deleteMessages: (ids: string[]) => Promise<void>;
292
- clearMessages: (category?: NotificationCategory) => Promise<void>;
293
- selectMessage: (msg: NotificationMessage) => void;
294
- clearSelection: () => void;
295
- switchCategory: (category: NotificationCategory | "all") => void;
296
- requestDesktopPermission: () => Promise<NotificationPermission | "unsupported">;
297
- connectWS: (config: NotificationWSConfig) => void;
298
- disconnectWS: () => void;
250
+ declare function useNotificationCore(props: NotificationCenterProps, events?: NotificationCoreEvents): NotificationCenterController & {
251
+ initialize: () => void;
252
+ dispose: () => void;
299
253
  };
300
254
  //#endregion
301
255
  //#region src/components/C_NotificationCenter/composables/useNotificationFormat.d.ts
@@ -480,4 +434,4 @@ declare const MOCK_MESSAGES: ({
480
434
  actionText?: undefined;
481
435
  })[];
482
436
  //#endregion
483
- export { NotificationWSConfig as A, NotificationCenterEmits as C, NotificationPriority as D, NotificationMessage as E, WSNotificationPayload as M, NotificationSender as O, NotificationCategory as S, NotificationCenterProps as T, ClearNotificationsFn as _, DEFAULT_POLLING_INTERVAL as a, MarkAllReadFn as b, DEFAULT_WS_HEARTBEAT_MESSAGE as c, MOCK_MESSAGES as d, PRIORITY_MAP as f, _default as g, useNotificationCore as h, DEFAULT_PAGE_SIZE as i, WSConnectionStatus as j, NotificationStatus as k, DEFAULT_WS_MAX_RECONNECT as l, useNotificationFormat as m, CATEGORY_TABS as n, DEFAULT_STORAGE_KEY as o, useNotificationWS as p, DEFAULT_MAX_BADGE_COUNT as r, DEFAULT_WS_HEARTBEAT_INTERVAL as s, CATEGORY_MAP as t, DEFAULT_WS_RECONNECT_INTERVAL as u, DeleteNotificationFn as v, NotificationCenterExpose as w, MarkAsReadFn as x, FetchNotificationsFn as y };
437
+ export { NotificationPriority as A, NotificationCategory as C, NotificationCenterProps as D, NotificationCenterExpose as E, WSConnectionStatus as F, WSNotificationPayload as I, NotificationStatus as M, NotificationUnreadByCategory as N, NotificationDataMode as O, NotificationWSConfig as P, MarkAsReadFn as S, NotificationCenterEmits as T, ClearNotificationsFn as _, DEFAULT_POLLING_INTERVAL as a, FetchNotificationsResult as b, DEFAULT_WS_HEARTBEAT_MESSAGE as c, MOCK_MESSAGES as d, PRIORITY_MAP as f, _default as g, useNotificationCore as h, DEFAULT_PAGE_SIZE as i, NotificationSender as j, NotificationMessage as k, DEFAULT_WS_MAX_RECONNECT as l, useNotificationFormat as m, CATEGORY_TABS as n, DEFAULT_STORAGE_KEY as o, useNotificationWS as p, DEFAULT_MAX_BADGE_COUNT as r, DEFAULT_WS_HEARTBEAT_INTERVAL as s, CATEGORY_MAP as t, DEFAULT_WS_RECONNECT_INTERVAL as u, DeleteNotificationFn as v, NotificationCenterController as w, MarkAllReadFn as x, FetchNotificationsFn as y };