Browse Source

新增消息通知

wangzhiqiang 3 months ago
parent
commit
5ca248674a
3 changed files with 212 additions and 1 deletions
  1. 19 1
      src/api/dashboard.js
  2. 190 0
      src/layout/Header/functionList/notices.vue
  3. 3 0
      src/layout/Header/index.vue

+ 19 - 1
src/api/dashboard.js

@@ -34,4 +34,22 @@ export function getTopCount(params) {
         method: 'get',
         params
     })
-}
+}
+
+// 查询我的未读通知
+export function unreadMessage(params) {
+    return request({
+        url: '/agent-service/index/unreadMessage',
+        method: 'get',
+        params
+    })
+}
+
+// 标记为已读
+export function markRead(params) {
+    return request({
+        url: '/agent-service/index/markRead',
+        method: 'get',
+        params
+    })
+}

+ 190 - 0
src/layout/Header/functionList/notices.vue

@@ -0,0 +1,190 @@
+<template>
+    <el-dropdown trigger="click" size="medium">
+        <span class="el-dropdown-link">
+            <el-badge :value="unreadData.length" class="badge" type="primary">
+                <el-icon size="16">
+                    <Bell />
+                </el-icon>
+            </el-badge>
+        </span>
+        <template #dropdown>
+            <el-dropdown-menu class="dropdown">
+                <el-dropdown-item>
+                    <div class="read" @click="oneKeyRead">
+                        一键已读
+                    </div>
+                </el-dropdown-item>
+                <el-dropdown-item divided v-for="item in messageData" :key="item.messageId"
+                    :disabled="item.messageStatus === 1" @click="handleMarkRead(item.messageId)">
+                    <div class="dropdown_icon" :style="{ color: item.messageStatus === 1 ? '#c0c4cc' : null }">
+                        {{ getDictionaryName("message_type", item.messageType) }}
+                    </div>
+                    <div class="dropdown_item">
+                        <div class="dropdown_item_main">
+                            <div class="dropdown_item_title no-ellipsis">
+                                {{ item.messageTitle }}
+                            </div>
+                            <div class="dropdown_item_text no-ellipsis">
+                                {{ item.messageContent }}
+                            </div>
+                            <div class="dropdown_item_time">{{ convertUTCToBeijing(item.sendTime) }}</div>
+                        </div>
+                        <div class="dropdown_item_btn" v-if="item.messageStatus === 0">
+                            标记已读
+                        </div>
+                    </div>
+                </el-dropdown-item>
+            </el-dropdown-menu>
+        </template>
+    </el-dropdown>
+</template>
+
+<script setup>
+import { ref, onBeforeMount } from 'vue'
+import { Bell } from '@element-plus/icons'
+import { unreadMessage, markRead } from '@/api/dashboard.js'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { convertUTCToBeijing } from '@/utils/index.js'
+import { useGetDictList } from '@/hooks/useGetDictList.js'
+
+const { dictData, loadDictData, getOptions, getDictionaryName } = useGetDictList();
+const messageId = ref('')
+const messageData = ref([]) //消息总数据
+const unreadData = ref([]) // 未读消息数据
+
+/**
+ * 获取信息公告
+ * messageStatus 消息状态 0-未读完 1-已读完
+ * messageType 消息类型 1-公告 2-系统通知 3-运营活动 4-温馨提醒
+ */
+const getMessage = async () => {
+    const res = await unreadMessage()
+    if (res.data) {
+        // 总消息
+        messageData.value = res.data.reverse()
+        // 未读消息
+        unreadData.value = messageData.value.filter(item => item.messageStatus === 0);
+        // 公告消息
+        const noticeData = unreadData.value.filter(item => item.messageType === 1);
+        if (noticeData.length > 0) {
+            const { messageTitle, messageContent } = noticeData[0]
+            messageId.value = noticeData[0].messageId
+            // 通知弹窗
+            notice(messageContent, messageTitle)
+        }
+    }
+}
+
+// 改为已读
+const isReading = ref(false)
+const handleMarkRead = async (messageId) => {
+    if (isReading.value) return
+    isReading.value = true
+    try {
+        await markRead({ messageId })
+        await getMessage()
+    } catch (e) {
+        console.log('请求失败', e)
+    } finally {
+        isReading.value = false
+    }
+}
+
+// 一键已读 - 并发执行
+const oneKeyRead = async () => {
+    if (unreadData.value.length === 0) return
+    try {
+        await Promise.all(
+            unreadData.value.map(item => markRead({ messageId: item.messageId }))
+        )
+        await getMessage()
+        ElMessage.success('全部标记为已读')
+    } catch (e) {
+        ElMessage.error('一键已读失败')
+        console.error('一键已读失败:', e)
+    }
+}
+
+// 公告弹窗
+const notice = async (message, title) => {
+    ElMessageBox.alert(message, title, {
+        confirmButtonText: '知道了',
+        callback: (action) => {
+            handleMarkRead(messageId.value)
+        },
+    })
+}
+
+onBeforeMount(() => {
+    loadDictData()
+    getMessage()
+})
+
+</script>
+
+<style lang="scss" scoped>
+.el-dropdown-link {
+    .badge {
+        margin-top: 2px;
+        margin-right: 20px;
+    }
+}
+
+.dropdown {
+    max-height: 70vh;
+    overflow-y: auto;
+
+    .read {
+        margin-left: auto;
+        font-weight: bold;
+        color: var(--system-primary-color);
+        cursor: pointer;
+    }
+
+    .dropdown_icon {
+        width: 55px;
+        height: 55px;
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 12px;
+        margin-right: 10px;
+        color: var(--system-primary-color);
+        box-shadow: 0 4px 5px rgba(0, 0, 0, 0.08), 0 0 6px rgba(0, 0, 0, 0.1);
+    }
+
+    .dropdown_item {
+        display: flex;
+        align-items: center;
+        flex: 1;
+
+        .dropdown_item_main {
+            .dropdown_item_title {
+                font-weight: 600;
+            }
+
+            .dropdown_item_text {
+                font-weight: 400;
+            }
+
+            .dropdown_item_time {
+                font-size: 14px;
+            }
+        }
+
+        .dropdown_item_btn {
+            margin-left: 10px;
+            width: 60px;
+            color: var(--system-primary-color);
+        }
+
+        .no-ellipsis {
+            overflow: visible;
+            text-overflow: initial;
+            white-space: normal;
+            word-break: break-word;
+        }
+    }
+}
+</style>

+ 3 - 0
src/layout/Header/index.vue

@@ -10,6 +10,7 @@
     <div class="right-box">
       <!-- 快捷功能按钮 -->
       <div class="function-list">
+        <div class="function-list-item"><Notices /></div>
         <div class="function-list-item hidden-sm-and-down"><Full-screen /></div>
         <div class="function-list-item">
           <SizeChange />
@@ -46,6 +47,7 @@
   import { defineComponent, computed, reactive } from 'vue'
   import { useStore } from 'vuex'
   import { useRouter, useRoute } from 'vue-router'
+  import Notices from './functionList/notices.vue'
   import FullScreen from './functionList/fullscreen.vue'
   import SizeChange from './functionList/sizeChange.vue'
   import Github from './functionList/github.vue'
@@ -54,6 +56,7 @@
   import PasswordLayer from './passwordLayer.vue'
   export default defineComponent({
     components: {
+      Notices,
       FullScreen,
       Breadcrumb,
       SizeChange,