update 完成消息盒子功能前后端联动(已读未读在前端浏览器存储)
This commit is contained in:
45
src/utils/message-read.ts
Normal file
45
src/utils/message-read.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import cache from '@/plugins/cache';
|
||||
|
||||
const MESSAGE_READ_KEY = 'message_read_ids';
|
||||
const MAX_READ_IDS = 300;
|
||||
|
||||
const buildCacheKey = (userId: string | number) => `${MESSAGE_READ_KEY}:${userId}`;
|
||||
|
||||
const normalizeIds = (ids: Array<string | number>) => {
|
||||
const values = ids
|
||||
.map((item) => String(item))
|
||||
.filter((item) => !!item);
|
||||
return Array.from(new Set(values)).slice(0, MAX_READ_IDS);
|
||||
};
|
||||
|
||||
export const getMessageReadIds = (userId: string | number) => {
|
||||
if (!userId) {
|
||||
return [] as string[];
|
||||
}
|
||||
const ids = cache.local.getJSON(buildCacheKey(userId));
|
||||
return Array.isArray(ids) ? normalizeIds(ids) : [];
|
||||
};
|
||||
|
||||
export const isMessageRead = (userId: string | number, messageId?: string | number) => {
|
||||
if (!userId || messageId === undefined || messageId === null) {
|
||||
return false;
|
||||
}
|
||||
return getMessageReadIds(userId).includes(String(messageId));
|
||||
};
|
||||
|
||||
export const markMessageRead = (userId: string | number, messageId?: string | number) => {
|
||||
if (!userId || messageId === undefined || messageId === null) {
|
||||
return [];
|
||||
}
|
||||
return markMessageReadBatch(userId, [messageId]);
|
||||
};
|
||||
|
||||
export const markMessageReadBatch = (userId: string | number, messageIds: Array<string | number>) => {
|
||||
if (!userId) {
|
||||
return [] as string[];
|
||||
}
|
||||
const current = getMessageReadIds(userId);
|
||||
const next = normalizeIds([...messageIds, ...current]);
|
||||
cache.local.setJSON(buildCacheKey(userId), next);
|
||||
return next;
|
||||
};
|
||||
@@ -20,6 +20,7 @@ export const NOTICE_GROUP = {
|
||||
} as const;
|
||||
|
||||
export interface PushMessagePayload {
|
||||
messageId?: string | number;
|
||||
type?: string;
|
||||
source?: string;
|
||||
message?: string;
|
||||
@@ -36,6 +37,7 @@ export const parsePushMessage = (raw: string): PushMessagePayload => {
|
||||
return {
|
||||
type: payload.type ?? PUSH_MESSAGE_TYPE.MESSAGE,
|
||||
source: payload.source ?? 'backend',
|
||||
messageId: payload.messageId,
|
||||
message: payload.message ?? '',
|
||||
data: payload.data ?? null,
|
||||
path: payload.path,
|
||||
@@ -45,6 +47,7 @@ export const parsePushMessage = (raw: string): PushMessagePayload => {
|
||||
return {
|
||||
type: PUSH_MESSAGE_TYPE.MESSAGE,
|
||||
source: 'backend',
|
||||
messageId: undefined,
|
||||
message: raw,
|
||||
data: null,
|
||||
path: undefined,
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
import { getMessageBox } from '@/api/system/message';
|
||||
import type { MessageVO } from '@/api/system/message/types';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { ElNotification } from 'element-plus';
|
||||
import { useNoticeStore } from '@/store/modules/notice';
|
||||
import { isMessageRead } from '@/utils/message-read';
|
||||
import { parsePushMessage, resolveNoticeGroup, resolveNoticeTitle, shouldAppendNotice } from '@/utils/push-message';
|
||||
|
||||
let closePushConnection: (() => void) | undefined;
|
||||
|
||||
const formatNoticeTime = (timestamp?: number | string) => {
|
||||
const time = timestamp ? new Date(timestamp) : new Date();
|
||||
return time.toLocaleString();
|
||||
};
|
||||
|
||||
const appendNotice = (raw: string) => {
|
||||
const payload = parsePushMessage(raw);
|
||||
if (!shouldAppendNotice(payload)) {
|
||||
return;
|
||||
}
|
||||
const userId = useUserStore().userId;
|
||||
const title = resolveNoticeTitle(payload);
|
||||
useNoticeStore().addNotice({
|
||||
messageId: payload.messageId,
|
||||
title,
|
||||
category: resolveNoticeGroup(payload),
|
||||
type: payload.type,
|
||||
@@ -20,8 +31,9 @@ const appendNotice = (raw: string) => {
|
||||
content: payload.data?.noticeContent,
|
||||
data: payload.data,
|
||||
path: payload.path,
|
||||
read: false,
|
||||
time: new Date(payload.timestamp ?? Date.now()).toLocaleString()
|
||||
read: isMessageRead(userId, payload.messageId),
|
||||
timestamp: payload.timestamp ?? Date.now(),
|
||||
time: formatNoticeTime(payload.timestamp)
|
||||
});
|
||||
ElNotification({
|
||||
title,
|
||||
@@ -31,6 +43,25 @@ const appendNotice = (raw: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
const toNoticeItem = (item: MessageVO) => {
|
||||
const userId = useUserStore().userId;
|
||||
const timestamp = item.createTime ? new Date(item.createTime).getTime() : Date.now();
|
||||
return {
|
||||
messageId: item.messageId,
|
||||
title: item.title,
|
||||
category: resolveNoticeGroup(item),
|
||||
type: item.type,
|
||||
source: item.source,
|
||||
message: item.message ?? '',
|
||||
content: item.content,
|
||||
data: item.data ?? null,
|
||||
path: item.path,
|
||||
read: isMessageRead(userId, item.messageId),
|
||||
timestamp,
|
||||
time: formatNoticeTime(timestamp)
|
||||
};
|
||||
};
|
||||
|
||||
const buildSseUrl = (path: string) => {
|
||||
return `${import.meta.env.VITE_APP_BASE_API}${path}?Authorization=Bearer ${getToken()}&clientid=${import.meta.env.VITE_APP_CLIENT_ID}`;
|
||||
};
|
||||
@@ -108,6 +139,16 @@ export const initPush = () => {
|
||||
initSsePush(buildSseUrl(path));
|
||||
};
|
||||
|
||||
export const initMessageBox = async () => {
|
||||
if (import.meta.env.VITE_APP_MESSAGE_ENABLED === 'false') {
|
||||
useNoticeStore().clearNotice();
|
||||
return;
|
||||
}
|
||||
const { data } = await getMessageBox();
|
||||
const notices = [...(data?.systemList ?? []), ...(data?.noticeList ?? []), ...(data?.workflowList ?? [])].map(toNoticeItem);
|
||||
useNoticeStore().setNotices(notices);
|
||||
};
|
||||
|
||||
export const closePush = () => {
|
||||
closePushConnection?.();
|
||||
closePushConnection = undefined;
|
||||
|
||||
Reference in New Issue
Block a user