Sfoglia il codice sorgente

对接消息接口

Fan 3 settimane fa
parent
commit
86a98af83a

+ 2 - 0
ui/smarttrade-platform/.env.development

@@ -1,2 +1,4 @@
 # 开发环境后台接口地址
 VITE_API_BASE_URL=http://localhost:10010/
+
+VITE_API_APP_ID=7

+ 2 - 0
ui/smarttrade-platform/.env.production

@@ -1,2 +1,4 @@
 # 生产环境后台接口地址
 VITE_API_BASE_URL=/api
+
+VITE_API_APP_ID=7

+ 9 - 0
ui/smarttrade-platform/package-lock.json

@@ -11,6 +11,7 @@
         "@fortawesome/fontawesome-free": "^6.5.1",
         "axios": "^1.6.7",
         "element-plus": "^2.14.2",
+        "moment": "^2.30.1",
         "pinia": "^2.1.7",
         "vue": "^3.4.21",
         "vue-router": "^4.3.0"
@@ -1513,6 +1514,14 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/moment": {
+      "version": "2.30.1",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
+      "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",

+ 1 - 0
ui/smarttrade-platform/package.json

@@ -12,6 +12,7 @@
     "@fortawesome/fontawesome-free": "^6.5.1",
     "axios": "^1.6.7",
     "element-plus": "^2.14.2",
+    "moment": "^2.30.1",
     "pinia": "^2.1.7",
     "vue": "^3.4.21",
     "vue-router": "^4.3.0"

+ 6 - 1
ui/smarttrade-platform/src/api/layout/index.js

@@ -1,6 +1,11 @@
 import { get, post, put, remove, upload } from '@/utils/request'
 
-export const getNoReadCount = () => post('/router/rest/sys/message/getNoReadCountByApp', {appId: 7})
+export const getNoReadCount = () => post('/router/rest/sys/message/getNoReadCount', {appId: import.meta.env.VITE_API_APP_ID})
+export const getMessageList = (data) => post('/router/rest/sys/message/pageList', data)
+export const updateRead = (data) => post('/router/rest/sys/message/read', data)
+export const updateReadAll = (data) => post('/router/rest/sys/message/readAll', data)
+export const listPageBuUserSet = (data) => post('/router/rest/sys/message/config/listPage', data)
+export const setMessageConfig = (data) => post('/router/rest/sys/message/config/setMessageConfig', data)
 export const getUserInfo = () => post('/router/rest/sys/auth/getCurrentUserInfo')
 export const updateUserPwd = (data) => post('/router/rest/sys/auth/modifyPass', data)
 export const updateRemark = (data) => post('/router/rest/sys/auth/updateRemark', data)

+ 13 - 3
ui/smarttrade-platform/src/components/layout/Sidebar.vue

@@ -330,6 +330,7 @@
 import { ref, onMounted } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { getUserInfo, updateUserPwd, getLoginData, updateRemark } from '@/api/layout'
+import { ElMessageBox } from 'element-plus'
 
 const route = useRoute()
 const router = useRouter()
@@ -380,9 +381,18 @@ const toggleTheme = () => {
 }
 
 const handleLogout = () => {
-  showUserMenu.value = false
-  // Handle logout
-  console.log('Logout')
+  ElMessageBox.confirm(
+    '确定要退出登录吗?',
+    '提示',
+    {
+      confirmButtonText: '确认',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  ).then(() => {
+    localStorage.clear()
+    router.push({ path: '/login' })
+  })
 }
 
 const pwdForm = ref({

+ 162 - 245
ui/smarttrade-platform/src/components/layout/TopBar.vue

@@ -28,7 +28,7 @@
       <!-- Notifications -->
       <div class="action-btn notification-btn" @click="toggleNotifications" :class="{ active: showNotifications }">
         <i class="fas fa-bell"></i>
-        <span v-if="unreadCount > 0" class="notification-badge">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>
+        <span v-if="noReadCount > 0" class="notification-badge">{{ noReadCount > 99 ? '99+' : noReadCount }}</span>
       </div>
 
       <!-- Help -->
@@ -45,11 +45,11 @@
           <div class="panel-title">
             <i class="fas fa-bell"></i>
             消息中心
-            <span class="unread-count">{{ unreadCount }}条未读</span>
+            <span class="unread-count" v-if="noReadCount > 0">{{ noReadCount }}条未读</span>
           </div>
           <div class="panel-actions">
             <button class="action-text" @click="markAllAsRead">全部已读</button>
-            <button class="action-text" @click="showSettings = true">
+            <button class="action-text" @click="openSettings">
               <i class="fas fa-cog"></i>
             </button>
           </div>
@@ -59,14 +59,13 @@
         <div class="panel-tabs">
           <div 
             v-for="tab in notificationTabs" 
-            :key="tab.key"
+            :key="tab.messageType"
             class="panel-tab"
-            :class="{ active: activeTab === tab.key }"
-            @click="activeTab = tab.key"
+            :class="{ active: activeTab === tab.messageType }"
+            @click="activeTab = tab.messageType"
           >
-            <i :class="tab.icon"></i>
-            {{ tab.label }}
-            <span v-if="tab.count > 0" class="tab-count">{{ tab.count }}</span>
+            {{ tab.messageTypeName }}
+            <span v-if="tab.stateNumber > 0" class="tab-count">{{ tab.stateNumber > 99 ? '99+' : tab.stateNumber }}</span>
           </div>
         </div>
 
@@ -77,30 +76,23 @@
               v-for="notification in filteredNotifications" 
               :key="notification.id"
               class="notification-item"
-              :class="{ unread: !notification.read, [notification.type]: true }"
+              :class="{ unread: !notification.isRead }"
               @click="handleNotificationClick(notification)"
             >
-              <div class="notification-icon" :style="{ background: getIconBg(notification.type), color: getIconColor(notification.type) }">
-                <i :class="notification.icon"></i>
+              <div class="notification-icon" :style="{ background: getIconBg('reply'), color: getIconColor('reply') }">
+                <i class="fas fa-reply"></i>
               </div>
               <div class="notification-content">
                 <div class="notification-title">{{ notification.title }}</div>
-                <div class="notification-desc">{{ notification.description }}</div>
+                <div class="notification-desc">{{ notification.content }}</div>
                 <div class="notification-meta">
                   <span class="notification-time">{{ notification.time }}</span>
-                  <span v-if="notification.source" class="notification-source">
-                    <i :class="notification.sourceIcon"></i>
-                    {{ notification.source }}
-                  </span>
                 </div>
               </div>
               <div class="notification-actions">
-                <button v-if="!notification.read" class="mark-read-btn" @click.stop="markAsRead(notification.id)">
+                <button v-if="!notification.isRead" class="mark-read-btn" @click.stop="markAsRead(notification)">
                   <i class="fas fa-check"></i>
                 </button>
-                <button class="more-btn" @click.stop="showNotificationMenu($event, notification)">
-                  <i class="fas fa-ellipsis-v"></i>
-                </button>
               </div>
             </div>
           </template>
@@ -114,9 +106,7 @@
 
         <!-- Panel Footer -->
         <div class="panel-footer">
-          <button class="btn btn-secondary btn-sm" @click="viewAllNotifications">
-            <i class="fas fa-list"></i> 查看全部消息
-          </button>
+          <div></div>
           <button class="btn btn-primary btn-sm" @click="showNotifications = false">
             关闭
           </button>
@@ -224,8 +214,8 @@
         <div class="modal notification-detail-modal">
           <div class="modal-header">
             <div class="modal-title">
-              <div class="title-icon" :style="{ background: getIconBg(selectedNotification.type), color: getIconColor(selectedNotification.type) }">
-                <i :class="selectedNotification.icon"></i>
+              <div class="title-icon" :style="{ background: getIconBg('reply'), color: getIconColor('reply') }">
+                <i class="fas fa-reply"></i>
               </div>
               <span>{{ selectedNotification.title }}</span>
             </div>
@@ -238,7 +228,7 @@
               <i class="fas fa-clock"></i>
               {{ selectedNotification.time }}
             </div>
-            <div class="detail-content" v-html="selectedNotification.detail"></div>
+            <div class="detail-content" v-html="selectedNotification.content"></div>
             
             <!-- Quick Actions -->
             <div v-if="selectedNotification.actions" class="detail-actions">
@@ -580,27 +570,38 @@
   <AddMarketing ref="addMarketingRef" />
 
   <div v-if="showSettings" class="modal-overlay" @click.self="showSettings = false">
-    <div class="modal create-modal">
+    <div class="modal create-modal" style="max-width: 800px;">
       <div class="modal-header">
           <div class="modal-title"><i class="fas fa-bell"></i> 通知设置</div>
           <button class="modal-close" @click="showSettings = false"><i class="fas fa-times"></i></button>
       </div>
       <div class="modal-body">
         <div class="settings-list">
-          <div class="settings-item" style="padding-top: 0;">
-            <div class="item-icon" style="background: rgba(99, 102, 241, 0.2); color: var(--primary);">
+          <div class="settings-item" v-for="item in settingsData">
+            <!-- <div class="item-icon" style="background: rgba(99, 102, 241, 0.2); color: var(--primary);">
               <i class="fas fa-envelope"></i>
-            </div>
+            </div> -->
             <div class="item-content">
-              <div class="item-title">邮件通知</div>
-              <div class="item-desc">重要通知发送到邮箱</div>
+              <div class="item-title">{{ item.templateServiceName }}</div>
+              <div class="item-desc">{{ item.eventName }}</div>
             </div>
             <div class="item-action">
-              <el-switch v-model="settings.emailNotify" style="--el-switch-on-color: #13ce66;" />
+              <div>
+                <span>企微消息:</span>
+                <el-switch v-model="item.wecom" @change="changeSetting(item, 'wecom')" />
+              </div>
+              <div>
+                <span>站内信:</span>
+                <el-switch v-model="item.site" @change="changeSetting(item, 'site')" />
+              </div>
+              <div>
+                <span>邮件:</span>
+                <el-switch v-model="item.mail" @change="changeSetting(item, 'mail')" />
+              </div>
             </div>
           </div>
 
-          <div class="settings-item">
+          <!-- <div class="settings-item">
             <div class="item-icon" style="background: rgba(16, 185, 129, 0.2); color: var(--success);">
               <i class="fas fa-reply"></i>
             </div>
@@ -609,9 +610,20 @@
               <div class="item-desc">客户回复邮件、消息时即时提醒</div>
             </div>
             <div class="item-action">
-              <el-switch v-model="settings.replyNotify" style="--el-switch-on-color: #13ce66;" />
+              <div>
+                <span>企微消息:</span>
+                <el-switch v-model="settings.replyNotify" />
+              </div>
+              <div>
+                <span>站内信:</span>
+                <el-switch v-model="settings.replyNotify" />
+              </div>
+              <div>
+                <span>邮件:</span>
+                <el-switch v-model="settings.replyNotify" />
+              </div>
             </div>
-          </div>
+          </div> -->
         </div>
       </div>
     </div>
@@ -622,7 +634,8 @@
 import { ref, computed, onMounted } from 'vue'
 import { useRoute } from 'vue-router'
 import AddMarketing from '../addMarketing.vue'
-import { getNoReadCount } from '@/api/layout'
+import { getNoReadCount, getMessageList, updateRead, updateReadAll, listPageBuUserSet } from '@/api/layout'
+import moment from 'moment'
 
 const route = useRoute()
 const showQuickActions = ref(false)
@@ -770,9 +783,32 @@ const generateReport = () => {
   alert('报告生成中,完成后将发送至您的邮箱...')
 }
 
+// Notification data
+const notifications = ref([])
 const toggleNotifications = () => {
   showNotifications.value = !showNotifications.value
-  if (showNotifications.value) showHelp.value = false
+  if (showNotifications.value){
+    showHelp.value = false
+    let params = {
+      pageIndex: 1,
+      pageSize: 10000,
+      appId: import.meta.env.VITE_API_APP_ID
+    }
+    getMessageList(params).then(res => {
+      notifications.value = (res.result.records || []).map(item => {
+          // 判断创建时间是不是今天
+          let date = moment(item.createTime).format("YYYY-MM-DD HH:mm:ss")
+          if(date.slice(0, 10) == moment().format("YYYY-MM-DD")){
+              item.time = "今天 " + date.slice(11, 16)
+          }else{
+              item.time = moment(item.createTime).format("MM月DD日 HH:mm")
+          }
+          return item
+      })
+    }).catch(err => {
+      console.error('获取消息列表失败:', err)
+    })
+  }
 }
 
 const toggleHelp = () => {
@@ -780,196 +816,8 @@ const toggleHelp = () => {
   if (showHelp.value) showNotifications.value = false
 }
 
-// Notification data
-const notifications = ref([
-  // 客户回复
-  {
-    id: 1,
-    type: 'reply',
-    icon: 'fas fa-reply',
-    title: 'Riyadh Tech 回复了邮件',
-    description: '对方对您的产品报价表示感兴趣,希望进一步了解交期和付款方式',
-    detail: '<p>客户 Ahmed Al-Rashid 回复了您的报价邮件:</p><blockquote style="border-left:3px solid var(--primary);padding-left:12px;margin:12px 0;color:var(--text-secondary);">您好,我们对贵公司的SSD产品很感兴趣。请问MOQ是多少?交期大概多久?付款方式有哪些?</blockquote><p>建议尽快回复客户,可以提供详细的报价单和公司介绍。</p>',
-    time: '5分钟前',
-    source: '邮件',
-    sourceIcon: 'fas fa-envelope',
-    read: false,
-    actions: [
-      { label: '立即回复', icon: 'fas fa-reply', primary: true },
-      { label: '查看邮件', icon: 'fas fa-envelope-open' },
-    ]
-  },
-  {
-    id: 2,
-    type: 'reply',
-    icon: 'fab fa-whatsapp',
-    title: 'Dubai Storage WhatsApp 已读',
-    description: '您发送的消息已被查看,对方正在输入中...',
-    detail: '<p>客户 Mohammed Khan 已读您的 WhatsApp 消息,显示对方正在输入回复。</p><p>消息内容:关于企业级SSD采购的询价</p>',
-    time: '15分钟前',
-    source: 'WhatsApp',
-    sourceIcon: 'fab fa-whatsapp',
-    read: false
-  },
-  {
-    id: 3,
-    type: 'reply',
-    icon: 'fab fa-linkedin',
-    title: 'LinkedIn 好友请求被接受',
-    description: 'Kuwait Data Systems 的 CIO Faisal 接受了您的好友请求',
-    detail: '<p>Faisal Al-Mutairi (CTO @ Kuwait Data Systems) 接受了您的 LinkedIn 连接请求。</p><p>建议:发送个性化感谢消息,介绍公司和产品。</p>',
-    time: '1小时前',
-    source: 'LinkedIn',
-    sourceIcon: 'fab fa-linkedin',
-    read: true
-  },
-  
-  // 风险预警
-  {
-    id: 4,
-    type: 'risk',
-    icon: 'fas fa-exclamation-triangle',
-    title: '⚠️ 高风险预警:客户信用下调',
-    description: 'ABC Corp 信用评级从 A 下调至 B,建议提高预付款比例',
-    detail: '<p><strong>风险等级:高</strong></p><p>客户 ABC Corp 的信用评级发生变动:</p><ul><li>原评级:A</li><li>新评级:B</li><li>原因:近期财务状况恶化</li></ul><p><strong>建议措施:</strong></p><ul><li>提高预付款比例至 50%</li><li>缩短付款周期</li><li>关注后续订单风险</li></ul>',
-    time: '30分钟前',
-    source: '风控系统',
-    sourceIcon: 'fas fa-shield-alt',
-    read: false,
-    actions: [
-      { label: '查看详情', icon: 'fas fa-info-circle', primary: true },
-      { label: '调整付款条件', icon: 'fas fa-edit' }
-    ]
-  },
-  {
-    id: 5,
-    type: 'risk',
-    icon: 'fas fa-gavel',
-    title: '欧盟能效新规即将生效',
-    description: '2026年7月生效,涉及SSD产品能效认证要求',
-    detail: '<p><strong>法规更新提醒</strong></p><p>欧盟委员会发布新的能效认证要求,将于2026年7月1日正式生效。</p><p><strong>影响范围:</strong></p><ul><li>所有出口欧盟的SSD产品</li><li>需要提供能效测试报告</li><li>认证周期约30天</li></ul><p><strong>建议:</strong>提前准备相关认证材料。</p>',
-    time: '2小时前',
-    source: '市场情报',
-    sourceIcon: 'fas fa-globe',
-    read: false
-  },
-  
-  // AI情报
-  {
-    id: 6,
-    type: 'ai',
-    icon: 'fas fa-robot',
-    title: '🤖 AI发现新商机',
-    description: '识别到新加坡 Digital Hub 近期频繁访问官网定价页面',
-    detail: '<p><strong>AI商机分析报告</strong></p><p>客户行为分析:</p><ul><li>过去7天访问定价页面 12 次</li><li>查看企业级SSD产品详情 8 次</li><li>下载产品手册 2 次</li></ul><p><strong>AI建议:</strong>该客户意向度高,建议尽快主动联系。</p>',
-    time: '45分钟前',
-    source: 'AI大脑',
-    sourceIcon: 'fas fa-brain',
-    read: false,
-    actions: [
-      { label: '立即联系', icon: 'fas fa-phone', primary: true },
-      { label: '发送报价', icon: 'fas fa-file-invoice' }
-    ]
-  },
-  {
-    id: 7,
-    type: 'ai',
-    icon: 'fas fa-lightbulb',
-    title: '💡 AI策略建议',
-    description: '基于近期数据分析,建议调整中东地区邮件发送时间',
-    detail: '<p><strong>策略优化建议</strong></p><p>AI分析了过去30天的邮件数据,发现:</p><ul><li>中东客户最佳回复时段:晚上8-10点</li><li>当前发送时段:上午10点</li><li>预计调整后回复率提升:52%</li></ul><p>是否应用此策略?</p>',
-    time: '3小时前',
-    source: 'AI策略中心',
-    sourceIcon: 'fas fa-lightbulb',
-    read: true,
-    actions: [
-      { label: '应用策略', icon: 'fas fa-check', primary: true },
-      { label: '查看详情', icon: 'fas fa-chart-bar' }
-    ]
-  },
-  
-  // 营销报告
-  {
-    id: 8,
-    type: 'marketing',
-    icon: 'fas fa-chart-line',
-    title: '📊 周度营销报告已生成',
-    description: '本周发送邮件 1,247 封,打开率 42%,回复率 18%',
-    detail: '<p><strong>本周营销数据汇总</strong></p><table style="width:100%;border-collapse:collapse;margin:12px 0;"><tr style="border-bottom:1px solid var(--border)"><td style="padding:8px 0;">邮件发送</td><td style="text-align:right;font-weight:600;">1,247 封</td></tr><tr style="border-bottom:1px solid var(--border)"><td style="padding:8px 0;">打开率</td><td style="text-align:right;font-weight:600;color:var(--success)">42% (+8%)</td></tr><tr style="border-bottom:1px solid var(--border)"><td style="padding:8px 0;">回复率</td><td style="text-align:right;font-weight:600;color:var(--success)">18% (+5%)</td></tr><tr><td style="padding:8px 0;">新增商机</td><td style="text-align:right;font-weight:600;">23 个</td></tr></table><p>详细报告已发送至您的邮箱。</p>',
-    time: '今天 09:00',
-    source: '自动报告',
-    sourceIcon: 'fas fa-file-alt',
-    read: true,
-    actions: [
-      { label: '查看完整报告', icon: 'fas fa-file-pdf', primary: true }
-    ]
-  },
-  {
-    id: 9,
-    type: 'marketing',
-    icon: 'fas fa-check-circle',
-    title: '✅ 营销活动完成',
-    description: '中东潜客开发活动已完成,共触达 156 位客户',
-    detail: '<p><strong>活动执行报告</strong></p><p>活动名称:中东潜客开发</p><p>执行时间:2026-03-12 ~ 2026-03-19</p><p><strong>执行结果:</strong></p><ul><li>目标客户:156 位</li><li>邮件送达:152 封 (97%)</li><li>邮件打开:68 封 (45%)</li><li>客户回复:12 封 (8%)</li><li>意向客户:5 位</li></ul>',
-    time: '昨天 18:30',
-    source: '营销系统',
-    sourceIcon: 'fas fa-paper-plane',
-    read: true
-  },
-  
-  // 寻客通知
-  {
-    id: 10,
-    type: 'prospect',
-    icon: 'fas fa-user-plus',
-    title: '🎯 发现 12 个高匹配潜客',
-    description: '基于您的历史成交客户,AI 推荐 12 个相似潜客',
-    detail: '<p><strong>AI寻客报告</strong></p><p>寻客条件:中东地区 + SSD进口商</p><p><strong>推荐潜客 TOP 3:</strong></p><ol><li>Riyadh Tech Distribution (92分)</li><li>Dubai Storage Solutions (88分)</li><li>Saudi Digital Hub (76分)</li></ol><p>点击查看完整列表。</p>',
-    time: '今天 14:30',
-    source: '自动寻客',
-    sourceIcon: 'fas fa-crosshairs',
-    read: false,
-    actions: [
-      { label: '查看潜客列表', icon: 'fas fa-list', primary: true },
-      { label: '发送营销邮件', icon: 'fas fa-paper-plane' }
-    ]
-  },
-  {
-    id: 11,
-    type: 'prospect',
-    icon: 'fas fa-search',
-    title: '寻客任务更新',
-    description: '欧洲企业级存储寻客任务进度 75%,已发现 45 家目标公司',
-    detail: '<p><strong>任务进度更新</strong></p><p>任务名称:欧洲企业级存储寻客</p><p>当前进度:75%</p><p><strong>已发现:</strong></p><ul><li>目标公司:45 家</li><li>关键人信息:28 位</li><li>高匹配度:12 家</li></ul>',
-    time: '今天 11:20',
-    source: '寻客任务',
-    sourceIcon: 'fas fa-tasks',
-    read: true
-  },
-  
-  // 系统通知
-  {
-    id: 12,
-    type: 'system',
-    icon: 'fas fa-cog',
-    title: '系统更新通知',
-    description: '领存智贸 AI 已更新至 v2.3,新增策略自进化功能',
-    detail: '<p><strong>版本更新 v2.3</strong></p><p><strong>新增功能:</strong></p><ul><li>AI策略自进化 - 自动测试优化营销策略</li><li>智能跟进提醒 - 基于客户行为预测最佳跟进时机</li><li>知识库问答优化 - 支持更多行业知识</li></ul><p><strong>优化:</strong></p><ul><li>邮件生成速度提升 30%</li><li>潜客匹配准确率提升 15%</li></ul>',
-    time: '昨天 10:00',
-    source: '系统',
-    sourceIcon: 'fas fa-server',
-    read: true
-  }
-])
-
 // Computed
-const notificationTabs = computed(() => [
-  { key: 'all', label: '全部', icon: 'fas fa-inbox', count: notifications.value.filter(n => !n.read).length },
-  { key: 'reply', label: '客户回复', icon: 'fas fa-reply', count: notifications.value.filter(n => n.type === 'reply' && !n.read).length },
-  { key: 'marketing', label: '营销报告', icon: 'fas fa-chart-line', count: notifications.value.filter(n => n.type === 'marketing' && !n.read).length }
-])
-
-const unreadCount = computed(() => notifications.value.filter(n => !n.read).length)
+const notificationTabs = ref([])
 
 const filteredNotifications = computed(() => {
   if (activeTab.value === 'all') return notifications.value
@@ -1002,30 +850,81 @@ const getIconColor = (type) => {
 }
 
 const handleNotificationClick = (notification) => {
-  if (!notification.read) {
-    notification.read = true
-  }
+  setRead(notification)
   selectedNotification.value = notification
+  // if(notification.callbackUrl){
+  //     window.open(item.callbackUrl, '_blank')
+  // }
 }
 
-const markAsRead = (id) => {
-  const notification = notifications.value.find(n => n.id === id)
-  if (notification) {
-    notification.read = true
-  }
+const markAsRead = (notification) => {
+  setRead(notification)
 }
 
-const markAllAsRead = () => {
-  notifications.value.forEach(n => n.read = true)
+const setRead = (item) => {
+  if(!item.isRead){
+      updateRead({ messageLogIds: [item.id], appId: import.meta.env.VITE_API_APP_ID }).then(res => {
+        item.isRead = 1
+        getCount()
+        // item.stateNumber --
+      }).catch(err => {
+        ElMessage.error(err.msg);
+      })
+  }
 }
 
-const viewAllNotifications = () => {
-  showNotifications.value = false
-  // Navigate to notifications page
+const markAllAsRead = () => {
+  if(notifications.value.length == 0){
+      ElMessage.error('列表暂无数据');
+      return
+  }
+  updateReadAll({ appId: import.meta.env.VITE_API_APP_ID }).then(res => {
+      if(res.success){
+          ElMessage.success('操作成功');
+          notifications.value.map(item => item.isRead = 1)
+          getCount()
+      }else{
+          ElMessage.error(res.msg);
+      }
+  })
 }
 
-const showNotificationMenu = (event, notification) => {
-  // Show context menu
+const settingsData = ref([])
+const openSettings = () => {
+  listPageBuUserSet({ pageIndex: 1, pageSize: 9999, appId: import.meta.env.VITE_API_APP_ID }).then(res => {
+    settingsData.value = res.result.records.map(item => {
+      item.wecom = handleData('wecom', item)
+      item.site = handleData('site', item)
+      item.mail = handleData('mail', item)
+      return item
+    })
+  })
+  showSettings.value = true
+}
+const handleData = (type, column) => {
+  let enabled = true
+	let templateData = null
+	if(column.userDetails && column.userDetails.length > 0) {
+		templateData = column.userDetails.find(item => item.templateEventId == column.id && item.templateDetailType == type)
+      //找到对应的配置就按照对应的配置显示
+      if(templateData) {
+          enabled = templateData?.enabled
+      }
+  }
+  return enabled
+}
+const changeSetting = (item, type) => {
+  let params = {
+    appId: import.meta.env.VITE_API_APP_ID,
+    templateDetailType: type,
+    templateEventId: item.id,
+    enabled: item[type]
+  }
+  setMessageConfig(params).then(res => {
+    ElMessage.success((item[type] ? '启用' : '禁用') + '成功')
+  }).catch(err => {
+    ElMessage.error(err.msg)
+  })
 }
 
 const handleAction = (action) => {
@@ -1106,10 +1005,19 @@ const showPrivacy = () => {
   console.log('Show privacy')
 }
 
-onMounted(() => {
+const noReadCount = ref(0)
+const getCount = () => {
   getNoReadCount().then(res => {
-    console.log('Unread notifications count:', res)
+    let countList = (res.result || []).map(item => item.stateNumber)
+    noReadCount.value = eval(countList.join("+"))
+    notificationTabs.value = [
+      { messageType: 'all', messageTypeName: '全部', stateNumber: noReadCount.value },
+      ...res.result
+    ]
   })
+}
+onMounted(() => {
+  getCount()
 })
 </script>
 
@@ -1701,6 +1609,7 @@ onMounted(() => {
   position: sticky;
   top: 0;
   z-index: 10;
+  margin-bottom: 0;
 }
 
 .panel-title {
@@ -2364,6 +2273,14 @@ onMounted(() => {
   cursor: pointer;
 }
 
+.settings-item:first-child{
+  padding-top: 0;
+}
+
+.settings-item .el-switch{
+  --el-switch-on-color: #13ce66;
+}
+
 .item-icon {
   width: 40px;
   height: 40px;