diff --git a/src/api/system/notice/sysNotice.ts b/src/api/system/notice/sysNotice.ts
new file mode 100644
index 0000000..39adb08
--- /dev/null
+++ b/src/api/system/notice/sysNotice.ts
@@ -0,0 +1,80 @@
+import request from '/@/utils/request'
+// 查询通知私信列表
+export function listSysNotice(query:object) {
+ return request({
+ url: '/api/v1/system/sysNotice/list',
+ method: 'get',
+ params: query
+ })
+}
+
+export function listShowNotice(query:object) {
+ return request({
+ url: '/api/v1/system/sysNotice/listShow',
+ method: 'get',
+ params: query
+ })
+}
+// 查询通知私信详细
+export function getSysNotice(id:number) {
+ return request({
+ url: '/api/v1/system/sysNotice/get',
+ method: 'get',
+ params: {
+ id: id.toString()
+ }
+ })
+}
+// 新增通知私信
+export function addSysNotice(data:object) {
+ return request({
+ url: '/api/v1/system/sysNotice/add',
+ method: 'post',
+ data: data
+ })
+}
+// 修改通知私信
+export function updateSysNotice(data:object) {
+ return request({
+ url: '/api/v1/system/sysNotice/edit',
+ method: 'put',
+ data: data
+ })
+}
+// 删除通知私信
+export function delSysNotice(ids:number[]) {
+ return request({
+ url: '/api/v1/system/sysNotice/delete',
+ method: 'delete',
+ data:{
+ ids:ids
+ }
+ })
+}
+
+
+export function getIndexData(){
+ return request(
+ {
+ url:'/api/v1/system/sysNotice/getIndexData',
+ method:'get'
+ }
+ )
+}
+
+//获取维度通知私信公告信息
+export function unReadCount(){
+ return request({
+ url:'/api/v1/system/sysNotice/unReadCount',
+ method:'get'
+ })
+}
+
+//获取私信待选择的用户
+export function getUserList(query:string){
+ return request({
+ url:'/api/v1/system/sysNotice/userList',
+ method:'get',
+ params:{userNickname:query}
+ })
+}
diff --git a/src/api/system/notice/sysNoticeRead.ts b/src/api/system/notice/sysNoticeRead.ts
new file mode 100644
index 0000000..c2576f2
--- /dev/null
+++ b/src/api/system/notice/sysNoticeRead.ts
@@ -0,0 +1,52 @@
+import request from '/@/utils/request'
+// 查询已读记录列表
+export function listSysNoticeRead(query:object) {
+ return request({
+ url: '/api/v1/system/sysNoticeRead/list',
+ method: 'get',
+ params: query
+ })
+}
+// 查询已读记录详细
+export function getSysNoticeRead(id:number) {
+ return request({
+ url: '/api/v1/system/sysNoticeRead/get',
+ method: 'get',
+ params: {
+ id: id.toString()
+ }
+ })
+}
+// 新增已读记录
+export function addSysNoticeRead(data:object) {
+ return request({
+ url: '/api/v1/system/sysNoticeRead/add',
+ method: 'post',
+ data: data
+ })
+}
+export function readNotice(data:object) {
+ return request({
+ url: '/api/v1/system/sysNoticeRead/readNotice',
+ method: 'post',
+ data: data
+ })
+}
+// 修改已读记录
+export function updateSysNoticeRead(data:object) {
+ return request({
+ url: '/api/v1/system/sysNoticeRead/edit',
+ method: 'put',
+ data: data
+ })
+}
+// 删除已读记录
+export function delSysNoticeRead(ids:number[]) {
+ return request({
+ url: '/api/v1/system/sysNoticeRead/delete',
+ method: 'delete',
+ data:{
+ ids:ids
+ }
+ })
+}
diff --git a/src/layout/navBars/breadcrumb/user.vue b/src/layout/navBars/breadcrumb/user.vue
index c8a38a1..9d68707 100644
--- a/src/layout/navBars/breadcrumb/user.vue
+++ b/src/layout/navBars/breadcrumb/user.vue
@@ -36,7 +36,7 @@
-
+
@@ -45,7 +45,7 @@
-
+
@@ -80,9 +80,9 @@
diff --git a/src/main.ts b/src/main.ts
index 6561639..a241a45 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -13,6 +13,7 @@ import '/@/theme/index.scss';
import mitt from 'mitt';
import VueGridLayout from 'vue-grid-layout';
import {getUpFileUrl, handleTree, parseTime, selectDictLabel} from '/@/utils/gfast';
+import Websocket from '/@/utils/websocket';
import {useDict} from '/@/api/system/dict/data';
import {getItems, setItems, getOptionValue, isEmpty} from '/@/api/items'
// 分页组件
@@ -27,6 +28,16 @@ import VueUeditorWrap from 'vue-ueditor-wrap';
const app = createApp(App);
+// 全局websocket
+const onMessageList: Array = [];
+app.provide('onMessageList', onMessageList);
+const onMessage = (event: any) => {
+ onMessageList.forEach((f) => {
+ f.call(null, event);
+ });
+};
+Websocket(onMessage);
+
directive(app);
other.elSvg(app);
diff --git a/src/stores/interface/index.ts b/src/stores/interface/index.ts
index 336b021..a0d99d0 100644
--- a/src/stores/interface/index.ts
+++ b/src/stores/interface/index.ts
@@ -95,3 +95,13 @@ export interface ThemeConfigStates {
export interface bigUploadStates {
panelShow : boolean
}
+
+export interface NoticeMessage{
+ id:number;
+ title:string;
+ tag:number;
+ type:number;
+}
+export interface NoticeStates{
+ message:NoticeMessage;
+}
diff --git a/src/stores/noticeStore.ts b/src/stores/noticeStore.ts
new file mode 100644
index 0000000..0f01209
--- /dev/null
+++ b/src/stores/noticeStore.ts
@@ -0,0 +1,19 @@
+import { defineStore } from 'pinia';
+import {NoticeMessage, NoticeStates} from "/@/stores/interface";
+
+export const noticeStore = defineStore({
+ id: 'noticeStore',
+ state: (): NoticeStates => ({
+ message: {}
+ }),
+ getters: {
+ getMessages(): NoticeMessage {
+ return this.message;
+ },
+ },
+ actions: {
+ setMessages(messages:NoticeMessage) {
+ this.message = messages;
+ },
+ },
+});
diff --git a/src/utils/websocket.ts b/src/utils/websocket.ts
new file mode 100644
index 0000000..7d0ac03
--- /dev/null
+++ b/src/utils/websocket.ts
@@ -0,0 +1,169 @@
+import {getToken} from "/@/utils/gfast"
+import {noticeStore} from "/@/stores/noticeStore";
+const noticeStoreAct = noticeStore()
+const webSocketURL = import.meta.env.VITE_WEBSOCKET_URL
+let socket: WebSocket;
+let isActive: boolean;
+
+export function getSocket(): WebSocket {
+ if (socket === undefined) {
+ location.reload();
+ }
+ return socket;
+}
+
+export function getActive(): boolean {
+ return isActive;
+}
+
+export function sendMsg(event: string, data = null, isRetry = true) {
+ if (socket === undefined || !isActive) {
+ if (!isRetry) {
+ console.log('socket连接异常,发送失败!');
+ return;
+ }
+ console.log('socket连接异常,等待重试..');
+ setTimeout(function () {
+ sendMsg(event, data);
+ }, 200);
+ return;
+ }
+
+ try {
+ socket.send(
+ JSON.stringify({
+ event: event,
+ data: data,
+ })
+ );
+ } catch (err) {
+ // @ts-ignore
+ console.log('ws发送消息失败,等待重试,err:' + err.message);
+ if (!isRetry) {
+ return;
+ }
+ setTimeout(function () {
+ sendMsg(event, data);
+ }, 100);
+ }
+}
+
+export function addOnMessage(onMessageList: any, func: Function) {
+ let exist = false;
+ for (let i = 0; i < onMessageList.length; i++) {
+ if (onMessageList[i].name == func.name) {
+ onMessageList[i] = func;
+ exist = true;
+ }
+ }
+ if (!exist) {
+ onMessageList.push(func);
+ }
+}
+
+export default (onMessage: Function) => {
+ const heartCheck = {
+ timeout: 10000,
+ timeoutObj: setTimeout(() => {}),
+ serverTimeoutObj: setInterval(() => {}),
+ reset: function () {
+ clearTimeout(this.timeoutObj);
+ clearTimeout(this.serverTimeoutObj);
+ return this;
+ },
+ start: function () {
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
+ const self = this;
+ clearTimeout(this.timeoutObj);
+ clearTimeout(this.serverTimeoutObj);
+ this.timeoutObj = setTimeout(function () {
+ socket.send(
+ JSON.stringify({
+ event: 'ping',
+ })
+ );
+ self.serverTimeoutObj = setTimeout(function () {
+ console.log('关闭服务');
+ socket.close();
+ }, self.timeout);
+ }, this.timeout);
+ },
+ };
+
+
+ let lockReconnect = false;
+ let timer: ReturnType;
+ const createSocket = () => {
+ console.log('createSocket...');
+ try {
+ if (getToken() === '') {
+ throw new Error('用户未登录,稍后重试...');
+ }
+ socket = new WebSocket(webSocketURL+'/api/v1/websocket?token='+encodeURIComponent(getToken()));
+ init();
+ } catch (e) {
+ console.log('createSocket err:' + e);
+ reconnect();
+ }
+ if (lockReconnect) {
+ lockReconnect = false;
+ }
+ };
+ const reconnect = () => {
+ console.log('lockReconnect:' + lockReconnect);
+ if (lockReconnect) return;
+ lockReconnect = true;
+ clearTimeout(timer);
+ timer = setTimeout(() => {
+ createSocket();
+ }, 30000);
+ };
+
+ const init = () => {
+ socket.onopen = function (_) {
+ console.log('WebSocket:已连接');
+ heartCheck.reset().start();
+ isActive = true;
+ };
+
+ socket.onmessage = function (event) {
+ isActive = true;
+ // console.log('WebSocket:收到一条消息', event.data);
+ let isHeart = false;
+ const message = JSON.parse(event.data);
+ if (message.event === 'ping') {
+ isHeart = true;
+ }
+ // 通知私信
+ if (message.event === 'notice') {
+ noticeStoreAct.setMessages(message.data)
+ return;
+ }
+ if (onMessage && !isHeart) {
+ onMessage.call(null, event);
+ }
+ heartCheck.reset().start();
+ };
+
+ socket.onerror = function (_) {
+ console.log('WebSocket:发生错误');
+ reconnect();
+ isActive = false;
+ };
+
+ socket.onclose = function (_) {
+ console.log('WebSocket:已关闭');
+ heartCheck.reset();
+ reconnect();
+ isActive = false;
+ };
+
+ window.onbeforeunload = function () {
+ socket.close();
+ isActive = false;
+ };
+ };
+
+ createSocket();
+};
+
diff --git a/src/views/system/sysNotice/list/component/NoticeMessageEdit.vue b/src/views/system/sysNotice/list/component/NoticeMessageEdit.vue
new file mode 100644
index 0000000..48cd0e0
--- /dev/null
+++ b/src/views/system/sysNotice/list/component/NoticeMessageEdit.vue
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+ {{
+ (!formData.id || formData.id == 0 ? '发送' : '修改') + title
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/system/sysNotice/list/component/model.ts b/src/views/system/sysNotice/list/component/model.ts
new file mode 100644
index 0000000..072eb1e
--- /dev/null
+++ b/src/views/system/sysNotice/list/component/model.ts
@@ -0,0 +1,61 @@
+export interface SysNoticeTableColumns {
+ id:number; // ID
+ title:string; // 标题
+ type:number; // 类型
+ tag:number; // 标签
+ content:string; // 内容
+ remark:string; // 备注
+ sort:number; // 排序
+ status:number; // 状态
+ createdBy:string; // 发送人
+ createdAt:string; // 创建时间
+}
+
+
+export interface SysNoticeInfoData {
+ id:number|undefined; // ID
+ receiver:number[]|undefined;//用户id
+ title:string|undefined; // 标题
+ type:number|undefined; // 类型
+ tag:number|undefined; // 标签
+ content:string|undefined; // 内容
+ remark:string|undefined; // 备注
+ sort:number|undefined; // 排序
+ status:number; // 状态
+ createdBy:number|undefined; // 发送人
+ updatedBy:number|undefined; // 修改人
+ createdAt:string|undefined; // 创建时间
+ updatedAt:string|undefined; // 更新时间
+ deletedAt:string|undefined; // 删除时间
+}
+
+
+export interface SysNoticeTableDataState {
+ ids:any[];
+ tableData: {
+ data: Array;
+ total: number;
+ loading: boolean;
+ param: {
+ pageNum: number;
+ pageSize: number;
+ id: number|undefined;
+ title: string|undefined;
+ type: number|undefined;
+ tag: number|undefined;
+ status: number|undefined;
+ createdAt: string|undefined;
+ dateRange: string[];
+ };
+ };
+}
+
+
+export interface SysNoticeEditState{
+ loading:boolean;
+ isShowDialog: boolean;
+ userListOptions:object[];
+ title:string;
+ formData:SysNoticeInfoData;
+ rules: object;
+}
diff --git a/src/views/system/sysNotice/list/index.vue b/src/views/system/sysNotice/list/index.vue
new file mode 100644
index 0000000..f571318
--- /dev/null
+++ b/src/views/system/sysNotice/list/index.vue
@@ -0,0 +1,375 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+
+
+
+
+
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+ 发通知
+
+
+
+
+
+
+
+ 发私信
+
+
+
+
+
+
+
+ 修改
+
+
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+ 通知
+ 私信
+
+
+
+
+ 无标签
+ 提醒
+ 一般
+ 次要
+ 重要
+ 紧急
+
+
+
+
+
+
+
+
+ 正常
+ 停用
+
+
+
+
+
+ {{ proxy.parseTime(scope.row.createdAt, '{y}-{m}-{d}') }}
+
+
+
+
+
+
+
+
+ 修改
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/system/sysNotice/show/index.vue b/src/views/system/sysNotice/show/index.vue
new file mode 100644
index 0000000..61e1533
--- /dev/null
+++ b/src/views/system/sysNotice/show/index.vue
@@ -0,0 +1,259 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.title }}
+
+ 已读
+ 未读
+
+
+ 无标签
+ 提醒
+ 一般
+ 次要
+ 重要
+ 紧急
+
+
+ {{ scope.row.createdAt }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.title }}
+
+
+ 已读
+ 未读
+
+
+ 无标签
+ 提醒
+ 一般
+ 次要
+ 重要
+ 紧急
+
+
+ {{ scope.row.createdAt }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+