chenxiaochao vor 2 Tagen
Ursprung
Commit
6daea83d20

+ 31 - 0
apps/web-ele/src/api/messageHistory/index.ts

@@ -0,0 +1,31 @@
1
+import { requestClient } from '#/api/request';
2
+enum Api {
3
+  querymessageRecordslist = '/messageRecords/records/list',
4
+  details = '/messageRecords/records',
5
+}
6
+// //新增知识库分类
7
+// export function addKnowledgeCategory(data: any) {
8
+//   return requestClient.post(Api.baseknowledgeCategory, data, {
9
+//     successMessageMode: 'message',
10
+//   });
11
+// }
12
+//查询消息记录列表
13
+export function queryMessageRecordsList(params: any) {
14
+  return requestClient.get(Api.querymessageRecordslist, { params });
15
+}
16
+// //详情
17
+export function queryMessageRecordsDetail(id: any) {
18
+  return requestClient.get(`${Api.details}/${id}`);
19
+}
20
+// //修改知识库分类
21
+// export function editKnowledgeCategory(data: any) {
22
+//   return requestClient.put(Api.baseknowledgeCategory, data, {
23
+//     successMessageMode: 'message',
24
+//   });
25
+// }
26
+// //删除知识库分类
27
+// export function deleteKnowledgeCategory(ids: any) {
28
+//   return requestClient.delete(`${Api.baseknowledgeCategory}/${ids}`, {
29
+//     successMessageMode: 'message',
30
+//   });
31
+// }

+ 65 - 39
apps/web-ele/src/layouts/basic.vue

@@ -1,7 +1,6 @@
1 1
 <script lang="ts" setup>
2 2
 import type { NotificationItem } from '@vben/layouts';
3
-
4
-import { computed, ref, watch } from 'vue';
3
+import { computed, ref, watch, onMounted, onUnmounted } from 'vue';
5 4
 import { useRouter } from 'vue-router';
6 5
 // @ts-ignore
7 6
 import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
@@ -15,48 +14,71 @@ import {
15 14
 } from '@vben/layouts';
16 15
 import { preferences } from '@vben/preferences';
17 16
 import { useAccessStore, useUserStore } from '@vben/stores';
18
-
19 17
 import { useAuthStore } from '#/store';
20 18
 import LoginForm from '#/views/_core/authentication/login.vue';
19
+import { queryMessageRecordsList } from '#/api/messageHistory/index';
21 20
 
22
-const notifications = ref<NotificationItem[]>([
23
-  {
24
-    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
25
-    date: '3小时前',
26
-    isRead: true,
27
-    message: '描述信息描述信息描述信息',
28
-    title: '收到了 14 份新周报',
29
-  },
30
-  {
31
-    avatar: 'https://avatar.vercel.sh/1',
32
-    date: '刚刚',
33
-    isRead: false,
34
-    message: '描述信息描述信息描述信息',
35
-    title: '朱偏右 回复了你',
36
-  },
37
-  {
38
-    avatar: 'https://avatar.vercel.sh/1',
39
-    date: '2024-01-01',
40
-    isRead: false,
41
-    message: '描述信息描述信息描述信息',
42
-    title: '曲丽丽 评论了你',
43
-  },
44
-  {
45
-    avatar: 'https://avatar.vercel.sh/satori',
46
-    date: '1天前',
47
-    isRead: false,
48
-    message: '描述信息描述信息描述信息',
49
-    title: '代办提醒',
50
-  },
51
-]);
21
+const notifications = ref([
22
+  // {
23
+  //   avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
24
+  //   date: '3小时前',
25
+  //   isRead: true,
26
+  //   message: '描述信息描述信息描述信息',
27
+  //   title: '收到了 14 份新周报',
28
+  // },
29
+  // {
30
+  //   avatar: 'https://avatar.vercel.sh/1',
31
+  //   date: '刚刚',
32
+  //   isRead: false,
33
+  //   message: '描述信息描述信息描述信息',
34
+  //   title: '朱偏右 回复了你',
35
+  // },
36
+  // {
37
+  //   avatar: 'https://avatar.vercel.sh/1',
38
+  //   date: '2024-01-01',
39
+  //   isRead: false,
40
+  //   message: '描述信息描述信息描述信息',
41
+  //   title: '曲丽丽 评论了你',
42
+  // },
43
+  // {
44
+  //   avatar: 'https://avatar.vercel.sh/satori',
45
+  //   date: '1天前',
46
+  //   isRead: false,
47
+  //   message: '描述信息描述信息描述信息',
48
+  //   title: '代办提醒',
49
+  // },
50
+]) as any;
52 51
 
53 52
 const userStore = useUserStore();
54 53
 const authStore = useAuthStore();
55 54
 const accessStore = useAccessStore();
56 55
 const { destroyWatermark, updateWatermark } = useWatermark();
57
-const showDot = computed(() =>
58
-  notifications.value.some((item) => !item.isRead),
59
-);
56
+// const showDot = computed(() =>
57
+//   notifications.value.some((item: any) => !item.isRead),
58
+// );
59
+const queryMessageRecordsListfn = async () => {
60
+  const res = await queryMessageRecordsList({
61
+    pageNum: 1,
62
+    pageSize: 20,
63
+  });
64
+  notifications.value = res.rows || [];
65
+};
66
+
67
+// 定时器变量
68
+let notificationTimer: number | undefined;
69
+
70
+onMounted(() => {
71
+  queryMessageRecordsListfn();
72
+  notificationTimer = window.setInterval(() => {
73
+    queryMessageRecordsListfn();
74
+  }, 60000);
75
+});
76
+
77
+onUnmounted(() => {
78
+  if (notificationTimer) {
79
+    clearInterval(notificationTimer);
80
+  }
81
+});
60 82
 const router = useRouter();
61 83
 const menus = computed(() => [
62 84
   {
@@ -106,9 +128,12 @@ async function handleLogout() {
106 128
 function handleNoticeClear() {
107 129
   notifications.value = [];
108 130
 }
109
-
131
+// const handleclick = ()=>{
132
+//   console.log('打开了');
133
+  
134
+// }
110 135
 function handleMakeAll() {
111
-  notifications.value.forEach((item) => (item.isRead = true));
136
+  notifications.value.forEach((item: any) => (item.isRead = true));
112 137
 }
113 138
 watch(
114 139
   () => preferences.app.watermark,
@@ -140,11 +165,12 @@ watch(
140 165
       />
141 166
     </template>
142 167
     <template #notification>
168
+              <!-- :dot="showDot" -->
143 169
       <Notification
144
-        :dot="showDot"
145 170
         :notifications="notifications"
146 171
         @clear="handleNoticeClear"
147 172
         @make-all="handleMakeAll"
173
+        @refresh="queryMessageRecordsListfn"
148 174
       />
149 175
     </template>
150 176
     <template #extra>

+ 12 - 3
apps/web-ele/src/router/routes/local.ts

@@ -301,11 +301,20 @@ const localRoutes: RouteRecordStringComponent[] = [
301 301
     name: 'WarningDetail',
302 302
     path: '/aiAnalysis/warning/detail/:alertId',
303 303
   },
304
+  {
305
+    component: '/messageHistory/index',
306
+    meta: {
307
+      activePath: '/messageHistory',
308
+      icon: 'carbon:information',
309
+      title: '消息列表',
310
+      hideInMenu: true,
311
+    },
312
+    name: 'MessageList',
313
+    path: '/messageHistory/index',
314
+  },
304 315
 ];
305 316
 
306 317
 /**
307 318
  * 这里放本地路由
308 319
  */
309
-export const localMenuList: RouteRecordStringComponent[] = [
310
-  ...localRoutes,
311
-];
320
+export const localMenuList: RouteRecordStringComponent[] = [...localRoutes];

+ 56 - 0
apps/web-ele/src/views/messageHistory/config-data.tsx

@@ -0,0 +1,56 @@
1
+import type { VxeGridProps } from '#/adapter/vxe-table';
2
+export const columns: VxeGridProps['columns'] = [
3
+  {
4
+    field: 'action',
5
+    fixed: 'right',
6
+    slots: { default: 'action' },
7
+    resizable: false,
8
+    title: '操作',
9
+    width: 180,
10
+  },
11
+  {
12
+    title: '消息标题',
13
+    field: 'title',
14
+    minWidth: 130,
15
+  },
16
+  {
17
+    title: '消息类型',
18
+    field: 'messageType',
19
+    slots: { default: 'messageType' },
20
+    minWidth: 130,
21
+  },
22
+  {
23
+    title: '优先级',
24
+    field: 'priority',
25
+    minWidth: 130,
26
+    slots: { default: 'priority' },
27
+  },
28
+  {
29
+    title: '消息状态',
30
+    field: 'status',
31
+    minWidth: 130,
32
+    slots: { default: 'status' },
33
+  },
34
+  {
35
+    title: '消息内容',
36
+    field: 'content',
37
+    minWidth: 130,
38
+    slots: { default: 'content' },
39
+  },
40
+  {
41
+    title: '操作时间',
42
+    field: 'updateTime',
43
+    minWidth: 130,
44
+  },
45
+  {
46
+    title: '创建时间',
47
+    field: 'createTime',
48
+    minWidth: 130,
49
+  },
50
+  {
51
+    title: '任务类型',
52
+    field: 'taskType',
53
+    minWidth: 130,
54
+    slots: { default: 'taskType' },
55
+  },
56
+];

+ 123 - 0
apps/web-ele/src/views/messageHistory/index.vue

@@ -0,0 +1,123 @@
1
+<script setup lang="ts">
2
+import { Page } from '@vben/common-ui';
3
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
4
+//@ts-ignore
5
+import { columns } from './config-data';
6
+//@ts-ignore
7
+import type { VbenFormProps } from '@vben/common-ui';
8
+import { DictEnum } from '@vben/constants';
9
+import { getDictOptions } from '#/utils/dict';
10
+import { useRouter } from 'vue-router';
11
+import {
12
+  queryMessageRecordsList,
13
+  queryMessageRecordsDetail,
14
+} from '#/api/messageHistory/index';
15
+const router = useRouter();
16
+// 获取任务类型文本
17
+const getTaskTypeText = (taskType: string | undefined) => {
18
+  if (!taskType) return '';
19
+  const taskTypeOptions = getDictOptions(DictEnum.TASK_TYPE);
20
+  const option = taskTypeOptions.find((opt) => opt.value === taskType);
21
+  return option?.label || '';
22
+};
23
+
24
+// 列表中显示配置
25
+const gridOptions: VxeGridProps = {
26
+  checkboxConfig: {
27
+    // 高亮
28
+    highlight: true,
29
+    // 翻页时保留选中状态
30
+    reserve: true,
31
+    // 点击行选中
32
+    trigger: 'default',
33
+  },
34
+  columns,
35
+  size: 'medium',
36
+  height: 'auto',
37
+  proxyConfig: {
38
+    ajax: {
39
+      query: async ({ page }, formValues = {}) => {
40
+        const resp = await queryMessageRecordsList({
41
+          pageNum: page.currentPage,
42
+          pageSize: page.pageSize,
43
+        });
44
+        return { items: resp.rows, total: resp.total };
45
+      },
46
+    },
47
+  },
48
+  rowConfig: {
49
+    keyField: 'roleId',
50
+  },
51
+  toolbarConfig: {
52
+    custom: true,
53
+    refresh: true,
54
+    zoom: true,
55
+  },
56
+  id: 'system-role-index',
57
+};
58
+const [BasicTable, BasicTableApi] = useVbenVxeGrid({
59
+  gridOptions,
60
+});
61
+const handleView = async (row: any) => {
62
+  try {
63
+    await queryMessageRecordsDetail(row.id);
64
+    if (row.messageType === 1) {
65
+      router.push(`/schedule/detail/${row?.relatedId}`);
66
+    } else if (row.messageType === 2) {
67
+      router.push({
68
+        name: 'WarningDetail',
69
+        params: { alertId: row?.relatedId },
70
+      });
71
+    }
72
+  } catch (error) {
73
+    console.log(error);
74
+  }
75
+};
76
+</script>
77
+<template>
78
+  <Page :auto-content-height="true">
79
+    <BasicTable table-title="历史任务列表">
80
+      <template #action="{ row }">
81
+        <el-button size="small" type="primary" plain @click="handleView(row)"
82
+          >查看</el-button
83
+        >
84
+      </template>
85
+      <template #messageType="{ row }">
86
+        {{
87
+          row?.messageType === 1
88
+            ? '任务消息'
89
+            : row?.messageType === 2
90
+              ? '预警消息'
91
+              : ''
92
+        }}
93
+      </template>
94
+      <template #priority="{ row }">
95
+        {{
96
+          row?.priority === 0
97
+            ? '低'
98
+            : row?.priority === 1
99
+              ? '中'
100
+              : row?.priority === 2
101
+                ? '高'
102
+                : ''
103
+        }}
104
+      </template>
105
+      <template #status="{ row }">
106
+        <span :style="{ color: row?.status === 0 ? 'red' : 'green' }">
107
+          {{ row?.status === 0 ? '未读' : row?.status === 1 ? '已读' : '' }}
108
+        </span>
109
+      </template>
110
+      <template #content="{ row }">
111
+        <div v-html="row?.content || ''"></div>
112
+      </template>
113
+      <template #taskType="{ row }">
114
+        {{ getTaskTypeText(row.taskType) }}
115
+      </template>
116
+    </BasicTable>
117
+  </Page>
118
+</template>
119
+<style scoped lang="scss">
120
+:deep(.el-tooltip__trigger:focus) {
121
+  outline: none;
122
+}
123
+</style>

+ 37 - 20
packages/effects/layouts/src/widgets/notification/notification.vue

@@ -1,33 +1,31 @@
1 1
 <script lang="ts" setup>
2 2
 import type { NotificationItem } from './types';
3
-
3
+import { useRouter } from 'vue-router';
4 4
 import { Bell, MailCheck } from '@vben/icons';
5 5
 import { $t } from '@vben/locales';
6
-
7 6
 import {
8 7
   VbenButton,
9 8
   VbenIconButton,
10 9
   VbenPopover,
11 10
   VbenScrollbar,
12 11
 } from '@vben-core/shadcn-ui';
13
-
14 12
 import { useToggle } from '@vueuse/core';
15
-
13
+import { queryMessageRecordsDetail } from '../../../../../../apps/web-ele/src/api/messageHistory/index';
16 14
 interface Props {
17 15
   /**
18 16
    * 显示圆点
19 17
    */
20
-  dot?: boolean;
18
+  // dot?: boolean;
21 19
   /**
22 20
    * 消息列表
23 21
    */
24
-  notifications?: NotificationItem[];
22
+  notifications?: any[];
25 23
 }
26 24
 
27 25
 defineOptions({ name: 'NotificationPopup' });
28 26
 
29 27
 withDefaults(defineProps<Props>(), {
30
-  dot: false,
28
+  // dot: false,
31 29
   notifications: () => [],
32 30
 });
33 31
 
@@ -36,29 +34,46 @@ const emit = defineEmits<{
36 34
   makeAll: [];
37 35
   read: [NotificationItem];
38 36
   viewAll: [];
37
+  refresh: [];
39 38
 }>();
40 39
 
41 40
 const [open, toggle] = useToggle();
41
+const router = useRouter();
42 42
 
43 43
 function close() {
44 44
   open.value = false;
45 45
 }
46 46
 
47 47
 function handleViewAll() {
48
-  emit('viewAll');
49
-  close();
48
+  router.push({ path: '/messageHistory/index' });
49
+  // emit('viewAll');
50
+  // close();
50 51
 }
51 52
 
52 53
 function handleMakeAll() {
53
-  emit('makeAll');
54
+  // emit('makeAll');
54 55
 }
55 56
 
56 57
 function handleClear() {
57 58
   emit('clear');
58 59
 }
59 60
 
60
-function handleClick(item: NotificationItem) {
61
-  emit('read', item);
61
+async function handleClick(item: any) {
62
+  try {
63
+    await queryMessageRecordsDetail(item.id);
64
+    if (item.messageType === 1) {
65
+      router.push(`/schedule/detail/${item?.relatedId}`);
66
+    } else if (item.messageType === 2) {
67
+      router.push({
68
+        name: 'WarningDetail',
69
+        params: { alertId: item?.relatedId },
70
+      });
71
+    }
72
+    emit('refresh');
73
+  } catch (error) {
74
+    console.log(error);
75
+  }
76
+  // emit('read', item);
62 77
 }
63 78
 </script>
64 79
 <template>
@@ -70,7 +85,7 @@ function handleClick(item: NotificationItem) {
70 85
       <div class="flex-center mr-2 h-full" @click.stop="toggle()">
71 86
         <VbenIconButton class="bell-button text-foreground relative">
72 87
           <span
73
-            v-if="dot"
88
+            v-if="notifications.some((item) => item.status === 0)"
74 89
             class="bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded"
75 90
           ></span>
76 91
           <Bell class="size-4" />
@@ -97,26 +112,28 @@ function handleClick(item: NotificationItem) {
97 112
               @click="handleClick(item)"
98 113
             >
99 114
               <span
100
-                v-if="!item.isRead"
115
+                v-if="item.status === 0"
101 116
                 class="bg-primary absolute right-2 top-2 h-2 w-2 rounded"
102 117
               ></span>
103 118
 
104 119
               <span
105
-                class="relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full"
120
+                class="bg-primary relative flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-full text-sm font-semibold text-white"
106 121
               >
107
-                <img
122
+                <!-- <img
108 123
                   :src="item.avatar"
109 124
                   class="aspect-square h-full w-full object-cover"
110 125
                   role="img"
111
-                />
126
+                /> -->
127
+                {{ item.title?.substring(0, 2) || '未' }}
112 128
               </span>
113 129
               <div class="flex flex-col gap-1 leading-none">
114 130
                 <p class="font-semibold">{{ item.title }}</p>
115
-                <p class="text-muted-foreground my-1 line-clamp-2 text-xs">
131
+                <!-- <div v-html="item?.content"></div> -->
132
+                <!-- <p class="text-muted-foreground my-1 line-clamp-2 text-xs">
116 133
                   {{ item.message }}
117
-                </p>
134
+                </p> -->
118 135
                 <p class="text-muted-foreground line-clamp-2 text-xs">
119
-                  {{ item.date }}
136
+                  {{ item.updateTime }}
120 137
                 </p>
121 138
               </div>
122 139
             </li>