From 55ed081b8414698e6e3b7d76c5c4032f264fb53f Mon Sep 17 00:00:00 2001 From: wwl <xchao828@163.com> Date: 星期四, 24 七月 2025 09:10:27 +0800 Subject: [PATCH] 1 --- /dev/null | 142 ----------------- src/main.js | 146 +++++++++++++++++- src/111.js | 97 ++++++++++++ src/api/system/config.js | 9 + src/utils/websocket.js | 45 +++- 5 files changed, 272 insertions(+), 167 deletions(-) diff --git a/src/111.js b/src/111.js new file mode 100644 index 0000000..9ebec6f --- /dev/null +++ b/src/111.js @@ -0,0 +1,97 @@ +// src/main.js +import Vue from "vue"; +import Cookies from "js-cookie"; +import "babel-polyfill"; +import Element from "element-ui"; +import "./assets/styles/element-variables.scss"; +import "@/assets/styles/index.scss"; +import "@/assets/styles/ruoyi.scss"; +import App from "./App"; +import store from "./store"; +import router from "./router"; +import directive from "./directive"; +import plugins from "./plugins"; +import { download } from "@/utils/request"; +import Print from "vue-print-nb"; +import JsonExcel from "vue-json-excel"; +import "./assets/icons"; +import "./permission"; +import { getDicts } from "@/api/system/dict/data"; +import { getConfigKey } from "@/api/system/config"; +import { + parseTime, + resetForm, + addDateRange, + selectDictLabel, + selectDictLabels, + handleTree, +} from "@/utils/ruoyi"; +import Pagination from "@/components/Pagination"; +import Editor from "@/components/Editor"; +import FileUpload from "@/components/FileUpload"; +import ImageUpload from "@/components/ImageUpload"; +import ImagePreview from "@/components/ImagePreview"; +import DictTag from "@/components/DictTag"; +import VueMeta from "vue-meta"; +import DictData from "@/components/DictData"; +import * as echarts from "echarts"; +import VueBarcode from "vue-barcode"; + +Vue.component("downloadExcel", JsonExcel); +Vue.component("barcode", VueBarcode); +Vue.component("DictTag", DictTag); +Vue.component("Pagination", Pagination); +Vue.component("Editor", Editor); +Vue.component("FileUpload", FileUpload); +Vue.component("ImageUpload", ImageUpload); +Vue.component("ImagePreview", ImagePreview); + +Vue.prototype.getDicts = getDicts; +Vue.prototype.getConfigKey = getConfigKey; +Vue.prototype.parseTime = parseTime; +Vue.prototype.resetForm = resetForm; +Vue.prototype.addDateRange = addDateRange; +Vue.prototype.selectDictLabel = selectDictLabel; +Vue.prototype.selectDictLabels = selectDictLabels; +Vue.prototype.download = download; +Vue.prototype.handleTree = handleTree; +Vue.prototype.$echarts = echarts; + +// 淇濈暀 $showNotification锛屾敮鎸佹墜鍔ㄨЕ鍙戦�氱煡 +Vue.prototype.$showNotification = function (type, title, message, onClick) { + console.log('瑙﹀彂閫氱煡:', { type, title, message }, new Date().toLocaleString()); + Vue.prototype.$notify({ + title, + message, + type, + duration: 5000, + position: 'top-right', + offset: 50, + onClick, + customClass: 'global-notification', + appendTo: document.body + }); +}; + +// 鐩戝惉璺敱鍙樺寲 +router.afterEach(() => { + console.log('璺敱鍒囨崲瀹屾垚锛屽綋鍓嶈矾寰�:', router.currentRoute.path); +}); + +const app = new Vue({ + el: "#app", + router, + store, + render: (h) => h(App) +}); + +Vue.use(directive); +Vue.use(plugins); +Vue.use(VueMeta); +Vue.use(Print); +Vue.use(Element, { + size: Cookies.get("size") || "medium", +}); +DictData.install(); + +Vue.config.productionTip = false; \ No newline at end of file diff --git a/src/api/system/config.js b/src/api/system/config.js index a404d82..6a60353 100644 --- a/src/api/system/config.js +++ b/src/api/system/config.js @@ -33,7 +33,14 @@ data: data }) } - +// 鏂板鍙傛暟閰嶇疆 +export function yidu(data) { + return request({ + url: '/system/notice/readNotice ', + method: 'post', + data: data + }) +} // 淇敼鍙傛暟閰嶇疆 export function updateConfig(data) { return request({ diff --git a/src/main copy.js b/src/main copy.js deleted file mode 100644 index 30d4cab..0000000 --- a/src/main copy.js +++ /dev/null @@ -1,142 +0,0 @@ -// src/main.js -import Vue from "vue"; -import Cookies from "js-cookie"; -import "babel-polyfill"; -import Element from "element-ui"; -import "./assets/styles/element-variables.scss"; -import "@/assets/styles/index.scss"; -import "@/assets/styles/ruoyi.scss"; -import App from "./App"; -import store from "./store"; -import router from "./router"; -import directive from "./directive"; -import plugins from "./plugins"; -import { download } from "@/utils/request"; -import Print from "vue-print-nb"; -import JsonExcel from "vue-json-excel"; -import "./assets/icons"; -import "./permission"; -import { getDicts } from "@/api/system/dict/data"; -import { getConfigKey } from "@/api/system/config"; -import { - parseTime, - resetForm, - addDateRange, - selectDictLabel, - selectDictLabels, - handleTree, -} from "@/utils/ruoyi"; -import Pagination from "@/components/Pagination"; -import Editor from "@/components/Editor"; -import FileUpload from "@/components/FileUpload"; -import ImageUpload from "@/components/ImageUpload"; -import ImagePreview from "@/components/ImagePreview"; -import DictTag from "@/components/DictTag"; -import VueMeta from "vue-meta"; -import DictData from "@/components/DictData"; -import * as echarts from "echarts"; -import VueBarcode from "vue-barcode"; -import { initWebSocket, closeWebSocket } from "@/utils/websocket"; - -Vue.component("downloadExcel", JsonExcel); -Vue.component("barcode", VueBarcode); -Vue.component("DictTag", DictTag); -Vue.component("Pagination", Pagination); -Vue.component("Editor", Editor); -Vue.component("FileUpload", FileUpload); -Vue.component("ImageUpload", ImageUpload); -Vue.component("ImagePreview", ImagePreview); - -Vue.prototype.getDicts = getDicts; -Vue.prototype.getConfigKey = getConfigKey; -Vue.prototype.parseTime = parseTime; -Vue.prototype.resetForm = resetForm; -Vue.prototype.addDateRange = addDateRange; -Vue.prototype.selectDictLabel = selectDictLabel; -Vue.prototype.selectDictLabels = selectDictLabels; -Vue.prototype.download = download; -Vue.prototype.handleTree = handleTree; -Vue.prototype.$echarts = echarts; - -Vue.prototype.$showNotification = function (type, title, message, onClick) { - console.log('瑙﹀彂閫氱煡:', { type, title, message }); - Vue.prototype.$notify({ - title, - message, - type, - duration: 5000, - position: 'top-right', - offset: 50, - onClick, - customClass: 'global-notification', - appendTo: document.body - }); -}; - -// 鐩戝惉璺敱鍙樺寲 -router.afterEach(() => { - console.log('璺敱鍒囨崲瀹屾垚锛屽綋鍓嶈矾寰�:', router.currentRoute.path); -}); - -const app = new Vue({ - el: "#app", - router, - store, - render: (h) => h(App), - mounted() { - const token = store.state.user.token || Cookies.get('token') || ''; - if (token) { - console.log('Token:', token); - initWebSocket(token, (type, data) => { - if (type === 'error') { - Vue.prototype.$showNotification('error', '閿欒', data); - return; - } - try { - const message = JSON.parse(data); - console.log('WebSocket 瑙f瀽鍚庢秷鎭�:', message); - if (message.noticeId && message.noticeTitle) { - const noticeTypeLabel = message.noticeType === '1' ? '閫氱煡' : '鍏憡'; - const contentPreview = message.noticeContent - ? message.noticeContent.replace(/<[^>]+>/g, '').substring(0, 20) + '...' - : '鏃犲唴瀹�'; - Vue.prototype.$showNotification( - 'success', - `鏂�${noticeTypeLabel}`, - `${message.noticeTitle} - ${contentPreview}`, - () => { - - router.push({ - path: '/redirect/notice', - query: { noticeId: message.noticeId } - }); - } - ); - } else { - console.log('鏈煡娑堟伅绫诲瀷:', message); - Vue.prototype.$showNotification('info', '娑堟伅', '鏀跺埌鏈煡鏍煎紡鐨勬秷鎭�'); - } - } catch (error) { - console.error('娑堟伅瑙f瀽澶辫触:', error, '鍘熷鏁版嵁:', data); - Vue.prototype.$showNotification('info', '娑堟伅', `鏈嶅姟鍣ㄥ洖搴斿瓧绗︿覆: ${data}`); - } - }); - } else { - console.error('鏈壘鍒� token锛屾棤娉曞垵濮嬪寲 WebSocket'); - } - }, - beforeDestroy() { - closeWebSocket(); // 娓呯悊 WebSocket - } -}); - -Vue.use(directive); -Vue.use(plugins); -Vue.use(VueMeta); -Vue.use(Print); -Vue.use(Element, { - size: Cookies.get("size") || "medium", -}); -DictData.install(); - -Vue.config.productionTip = false; \ No newline at end of file diff --git a/src/main.js b/src/main.js index 9ebec6f..37508ae 100644 --- a/src/main.js +++ b/src/main.js @@ -17,7 +17,7 @@ import "./assets/icons"; import "./permission"; import { getDicts } from "@/api/system/dict/data"; -import { getConfigKey } from "@/api/system/config"; +import { getConfigKey, yidu } from "@/api/system/config"; import { parseTime, resetForm, @@ -36,7 +36,10 @@ import DictData from "@/components/DictData"; import * as echarts from "echarts"; import VueBarcode from "vue-barcode"; +import { initWebSocket, closeWebSocket } from "@/utils/websocket"; +import RightToolbar from "@/components/RightToolbar" +// 娉ㄥ唽鍏ㄥ眬缁勪欢 Vue.component("downloadExcel", JsonExcel); Vue.component("barcode", VueBarcode); Vue.component("DictTag", DictTag); @@ -45,7 +48,9 @@ Vue.component("FileUpload", FileUpload); Vue.component("ImageUpload", ImageUpload); Vue.component("ImagePreview", ImagePreview); +Vue.component("RightToolbar", RightToolbar); +// 娉ㄥ唽鍏ㄥ眬鏂规硶 Vue.prototype.getDicts = getDicts; Vue.prototype.getConfigKey = getConfigKey; Vue.prototype.parseTime = parseTime; @@ -57,20 +62,78 @@ Vue.prototype.handleTree = handleTree; Vue.prototype.$echarts = echarts; -// 淇濈暀 $showNotification锛屾敮鎸佹墜鍔ㄨЕ鍙戦�氱煡 -Vue.prototype.$showNotification = function (type, title, message, onClick) { - console.log('瑙﹀彂閫氱煡:', { type, title, message }, new Date().toLocaleString()); - Vue.prototype.$notify({ - title, - message, +// 閫氱煡绠$悊锛氳窡韪綋鍓嶉�氱煡鍜屽亸绉婚噺 +const notificationManager = { + notifications: [], // 瀛樺偍褰撳墠鏄剧ず鐨勯�氱煡瀹炰緥 + baseOffset: 50, // 鍩虹鍋忕Щ閲� + notificationHeight: 80, // 姣忎釜閫氱煡鐨勪及璁¢珮搴︼紙鍖呮嫭闂磋窛锛� + maxNotifications: 5, // 鏈�澶у悓鏃舵樉绀虹殑閫氱煡鏁伴噺 + addNotification(notification) { + if (this.notifications.length >= this.maxNotifications) { + // 鍏抽棴鏈�鏃╃殑閫氱煡 + const oldest = this.notifications.shift(); + oldest.close(); + } + this.notifications.push(notification); + // 璁剧疆鍔ㄦ�� offset 鍜� z-index + notification.offset = this.baseOffset + this.notifications.length * this.notificationHeight; + notification.customClass += ` notification-${this.notifications.length}`; // 涓� z-index 娣诲姞鍞竴绫� + // 鐩戝惉閫氱煡鍏抽棴 + notification.onClose = () => { + const index = this.notifications.indexOf(notification); + if (index > -1) { + this.notifications.splice(index, 1); + // 鏇存柊鍚庣画閫氱煡鐨� offset + this.updateOffsets(); + } + }; + }, + updateOffsets() { + this.notifications.forEach((notification, index) => { + notification.offset = this.baseOffset + (index + 1) * this.notificationHeight; + notification.customClass = notification.customClass.replace(/notification-\d+/, `notification-${index + 1}`); + }); + } +}; + +// 鍏ㄥ眬閫氱煡鏂规硶锛屾坊鍔犫�滃凡璇烩�濇寜閽� +Vue.prototype.$showNotification = function (type, title, message, onClick, noticeId) { + console.log('瑙﹀彂閫氱煡:', { type, title, message, noticeId, noticeIdType: typeof noticeId }); // 璋冭瘯锛氳褰� noticeId 鍜岀被鍨� + const h = this.$createElement; + const notification = this.$notify({ + title: title, + message: h('div', { class: 'notification-content' }, [ + h('div', { class: 'notification-message' }, message), + noticeId ? h('el-button', { + class: 'read-button', + style: { marginLeft: '10px', float: 'right', cursor: 'pointer' }, + props: { type: 'primary', size: 'mini' }, + on: { + click: async () => { + console.log('鐐瑰嚮鈥滃凡璇烩�濇寜閽紝noticeId:', noticeId, 'type:', typeof noticeId); // 璋冭瘯锛氳褰曠偣鍑绘椂鐨� noticeId + try { + await yidu({ noticeId: String(noticeId) }); + console.log(`閫氱煡 ${noticeId} 宸叉爣璁颁负宸茶`); + this.$message.success('鏍囪涓哄凡璇绘垚鍔�'); + notification.close(); + } catch (error) { + console.error('鏍囪宸茶澶辫触:', error, 'noticeId:', noticeId); + this.$message.error('鏍囪宸茶澶辫触'); + } + } + } + }, '宸茶') : null + ]), type, duration: 5000, position: 'top-right', - offset: 50, - onClick, + offset: notificationManager.baseOffset, // 鍒濆 offset + onClick: null, // 涓嶈烦杞� customClass: 'global-notification', + dangerouslyUseHTMLString: false, appendTo: document.body }); + notificationManager.addNotification(notification); // 娣诲姞鍒伴�氱煡绠$悊 }; // 鐩戝惉璺敱鍙樺寲 @@ -78,13 +141,76 @@ console.log('璺敱鍒囨崲瀹屾垚锛屽綋鍓嶈矾寰�:', router.currentRoute.path); }); +// 瀹氫箟 WebSocket 鍒濆鍖栨爣蹇楋紝闃叉閲嶅杩炴帴 +let isWebSocketInitialized = false; + const app = new Vue({ el: "#app", router, store, - render: (h) => h(App) + render: (h) => h(App), + mounted() { + const token = store.state.user.token || Cookies.get('token') || ''; + if (token && !isWebSocketInitialized) { + console.log('鍒濆鍖� WebSocket锛孴oken:', token); + isWebSocketInitialized = true; + initWebSocket(token, (type, data) => { + console.log('WebSocket 鏀跺埌娑堟伅:', { type, data }); // 璋冭瘯锛氳褰曞師濮嬫暟鎹� + if (type === 'error') { + Vue.prototype.$showNotification.call(this, 'error', '閿欒', data); + return; + } + try { + if (typeof data === 'string' && data.trim().startsWith('{')) { + // 鏇挎崲澶ф暣鏁板瓧娈碉紝闃叉绮惧害涓㈠け + const normalizedData = data.replace(/"(noticeId|notice_id|id)":\s*(\d+)/g, '"$1":"$2"'); + const message = JSON.parse(normalizedData); + console.log('WebSocket 瑙f瀽鍚庢秷鎭�:', message); // 璋冭瘯锛氳褰曡В鏋愬悗鐨勬秷鎭� + if (message.noticeId || message.notice_id || message.id) { + const noticeTypeLabel = message.noticeType === '1' ? '閫氱煡' : '鍏憡'; + const noticeTitle = message.noticeTitle ? message.noticeTitle.replace(/<[^>]+>/g, '') : '鏃犳爣棰�'; + const contentPreview = message.noticeContent + ? message.noticeContent.replace(/<[^>]+>/g, '').substring(0, 20) + '...' + : '鏃犲唴瀹�'; + const noticeId = String(message.noticeId || message.notice_id || message.id); + console.log('鍑嗗瑙﹀彂閫氱煡锛宯oticeId:', noticeId, 'type:', typeof noticeId); // 璋冭瘯锛氳褰曚紶閫掔殑 noticeId + Vue.prototype.$showNotification.call( + this, + 'success', + `鏂�${noticeTypeLabel}`, + `${noticeTitle} - ${contentPreview}`, + null, + noticeId + ); + } else { + console.log('鏈煡娑堟伅绫诲瀷:', message); + Vue.prototype.$showNotification.call(this, 'info', '娑堟伅', '鏀跺埌鏈煡鏍煎紡鐨勬秷鎭�'); + } + } else { + console.log('WebSocket 闈� JSON 娑堟伅:', data); + + } + } catch (error) { + console.error('娑堟伅瑙f瀽澶辫触:', error, '鍘熷鏁版嵁:', data); + Vue.prototype.$showNotification.call(this, 'error', '娑堟伅瑙f瀽澶辫触', `鏈嶅姟鍣ㄥ洖搴斿瓧绗︿覆: ${data}`); + } + }); + } else if (!token) { + console.error('鏈壘鍒� token锛屾棤娉曞垵濮嬪寲 WebSocket'); + } else { + console.log('WebSocket 宸插垵濮嬪寲锛岃烦杩囬噸澶嶈繛鎺�'); + } + }, + beforeDestroy() { + if (isWebSocketInitialized) { + closeWebSocket(); + isWebSocketInitialized = false; + console.log('Vue 瀹炰緥閿�姣侊紝WebSocket 宸叉竻鐞�'); + } + } }); +// 娉ㄥ唽鎻掍欢 Vue.use(directive); Vue.use(plugins); Vue.use(VueMeta); diff --git a/src/utils/websocket.js b/src/utils/websocket.js index 40529b1..9d956c5 100644 --- a/src/utils/websocket.js +++ b/src/utils/websocket.js @@ -1,6 +1,7 @@ // src/utils/websocket.js let ws = null; let reconnectAttempts = 0; +let pingTimer = null; // 鐢ㄤ簬绠$悊蹇冭烦瀹氭椂鍣� const maxReconnectAttempts = 5; const reconnectInterval = 5000; // 5绉掗噸杩為棿闅� const pingInterval = 5000; // 5绉掑彂閫乸ing @@ -11,21 +12,33 @@ return; } - const wsUrl = `ws://192.168.1.2:5011/ws?token=${token}`; + // 濡傛灉 ws 宸插瓨鍦ㄤ笖杩炴帴娲昏穬锛屽垯璺宠繃鍒濆鍖� + if (ws && ws.readyState === WebSocket.OPEN) { + console.log('WebSocket 宸茶繛鎺ワ紝璺宠繃閲嶅鍒濆鍖�'); + return; + } + + // 濡傛灉 ws 瀛樺湪浣嗘湭鍏抽棴锛屽厛鍏抽棴鏃ц繛鎺� + if (ws) { + console.warn('鍙戠幇鏃� WebSocket 杩炴帴锛屾鍦ㄥ叧闂�...'); + closeWebSocket(); + } + + const wsUrl = `ws://192.168.1.244:5011/ws?token=${token}`; ws = new WebSocket(wsUrl); ws.onopen = () => { - console.log('WebSocket 杩炴帴鎴愬姛'); - reconnectAttempts = 0; + reconnectAttempts = 0; // 閲嶇疆閲嶈繛璁℃暟 // 鍚姩蹇冭烦鏈哄埗 - const pingTimer = setInterval(() => { - if (ws.readyState === WebSocket.OPEN) { - console.log('鍙戦�� ping 娑堟伅'); + if (pingTimer) clearInterval(pingTimer); // 娓呯悊鏃у畾鏃跺櫒 + pingTimer = setInterval(() => { + if (ws && ws.readyState === WebSocket.OPEN) { ws.send('ping'); } else { console.warn('WebSocket 鏈繛鎺ワ紝鍋滄 ping'); clearInterval(pingTimer); + pingTimer = null; } }, pingInterval); }; @@ -35,6 +48,7 @@ console.log('WebSocket 鏀跺埌鍘熷娑堟伅:', data); if (data === 'pong') { console.log('鏀跺埌 pong 鍝嶅簲锛岃繛鎺ユ椿璺�'); + reconnectAttempts = 0; // 閲嶇疆閲嶈繛璁℃暟锛岀‘淇濇椿璺冭繛鎺ヤ笉瑙﹀彂閲嶈繛 return; } onMessage('message', data); @@ -42,11 +56,14 @@ ws.onerror = (error) => { console.error('WebSocket 閿欒:', error); - onMessage('error', 'WebSocket 杩炴帴閿欒'); }; ws.onclose = () => { - console.warn('WebSocket 杩炴帴鍏抽棴'); + console.warn('WebSocket 杩炴帴鍏抽棴锛屾椂闂�:', new Date()); + if (pingTimer) { + clearInterval(pingTimer); + pingTimer = null; + } if (reconnectAttempts < maxReconnectAttempts) { reconnectAttempts++; console.log(`灏濊瘯閲嶈繛 (${reconnectAttempts}/${maxReconnectAttempts})...`); @@ -61,18 +78,18 @@ // 娓呯悊 WebSocket window.addEventListener('beforeunload', () => { - if (ws) { - ws.close(); - ws = null; - console.log('WebSocket 宸叉竻鐞�'); - } - }); + closeWebSocket(); + }, { once: true }); // 纭繚浜嬩欢鐩戝惉鍙坊鍔犱竴娆� } export function closeWebSocket() { if (ws) { ws.close(); ws = null; + if (pingTimer) { + clearInterval(pingTimer); + pingTimer = null; + } console.log('WebSocket 宸插叧闂�'); } } \ No newline at end of file -- Gitblit v1.8.0