Vue+Notification 自界说消息关照组件 支持数据分页 及时更新

[复制链接]
发表于 2025-9-22 22:42:28 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
结果图:
  1. <img alt=""  src="[img]https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvMDI0OGY4ZGIwN2Y4NGNmZTg5YTA0NmNmNGFlZjFlNDUucG5n[/img]"  />
复制代码
 message.vue 消息组件 子组件
  1. <template>
  2.   <div class="custom-notification">
  3.     <div class="content">
  4.       <span @click="gotoMessageList(currentMessage.split('=')[1])">{{ currentMessage.split('=')[0] }}</span>
  5.     </div>
  6.     <div class="footer">
  7.       <div class="left-buttons">
  8.         <el-button size="mini" type="text"  @click="handleIgnoreAll">忽略全部</el-button>
  9.       </div>
  10.       <div class="pagination">
  11.         <el-pagination
  12.           small
  13.           :key="paginationKey"
  14.           :current-page.sync="currentPage"
  15.           :page-size="1"
  16.           :total="localNoticeList.length"
  17.           layout="prev,slot, next"
  18.           prev-text="<"
  19.           next-text=">"
  20.           @prev-click="currentPage--"
  21.           @next-click="currentPage++">
  22.           <span class="pagination-text">{{ currentPage }} / {{ totalPages }}</span>
  23.         </el-pagination>
  24.       </div>
  25.       <div class="right-button">
  26.         <el-button type="primary" size="mini" @click="handleAccept(currentMessage.split('=')[1])">接受</el-button>
  27.       </div>
  28.     </div>
  29.   </div>
  30. </template>
  31. <script>
  32.   export default {
  33.     props: {
  34.       messages: {
  35.         type: Array,
  36.         default: () => []
  37.       },
  38.       total:{
  39.         type:Number,
  40.         default:0
  41.       },
  42.       noticeList:{
  43.         type:Array,
  44.         default:()=>[]
  45.       }
  46.     },
  47.     data() {
  48.       return {
  49.         localNoticeList: [], // 新增本地副本
  50.         currentPage: 1,
  51.         totalPage: 5,
  52.         paginationKey: 0  // 分页组件独立key
  53.       }
  54.     },
  55.     watch: {
  56.       noticeList: {
  57.         deep:true,
  58.         immediate: true,
  59.         handler(newVal) {
  60.           this.localNoticeList = JSON.parse(JSON.stringify(newVal))
  61.           // 当消息更新时自动重置页码
  62.           this.currentPage = Math.min(this.currentPage, newVal.length)
  63.           this.paginationKey++  // 强制分页组件重置
  64.           // this.updateList(this.localNoticeList)
  65.         }
  66.       }
  67.     },
  68.     computed: {
  69.       totalPages() {
  70.         return this.localNoticeList.length || 1
  71.       },
  72.       currentMessage() {
  73.         return this.localNoticeList[this.currentPage - 1]?.messageTitle +'='+this.localNoticeList[this.currentPage - 1]?.messageId || ''
  74.       }
  75.     },
  76.     methods: {
  77.       handleLater() {
  78.         // 稍后提醒逻辑
  79.         this.$emit('later')
  80.       },
  81.       handleIgnoreAll() {
  82.         // 忽略全部 将消息全部设为已读
  83.         this.$emit('ignore-all',this.localNoticeList) // 触发父级关闭事件
  84.       },
  85.       handleAccept(msgId) {
  86.         //接收
  87.         this.$emit('gotoMessageList',msgId)
  88.       },
  89.       gotoMessageList(msgId){
  90.         this.$emit('gotoMessageList',msgId)
  91.       },
  92.       // 通过事件通知父组件
  93.       updateList(newList) {
  94.         this.$emit('update-list', newList)
  95.       }
  96.     }
  97.   }
  98. </script>
  99. <style scoped>
  100.   .custom-notification {
  101.     padding: 15px 0px 15px 0px;
  102.     width: 270px;
  103.   }
  104.   .header {
  105.     display: flex;
  106.     align-items: center;
  107.     margin-bottom: 12px;
  108.   }
  109.   .content{
  110.     cursor: pointer;
  111.     font-weight: bold;
  112.     font-size: 13px;
  113.   }
  114.   .header i {
  115.     margin-right: 8px;
  116.     font-size: 16px;
  117.   }
  118.   .footer {
  119.     display: flex;
  120.     justify-content: space-between;
  121.     align-items: center;
  122.     margin-top: 15px;
  123.   }
  124.   .pagination {
  125.     display: flex;
  126.     align-items: center;
  127.     gap: 8px;
  128.   }
  129.   .pagination i {
  130.     cursor: pointer;
  131.     color: #606266;
  132.   }
  133.   .left-buttons .el-button--text {
  134.     color: #909399;
  135.   }
  136.   .pagination-text{
  137.     text-align: center;
  138.   }
  139. </style>
复制代码
消息父组件:
  1. <template>
  2.   <div>
  3.     <el-badge :value="total" class="item" style="line-height: 40px; position: relative;">
  4.       <span @click="bellClick">
  5.         <el-icon
  6.           class="el-icon-bell"
  7.           style="font-size: 20px; cursor: pointer; transform: translateY(1.1px)"
  8.         ></el-icon>
  9.       </span>
  10.     </el-badge>
  11.     <!-- 添加或修改我的消息对话框 -->
  12.     <el-dialog title="我的消息" :visible.sync="open" width="500px" append-to-body>
  13.       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  14.         <el-form-item label="消息标题" prop="messageTitle">
  15.           <el-input disabled v-model="form.messageTitle" placeholder="请输入消息标题" />
  16.         </el-form-item>
  17.         <el-form-item label="消息内容">
  18.           <editor :readOnly="true" v-model="form.messageContent" :min-height="192" />
  19.         </el-form-item>
  20.       </el-form>
  21.       <div slot="footer" class="dialog-footer">
  22.         <el-button @click="cancel">关闭</el-button>
  23.       </div>
  24.     </el-dialog>
  25.     <!--  word预览弹窗  -->
  26.     <el-dialog fullscreen title="word预览" :visible.sync="dialogVisibleWord" append-to-body>
  27.       <vue-office-docx :src="previewWordOffice" @rendered="renderedHandler" @error="errorHandler" />
  28.     </el-dialog>
  29.     <!--    doc预览  -->
  30.     <el-dialog fullscreen title="word预览" :visible.sync="DocSync" append-to-body>
  31.       <VueOfficePdf :src="docSrc"  />
  32.     </el-dialog>
  33.     <el-dialog
  34.       :title="msg.messageTitle"
  35.       :visible.sync="messageVisible"
  36.       width="800px"
  37.       append-to-body
  38.       class="my-message__dialog"
  39.       @close="closeMsgModel"
  40.     >
  41.       <div><span class="contentImg" v-html="msg.messageContent"></span>
  42.       </div>
  43.       <div class="my-message__filebox" v-if="fileList.length > 0">
  44.         <div>附件:</div>
  45.         <ul class="my-message__ul">
  46.           <li class="my-message__li" v-for="(item, index) in fileList" :key="index">
  47.             <div class="my-message__li--title">{{ item.name }}</div>
  48.             <div class="my-message__li--opt">
  49.               <el-button
  50.                 style="color: green"
  51.                 @click.stop="handleShow(index, item)"
  52.                 type="text"
  53.                 icon="el-icon-view"
  54.                 size="mini"
  55.                 v-if="getFileExtension(item.name) !== 'zip' && getFileExtension(item.name) !== 'rar'"
  56.               >查看
  57.               </el-button>
  58.             </div>
  59.           </li>
  60.         </ul>
  61.       </div>
  62.       <div slot="footer" class="dialog-footer">
  63.         <el-button @click.stop="closeMsgModel">关闭</el-button>
  64.       </div>
  65.     </el-dialog>
  66. <!--    <custom-notification></custom-notification>-->
  67.   </div>
  68. </template>
  69. <script>
  70. import Vue from 'vue'
  71. import { mapGetters } from 'vuex';
  72. //引入VueOfficeDocx组件
  73. import VueOfficeDocx from '@vue-office/docx';
  74. import { listMyUnreadNotice, getSysmessage, listSysmessage } from '@/api/system/sysmessage';
  75. import { fileDownload, previewDocumentAPI } from '@/api/files/files';
  76. import XLSX from 'xlsx';
  77. import events from '@/utils/events';
  78. import VueOfficePdf from '@vue-office/pdf';
  79. import Notification from 'element-ui/lib/notification'
  80. import CustomNotification from '@/components/Bell/component/message'
  81. export default {
  82.   name: 'index',
  83.   components: { VueOfficePdf, VueOfficeDocx,CustomNotification },
  84.   data() {
  85.     return {
  86.       DocSync:false,
  87.       docSrc:'',
  88.       baseUrl: 'http://' + window.location.host + process.env.VUE_APP_BASE_API,
  89.       dialogVisibleWord: false,
  90.       previewWordOffice: '',
  91.       noticeList: [],
  92.       noticeListNew:[],//
  93.       pollInterval: null,// 轮询定时器
  94.       lastCheckTime: null,// 最后检查时间
  95.       notificationKey:0,
  96.       isFirstCheck: true,// 首次检查标志
  97.       templateVisible: false,
  98.       messageVisible:false,
  99.       showAllBtn: false,
  100.       msg:{},
  101.       form: {},
  102.       rules: {},
  103.       open: false,
  104.       queryParams: {
  105.         id: null,
  106.         status: '0'
  107.       },
  108.       fileList: [],
  109.       total: 0,
  110.       totalNew:0,
  111.       notificationInstance:null //通知示例
  112.     };
  113.   },
  114.   computed: {
  115.     ...mapGetters(['isDot', 'id'])
  116.   },
  117.   created() {
  118.     // on接收   emit发送
  119.     this.clearPolling()
  120.     this.getUnRead(); //查询是否有未读消息通知
  121.     this.getUnReadNew(); //初始化调用获取未读消息
  122.     events.$on('noticePush', this.getUnRead);
  123.     events.$on('noticePushByMsg', this.getUnRead);
  124.     this.$nextTick(() => {
  125.       events.$on('noticeCheckByMsg', this.getUnRead);
  126.       // events.$on('noticeCancel',this.cancel);
  127.     });
  128.     events.$on('noticePush',this.getUnReadNew)
  129.   },
  130.   mounted() {
  131.   },
  132.   beforeDestroy() {
  133.     // this.clearPolling()
  134.   },
  135.   // 关闭定时器
  136.   deactivated(){
  137.     // this.clearPolling()
  138.   },
  139.   methods: {
  140.     // 跳转链接
  141.     clickSpan() {
  142.       // 点击跳转我的消息页
  143.       this.$router.push('/task/myMessage');
  144.     },
  145.     /**word预览组件回调函数 */
  146.     renderedHandler() {
  147.       console.log('渲染完成');
  148.     },
  149.     errorHandler() {
  150.       console.log('渲染失败');
  151.     },
  152.     /** 查询是否存在未读消息 根据当前用户匹配消息表中得ID  */
  153.     getUnRead() {
  154.       this.queryParams.id = this.id;
  155.       // 查询未读消息
  156.       listSysmessage(this.queryParams).then((res) => {
  157.         if (res.code == 200) {
  158.           if (res.rows.length > 0) {
  159.             // 这里的total  要请求我的代办的接口 然后加起来
  160.             this.total = res.total;
  161.             this.noticeList = res.rows;
  162.             this.$store.dispatch('app/setIsDot', true);
  163.           } else {
  164.             this.total = null;
  165.             this.noticeList = [];
  166.             this.$store.dispatch('app/setIsDot', false);
  167.           }
  168.           this.$emit('getUnRead', this.noticeList);
  169.         }
  170.       });
  171.     },
  172.     //查询未读消息重构 添加定时任务 每隔20分钟调用一次
  173.     /** 核心查询方法 */
  174.     async getUnReadNew() {
  175.       try {
  176.         const params = {
  177.           id: this.id, // 用户ID
  178.           status:0,
  179.         }
  180.         const { code, rows, total } = await listSysmessage(params)
  181.         if (code === 200) {
  182.           this.handleNewMessages(rows, total)
  183.           this.lastCheckTime = new Date()
  184.         }
  185.       } catch (error) {
  186.         console.error('消息检查失败:', error)
  187.       }
  188.     },
  189.     /** 处理新消息逻辑 */
  190.     handleNewMessages(rows, total) {
  191.       // 数据同步
  192.       this.noticeListNew = rows
  193.       this.totalNew = rows.length//total
  194.       // 仅当有新消息时触发通知
  195.       if (rows.length > 0) {
  196.         if (this.notificationInstance) {
  197.           // 手动创建组件实例
  198.           // 通过 key 变化强制更新组件
  199.           this.notificationKey = Date.now()
  200.           // const NotificationComponent = new Vue({
  201.           //   render: h => h(CustomNotification, {
  202.           //     props: {
  203.           //       noticeList: [...this.noticeListNew],
  204.           //       total: this.noticeListNew.length
  205.           //     },
  206.           //     on: {
  207.           //       // 事件监听...
  208.           //     }
  209.           //   })
  210.           // }).$mount()
  211.           // // 保存组件实例引用
  212.           // this.customNotificationInstance = NotificationComponent.$children[0]
  213.           // this.customNotificationInstance = this.notificationInstance.$children[0]
  214.           //已有弹窗时仅更新数据
  215.           this.customNotificationInstance.$set(
  216.             this.customNotificationInstance,
  217.             'noticeList',
  218.             [...rows]
  219.           )
  220.           this.customNotificationInstance.$forceUpdate()
  221.          } else {
  222.           this.showNotification()
  223.          }
  224.       }
  225.       this.$emit('update:noticeList', rows)
  226.       window.clearInterval(this.pollInterval)
  227.       this.setupPolling()// 启动轮询 后台发送消息时 自动触发
  228.     },
  229.     /** 判断是否有新消息 */
  230.     hasNewMessages(newRows) {
  231.       return newRows.some(item =>
  232.         !this.noticeListNew.find(old => old.messageId === item.messageId)
  233.       )
  234.     },
  235.     /** 轮询控制 */
  236.     setupPolling() {
  237.       // 5分钟调用一次 60000 * 5 300000
  238.       this.clearPolling() // 清除已有定时器
  239.       this.pollInterval = window.setInterval(() => {
  240.         this.getUnReadNew()
  241.       },300000)
  242.     },
  243.     /** 销毁定时器*/
  244.     clearPolling() {
  245.       if (this.pollInterval) {
  246.         window.clearInterval(this.pollInterval)
  247.         this.pollInterval = null
  248.       }
  249.     },
  250.     bellClick() {
  251.       this.getUnRead();
  252.     },
  253.     cancel() {
  254.       this.open = false;
  255.       this.getUnRead();
  256.     },
  257.     cancelTempDialog() {
  258.       this.templateVisible = false;
  259.       this.getUnRead();
  260.     },
  261.     // 查看更多
  262.     showAll() {
  263.       this.$router.push({ path: '/monitor/myMessage' });
  264.     },
  265.     //查看消息 弹窗显示
  266.     handleRead(data) {
  267.       const messageId = data.messageId;
  268.       getSysmessage(messageId).then((response) => {
  269.         this.form = response.data;
  270.         // this.form.messageTitle = data.messageTitle
  271.         // this.form.messageContent = data.messageContent
  272.         if (this.form.fileJSON && JSON.parse(this.form.fileJSON)) {
  273.           this.fileList = JSON.parse(this.form.fileJSON);
  274.         } else {
  275.           this.fileList = [];
  276.         }
  277.         if (this.form.messageType === '3') {
  278.           this.templateVisible = true;
  279.         } else {
  280.           this.open = true;
  281.           this.title = '查看我的消息';
  282.         }
  283.       });
  284.     },
  285.     toLink(url) {
  286.       if (url) {
  287.         if (url.indexOf('http://') > -1 || url.indexOf('https://') > -1) {
  288.           window.open(url);
  289.         } else {
  290.           this.$router.push({ path: url });
  291.         }
  292.       }
  293.       this.cancelTempDialog();
  294.     },
  295.     handleDownLoad(index, file) {
  296.       const param = {
  297.         code: file.code,
  298.         fileName: file.name
  299.       };
  300.       fileDownload(param)
  301.         .then((response) => {
  302.           if (response) {
  303.             const url = window.URL.createObjectURL(new Blob([response]));
  304.             const link = document.createElement('a');
  305.             link.href = url;
  306.             link.setAttribute('download', file.name); // 设置下载的文件名
  307.             document.body.appendChild(link);
  308.             link.click();
  309.             document.body.removeChild(link);
  310.           }
  311.         })
  312.         .catch((error) => {
  313.         });
  314.     },
  315.     //  预览
  316.     async handleShow(index, file) {
  317.       const param = {
  318.         code: file.code,
  319.         fileName: file.name
  320.       };
  321.       const type = file.name.split('.')[file.name.split('.').length - 1];
  322.       await fileDownload(param)
  323.         .then(async (response) => {
  324.           if (type === 'pdf' || type === 'PDF') {
  325.             //pdf预览
  326.             let blob = new Blob([response], {
  327.               type: 'application/pdf'
  328.             });
  329.             let fileURL = window.URL.createObjectURL(blob);
  330.             window.open(fileURL, '_blank'); //这里是直接打开新窗口
  331.           } else if (type === 'txt' || type === 'TXT') {
  332.             //txt预览
  333.             // 将文件流转换为文本
  334.             const text = await response.text();
  335.             // 在新窗口中打开文本内容
  336.             const newWindow = window.open();
  337.             newWindow.document.write(`<pre>${text}</pre>`);
  338.           } else if (type === 'xls' || type === 'xlsx') {
  339.             //excel预览
  340.             // 将文件流转换为ArrayBuffer
  341.             const arrayBuffer = await response.arrayBuffer();
  342.             // 使用xlsx插件解析ArrayBuffer为Workbook对象
  343.             const workbook = XLSX.read(arrayBuffer, { type: 'array' });
  344.             // 获取第一个Sheet
  345.             const sheetName = workbook.SheetNames[0];
  346.             const sheet = workbook.Sheets[sheetName];
  347.             // 将Sheet转换为HTML表格
  348.             const html = XLSX.utils.sheet_to_html(sheet);
  349.             // 添加表格线样式
  350.             const styledHtml = `
  351.             <style>
  352.             table {
  353.               border-collapse: collapse;
  354.             }
  355.             td, th {
  356.               border: 1px solid black;
  357.               padding: 8px;
  358.             }
  359.             </style>
  360.             ${html}
  361.             `;
  362.             // 在新窗口中打开HTML内容
  363.             const newWindow = window.open();
  364.             setTimeout(() => {
  365.               newWindow.document.title = sheetName;
  366.             }, 0);
  367.             newWindow.document.write(styledHtml);
  368.           } else if (type === 'doc' || type === 'docx') {
  369.             if (type === 'doc') {
  370.               // doc预览 需要转码 定时任务
  371.               this.handleMany(file.code,type)
  372.             }else{
  373.               // docx预览
  374.               const fileUrl = window.URL.createObjectURL(response);
  375.               this.previewWordOffice = fileUrl;
  376.               this.dialogVisibleWord = true;
  377.             }
  378.           }
  379.           else if (type === 'png' || type === 'jpg') {
  380.             const fileURL = window.URL.createObjectURL(response);
  381.             this.qrCode = fileURL;
  382.             this.dialogVisible = true;
  383.             console.log(fileURL, 'fileURL的值为-----------');
  384.             this.saveFile = file;
  385.           }
  386.         })
  387.         .catch((error) => {});
  388.     },
  389.     //  doc 预览
  390.     handleMany(code,type) {
  391.       previewDocumentAPI({code: code}).then(response => {
  392.         let fileURL
  393.         fileURL = this.baseUrl + response.msg
  394.         if (type === 'doc' || type === 'docx') {
  395.           this.docSrc = fileURL
  396.           this.DocSync = true
  397.         }
  398.       })
  399.     },
  400.     showNotification() {
  401.       // 如果已有通知实例且未关闭,先关闭
  402.       if (this.notificationInstance) {
  403.         this.$notify.closeAll()
  404.       }
  405.       const h = this.$createElement
  406.       const notificationNode = h(CustomNotification, {
  407.         key: this.notificationKey, // 添加唯一key
  408.         props: {
  409.           noticeList: [...this.noticeListNew], // 传递消息列表
  410.           total:this.noticeListNew.length
  411.         },
  412.         on: {
  413.           // 添加事件监听
  414.           'update-list': this.handleListUpdate,
  415.           'close-notification': () => this.$notify.closeAll(),
  416.           'later': () => {
  417.             this.$notify.closeAll()
  418.           },
  419.           'ignore-all': (localNoticeList) => {
  420.             const msgList = localNoticeList
  421.             msgList & msgList.forEach((item)=>{
  422.               this.readMessageAll(item.messageId)
  423.             })
  424.             this.$notify.closeAll()
  425.             this.getUnRead()
  426.           },
  427.           'accept': () => {
  428.             console.log('接受处理逻辑')
  429.           },
  430.           close: () => {
  431.             this.notificationInstance = null
  432.           },
  433.           'gotoMessageList': (msgId) => {
  434.             this.readMessage(msgId)
  435.             this.getUnRead()
  436.             //阅读了那一条 根据ID匹配然后进行过滤
  437.             this.noticeListNew = this.noticeListNew.filter(item=> item.messageId !== Number(msgId))
  438.             if(this.noticeListNew.length > 0){
  439.               this.customNotificationInstance.$set(
  440.                 this.customNotificationInstance,
  441.                 'noticeList',
  442.                 [...this.noticeListNew]
  443.               )
  444.               this.customNotificationInstance.$forceUpdate()
  445.             }else{
  446.               this.$notify.closeAll()
  447.             }
  448.           }
  449.         }
  450.       })
  451.       this.notificationInstance = this.$notify.info({
  452.         title: '消息通知',
  453.         message: notificationNode,
  454.         customClass:'bellClass',
  455.         position: 'bottom-right',
  456.         duration:60000,
  457.         onClose: () => {
  458.           this.notificationInstance = null
  459.         }
  460.       });
  461.       // 获取组件实例
  462.       this.customNotificationInstance = notificationNode.componentInstance
  463.     },
  464.     // 处理列表更新事件
  465.     handleListUpdate(newList) {
  466.       this.noticeListNew = newList
  467.     },
  468.     //查看消息 弹窗显示
  469.     readMessage(msgId) {
  470.       const messageId = msgId;
  471.       getSysmessage(messageId).then((response) => {
  472.         this.messageVisible = true
  473.         this.msg = response.data;
  474.         // this.form.messageTitle = data.messageTitle
  475.         // this.form.messageContent = data.messageContent
  476.         if (this.msg.fileJSON && JSON.parse(this.msg.fileJSON)) {
  477.           this.fileList = JSON.parse(this.msg.fileJSON);
  478.         } else {
  479.           this.fileList = [];
  480.         }
  481.       });
  482.     },
  483.     //批量已读
  484.     readMessageAll(msgId) {
  485.       const messageId = msgId;
  486.       getSysmessage(messageId).then((response) => {
  487.       });
  488.     },
  489.     getFileExtension(filename) {
  490.       // 获取最后一个点的位置
  491.       const lastDotIndex = filename.lastIndexOf('.')
  492.       // 如果没有点或者点在第一个位置,返回空字符串
  493.       if (lastDotIndex === -1 || lastDotIndex === 0) {
  494.         return ''
  495.       }
  496.       // 截取点后的字符串作为后缀
  497.       return filename.substring(lastDotIndex + 1)
  498.     },
  499.     closeMsgModel(){
  500.       this.messageVisible = false
  501.     }
  502.   }
  503. };
  504. </script>
  505. <style rel="stylesheet/scss" lang="scss" scoped>
  506. .my-message {
  507.   ::v-deep .el-checkbox__label {
  508.     vertical-align: middle;
  509.   }
  510.   &__editor {
  511.     ::v-deep .ql-toolbar {
  512.       display: none;
  513.     }
  514.     ::v-deep .ql-container {
  515.       // border-top: 1px solid #ccc !important;
  516.       border: none !important;
  517.     }
  518.     ::v-deep .ql-editor {
  519.       max-height: 500px;
  520.     }
  521.   }
  522.   &__ul {
  523.     list-style-type: none;
  524.     // border: 1px solid #ccc;
  525.     // border-radius: 5px;
  526.   }
  527.   &__filebox {
  528.     margin-top: 10px;
  529.     padding-left: 20px;
  530.     padding-right: 20px;
  531.     background: #e6f7ff;
  532.     border-radius: 5px;
  533.   }
  534.   &__dialog {
  535.     ::v-deep .el-dialog__body {
  536.       padding-bottom: 0px !important;
  537.     }
  538.   }
  539.   &__li {
  540.     width: 100%;
  541.     display: flex;
  542.     justify-content: space-between;
  543.     margin-bottom: 5px;
  544.     &--opt {
  545.       padding-right: 10px;
  546.     }
  547.   }
  548. }
  549. ::v-deep .el-badge__content.is-fixed {
  550.   transform: translateY(-22%) translateX(100%);
  551. }
  552. ::v-deep .el-badge__content {
  553.   font-size: 11px;
  554.   padding: 0 5px;
  555. }
  556. ::v-deep .is-fullscreen {
  557.   .el-dialog__body {
  558.     /* padding: 15px 20px !important; */
  559.     color: #606266;
  560.     font-size: 14px;
  561.     word-break: break-all;
  562.     height: calc(100vh - 40px);
  563.     overflow: auto;
  564.   }
  565. }
  566. </style>
  567. <style>
  568.   .bellClass .el-notification__icon::before {
  569.     content: '\e7ba'; /* 需要更换的图标编码 */
  570.     color: #8BC34A; /* 图标颜色 */
  571.   }
  572.   .bellClass {
  573.     /*border: 1px solid #8bc34a57; !* 修改边框样式 f55e00 *!*/
  574.     box-shadow: 0 2px 10px 0 rgb(0 0 0 / 48%) !important;
  575.   }
  576.    .el-notification__title {
  577.     color: #000; /* 修改标题字体颜色 */
  578.     font-size:12px;
  579.     font-weight: 100;
  580.   }
  581.   .bellClass .el-notification__icon {
  582.     height: 20px;
  583.     width: 20px;
  584.     font-size: 18px;
  585.     transform: translateY(-2px);
  586.   }
  587.   .bellClass .el-notification__group {
  588.     margin-left: 8px;
  589.     margin-right: 8px;
  590.   }
  591. </style>
复制代码
焦点代码:
这个表现关照的焦点方法, 自界说消息组件 通过$createElement创建Vnode挂载到message中,
数据转达的话通过props转达,通过on自界说变乱
  1.     showNotification() {
  2.       // 如果已有通知实例且未关闭,先关闭
  3.       if (this.notificationInstance) {
  4.         this.$notify.closeAll()
  5.       }
  6.       const h = this.$createElement
  7.       const notificationNode = h(CustomNotification, {
  8.         key: this.notificationKey, // 添加唯一key
  9.         props: {
  10.           noticeList: [...this.noticeListNew], // 传递消息列表
  11.           total:this.noticeListNew.length
  12.         },
  13.         on: {
  14.           // 添加事件监听
  15.           'update-list': this.handleListUpdate,
  16.           'close-notification': () => this.$notify.closeAll(),
  17.           'later': () => {
  18.             this.$notify.closeAll()
  19.           },
  20.           'ignore-all': (localNoticeList) => {
  21.             const msgList = localNoticeList
  22.             msgList & msgList.forEach((item)=>{
  23.               this.readMessageAll(item.messageId)
  24.             })
  25.             this.$notify.closeAll()
  26.             this.getUnRead()
  27.           },
  28.           'accept': () => {
  29.             console.log('接受处理逻辑')
  30.           },
  31.           close: () => {
  32.             this.notificationInstance = null
  33.           },
  34.           'gotoMessageList': (msgId) => {
  35.             this.readMessage(msgId)
  36.             this.getUnRead()
  37.             //阅读了那一条 根据ID匹配然后进行过滤
  38.             this.noticeListNew = this.noticeListNew.filter(item=> item.messageId !== Number(msgId))
  39.             if(this.noticeListNew.length > 0){
  40.               this.customNotificationInstance.$set(
  41.                 this.customNotificationInstance,
  42.                 'noticeList',
  43.                 [...this.noticeListNew]
  44.               )
  45.               this.customNotificationInstance.$forceUpdate()
  46.             }else{
  47.               this.$notify.closeAll()
  48.             }
  49.           }
  50.         }
  51.       })
  52.       this.notificationInstance = this.$notify.info({
  53.         title: '消息通知',
  54.         message: notificationNode,
  55.         customClass:'bellClass',
  56.         position: 'bottom-right',
  57.         duration:60000,
  58.         onClose: () => {
  59.           this.notificationInstance = null
  60.         }
  61.       });
  62.       // 获取组件实例
  63.       this.customNotificationInstance = notificationNode.componentInstance
  64.     },
复制代码

获取当前弹窗的实例时数据通讯的关键! 
  1.     /** 处理新消息逻辑 */
  2.     handleNewMessages(rows, total) {
  3.       // 数据同步
  4.       this.noticeListNew = rows
  5.       this.totalNew = rows.length//total
  6.       // 仅当有新消息时触发通知
  7.       if (rows.length > 0) {
  8.         if (this.notificationInstance) {
  9.           // 手动创建组件实例
  10.           // 通过 key 变化强制更新组件
  11.           this.notificationKey = Date.now()
  12.           // const NotificationComponent = new Vue({
  13.           //   render: h => h(CustomNotification, {
  14.           //     props: {
  15.           //       noticeList: [...this.noticeListNew],
  16.           //       total: this.noticeListNew.length
  17.           //     },
  18.           //     on: {
  19.           //       // 事件监听...
  20.           //     }
  21.           //   })
  22.           // }).$mount()
  23.           // // 保存组件实例引用
  24.           // this.customNotificationInstance = NotificationComponent.$children[0]
  25.           // this.customNotificationInstance = this.notificationInstance.$children[0]
  26.           //已有弹窗时仅更新数据
  27.           this.customNotificationInstance.$set(
  28.             this.customNotificationInstance,
  29.             'noticeList',
  30.             [...rows]
  31.           )
  32.           this.customNotificationInstance.$forceUpdate()
  33.          } else {
  34.           this.showNotification()
  35.          }
  36.       }
  37.       this.$emit('update:noticeList', rows)
  38.       window.clearInterval(this.pollInterval)
  39.       this.setupPolling()// 启动轮询 后台发送消息时 自动触发
  40.     },
复制代码
已有弹窗只更新数据 不弹窗 

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表