@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.
- package/CHANGELOG.md +11 -0
- package/dist/C_NotificationCenter.css +114 -78
- package/dist/C_NotificationCenter.d.cts +2 -2
- package/dist/C_NotificationCenter.d.ts +2 -2
- package/dist/C_NotificationCenter2.cjs +1 -1
- package/dist/C_NotificationCenter2.js +1 -1
- package/dist/constants.d.cts +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants3.d.cts +73 -119
- package/dist/constants3.d.ts +73 -119
- package/dist/constants4.d.cts +2 -2
- package/dist/constants4.d.ts +2 -2
- package/dist/constants5.d.cts +4 -4
- package/dist/constants5.d.ts +4 -4
- package/dist/data.d.cts +9 -9
- package/dist/data.d.ts +9 -9
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.vue.d.cts +3 -3
- package/dist/index.vue.d.ts +3 -3
- package/dist/index10.vue.d.cts +3 -3
- package/dist/index10.vue.d.ts +1 -1
- package/dist/index11.vue.d.cts +1 -1
- package/dist/index11.vue.d.ts +2 -2
- package/dist/index12.vue.d.cts +2 -2
- package/dist/index13.vue.d.ts +2 -2
- package/dist/index14.vue.d.cts +2 -2
- package/dist/index14.vue.d.ts +7 -7
- package/dist/index15.vue.d.cts +7 -7
- package/dist/index15.vue.d.ts +1 -1
- package/dist/index16.vue.d.cts +1 -1
- package/dist/index16.vue.d.ts +1 -1
- package/dist/index17.vue.d.cts +1 -1
- package/dist/index17.vue.d.ts +2 -2
- package/dist/index18.vue.d.cts +2 -2
- package/dist/index18.vue.d.ts +4 -4
- package/dist/index19.vue.d.cts +4 -4
- package/dist/index19.vue.d.ts +1 -1
- package/dist/index2.vue.d.cts +2 -2
- package/dist/index2.vue.d.ts +2 -2
- package/dist/index20.vue.d.cts +2 -2
- package/dist/index20.vue.d.ts +2 -2
- package/dist/index21.vue.d.cts +1 -1
- package/dist/index21.vue.d.ts +1 -1
- package/dist/index22.vue.d.cts +2 -2
- package/dist/index22.vue.d.ts +2 -2
- package/dist/index23.vue.d.cts +1 -1
- package/dist/index23.vue.d.ts +1 -1
- package/dist/index25.vue.d.cts +3 -3
- package/dist/index25.vue.d.ts +3 -3
- package/dist/index27.vue.d.cts +3 -3
- package/dist/index27.vue.d.ts +3 -3
- package/dist/index28.vue.d.cts +3 -3
- package/dist/index28.vue.d.ts +3 -3
- package/dist/index3.vue.d.cts +3 -3
- package/dist/index3.vue.d.ts +3 -3
- package/dist/index4.vue.d.cts +1 -1
- package/dist/index6.vue.d.ts +2 -2
- package/dist/index7.vue.d.cts +2 -2
- package/dist/index9.vue.d.ts +3 -3
- package/dist/mapUtils.d.cts +3 -3
- package/dist/mapUtils.d.ts +3 -3
- package/dist/style.css +115 -79
- package/dist/useCalendarEvents.d.cts +1 -1
- package/dist/useCalendarEvents.d.ts +1 -1
- package/dist/useCollapsePanel.d.cts +1 -1
- package/dist/useCollapsePanel.d.ts +1 -1
- package/dist/useCropperCore.d.cts +6 -6
- package/dist/useCropperCore.d.ts +6 -6
- package/dist/useDraggableLayout.d.cts +3 -3
- package/dist/useDraggableLayout.d.ts +3 -3
- package/dist/useDynamicFormState.d.cts +2 -2
- package/dist/useDynamicFormState.d.ts +2 -2
- package/dist/useEdgeInteraction.d.cts +1 -1
- package/dist/useEdgeInteraction.d.ts +1 -1
- package/dist/useFullscreen.d.cts +2 -2
- package/dist/useFullscreen.d.ts +2 -2
- package/dist/useInfiniteScroll.d.cts +1 -1
- package/dist/useInfiniteScroll.d.ts +1 -1
- package/dist/useQRCode.d.cts +1 -1
- package/dist/useQRCode.d.ts +1 -1
- package/dist/useSearchState.d.cts +3 -3
- package/dist/useSearchState.d.ts +3 -3
- package/dist/useSignatureHistory.d.cts +4 -4
- package/dist/useSignatureHistory.d.ts +4 -4
- package/dist/useSplitResize.d.cts +6 -6
- package/dist/useSplitResize.d.ts +6 -6
- package/dist/useTableQuery.d.cts +1 -1
- package/dist/useTableQuery.d.ts +1 -1
- package/dist/useTimeSelection.d.cts +1 -1
- package/dist/useTimeSelection.d.ts +1 -1
- package/dist/useTreeOperations.d.cts +6 -6
- package/dist/useTreeOperations.d.ts +6 -6
- package/dist/useWorkflowValidation.d.cts +2 -2
- package/dist/useWorkflowValidation.d.ts +2 -2
- package/dist/verification.d.cts +1 -1
- package/dist/verification.d.ts +1 -1
- package/docs/components.en.md +5 -5
- package/docs/components.md +5 -5
- package/docs/guides/notification-center.md +95 -0
- 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};
|
package/dist/constants.d.cts
CHANGED
|
@@ -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;
|
package/dist/constants.d.ts
CHANGED
|
@@ -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;
|
package/dist/constants3.d.cts
CHANGED
|
@@ -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
|
-
|
|
196
|
-
|
|
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 {
|
|
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 };
|