|
|
@@ -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>
|