// 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, yidu } 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";
|
import RightToolbar from "@/components/RightToolbar"
|
|
// 注册全局组件
|
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.component("RightToolbar", RightToolbar);
|
|
// 注册全局方法
|
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;
|
|
// 通知管理:跟踪当前通知和偏移量
|
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: notificationManager.baseOffset, // 初始 offset
|
onClick: null, // 不跳转
|
customClass: 'global-notification',
|
dangerouslyUseHTMLString: false,
|
appendTo: document.body
|
});
|
notificationManager.addNotification(notification); // 添加到通知管理
|
};
|
|
// 监听路由变化
|
router.afterEach(() => {
|
console.log('路由切换完成,当前路径:', router.currentRoute.path);
|
});
|
|
// 定义 WebSocket 初始化标志,防止重复连接
|
let isWebSocketInitialized = false;
|
|
const app = new Vue({
|
el: "#app",
|
router,
|
store,
|
render: (h) => h(App),
|
mounted() {
|
const token = store.state.user.token || Cookies.get('token') || '';
|
if (token && !isWebSocketInitialized) {
|
console.log('初始化 WebSocket,Token:', 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 解析后消息:', 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('准备触发通知,noticeId:', 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('消息解析失败:', error, '原始数据:', data);
|
Vue.prototype.$showNotification.call(this, 'error', '消息解析失败', `服务器回应字符串: ${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);
|
Vue.use(Print);
|
Vue.use(Element, {
|
size: Cookies.get("size") || "medium",
|
});
|
DictData.install();
|
|
Vue.config.productionTip = false;
|