Browse Source

Merge remote-tracking branch 'origin/master'

luoyali 9 months ago
parent
commit
9d2f54676e

+ 19 - 1
src/api/system/message.ts

@@ -20,6 +20,14 @@ function getMessageInfo(data: any): AxiosPromise {
 	})
 }
 
+function getMessageMyInfoApi(data: any): AxiosPromise {
+	return request({
+		url: '/sys/message/page-my',
+		method: 'post',
+		data
+	})
+}
+
 function getMessageInfoById(id: any): AxiosPromise {
 	return request({
 		url: '/sys/message/get?id=' + id,
@@ -27,6 +35,14 @@ function getMessageInfoById(id: any): AxiosPromise {
 	})
 }
 
+function readMessageApi(data: any): AxiosPromise {
+	return request({
+		url: '/sys/message/read',
+		method: 'post',
+		data
+	})
+}
+
 /**
  * 扩展配置 - 删除
  */
@@ -41,5 +57,7 @@ export default {
 	getMessage,
 	getMessageInfo,
 	getMessageInfoById,
-	messageDeleteApi
+	messageDeleteApi,
+	getMessageMyInfoApi,
+	readMessageApi
 }

+ 161 - 20
src/layout/components/Header/components/Message.vue

@@ -4,58 +4,199 @@
 			<div class="menu--message-trigger">
 				<el-tooltip :content="$t('le.message.txt')" effect="dark" placement="bottom">
 					<div class="menu--message menu-item le-hover-effect--bg">
-						<el-badge :value="90" :max="99">
+						<el-badge :value="total" :max="99">
 							<i class="le-iconfont le-notice"></i>
 						</el-badge>
 					</div>
 				</el-tooltip>
 			</div>
 		</template>
-		<ul>
-			<li v-for="(item, idx) in receivedData" :key="idx">{{ item }}</li>
-		</ul>
+		<el-tabs class="message-tabs" v-model="activeTab">
+			<el-tab-pane v-for="v of tabsConfig" :key="v.name" :name="v.name">
+				<template #label> {{ v.label }}({{ v.list.length }}) </template>
+				<template v-if="v.list.length">
+					<div class="message-list">
+						<div v-for="item of v.list" :key="item.id" class="message-item" @click="jumpMessageDetail(item.id)">
+							<!--<img src="" alt="" class="message-icon" />-->
+							<div class="message-content">
+								<div class="message-title">
+									<span class="txt text-overflow_ellipsis" :title="item.title">{{ item.title }}</span>
+									<span class="message-date">{{ item.createTime }}</span>
+								</div>
+								<span class="message-txt">{{ item.content }}</span>
+							</div>
+						</div>
+						<div class="message-fix-item" @click="jumpMessageInfo">查看更多</div>
+					</div>
+				</template>
+				<template v-else>
+					<LeNoData />
+				</template>
+			</el-tab-pane>
+		</el-tabs>
 	</el-popover>
 </template>
 
-<script setup>
-import { onMounted, onBeforeUnmount, ref } from 'vue'
+<script setup lang="ts">
+import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
+import message from '@/api/system/message'
+import router from '@/router'
 import { EventSourcePolyfill } from 'event-source-polyfill'
 import { ls } from '@/utils'
 import { ElNotification } from 'element-plus'
 const token = ls.get('token')
 const { VITE_APP_BASE_API } = import.meta.env
 const serviceUrlApi = ref(`${VITE_APP_BASE_API}/sys/sse/connect`)
-const receivedData = ref([])
-let eventSource = null
+let eventSource: EventSourcePolyfill | null = null
+
+// noticeList  通知     messageList   消息     todoList   待办
+const tabsConfig = reactive({
+	noticeList: {
+		name: 'noticeList',
+		label: '通知',
+		list: []
+	},
+	messageList: {
+		name: 'messageList',
+		label: '消息',
+		list: []
+	},
+	todoList: {
+		name: 'todoList',
+		label: '待办',
+		list: []
+	}
+})
+const activeTab = ref('noticeList')
+const total = ref(0)
+message.getMessage().then(res => {
+	let _total = 0
+	Object.keys(tabsConfig).map(key => {
+		if (res[key]) {
+			tabsConfig[key].list = res[key]
+			_total += res[key].length
+		} else {
+			res[key].list = []
+		}
+	})
+	total.value = _total
+})
+
+const jumpMessageInfo = () => {
+	router.push('/message/list')
+}
+
+const jumpMessageDetail = (id: any) => {
+	router.push('/message/list?id=' + id)
+}
 
 onMounted(() => {
 	eventSource = new EventSourcePolyfill(serviceUrlApi.value, {
 		headers: { accessToken: token }
 	})
 
-	eventSource.onmessage = event => {
+	eventSource.onmessage = (event: MessageEvent) => {
+		// const data = JSON.parse()
+		console.log('Received message-----:', event)
+
+		const eventType = event.type
+		const notificationTitles: { [key: string]: string } = {
+			message: '消息',
+			notice: '通知',
+			remind: '待办'
+		}
+		const notificationTitle = notificationTitles[eventType] || '您有一条新消息'
 		console.log('Received message:', event.data)
-		receivedData.value.push(event.data)
 		// 处理接收到的消息
 		ElNotification({
-			title: '您有一条新消息',
+			title: notificationTitle,
 			message: event.data,
-			type: 'success'
+			type: 'success',
+			duration: 10000
 		})
 	}
 
-	eventSource.onerror = error => {
+	eventSource.addEventListener('remind', (event: MessageEvent) => {
+		const data = JSON.parse(event.data)
+		console.log('Received remind event:', event)
+		// 处理接收到的提醒消息
+		ElNotification({
+			title: data.title,
+			message: data.content,
+			type: 'success',
+			duration: 10000
+		})
+	})
+
+	eventSource.onerror = (error: any) => {
 		console.error('EventSource failed:', error)
 	}
 })
 
-onBeforeUnmount(() => {
-	if (eventSource) {
-		eventSource.close()
-	}
-})
+// onBeforeUnmount(() => {
+// 	if (eventSource) {
+// 		eventSource.close()
+// 	}
+// })
 </script>
 
-<style scoped>
-/* 你的样式代码 */
+<style scoped lang="scss">
+.message-list {
+	display: flex;
+	flex-direction: column;
+	max-height: 390px;
+	overflow-y: auto;
+	.message-item {
+		display: flex;
+		align-items: center;
+		padding: 8px 0;
+		border-bottom: 1px solid var(--el-border-color-light);
+		cursor: pointer;
+		&:last-child {
+			border: none;
+		}
+		.message-content {
+			display: flex;
+			flex-direction: column;
+			width: 100%;
+			.message-title {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				margin-bottom: 5px;
+				font-weight: 600;
+				color: var(--el-text-color-primary);
+			}
+			.message-date {
+				font-size: 12px;
+				color: var(--el-text-color-secondary);
+				margin-left: 10px;
+				font-weight: 400;
+				flex-shrink: 0;
+			}
+			.message-txt {
+				//margin-bottom: 5px;
+				color: var(--el-text-color-regular);
+			}
+		}
+	}
+	.message-fix-item {
+		// flex 居中
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		height: 40px;
+		cursor: pointer;
+	}
+}
+.menu--message-trigger {
+	height: 100%;
+}
+.menu--message {
+	width: 40px;
+	justify-content: center;
+	//.le-notice {
+	//.le-iconfont {
+	//}
+}
 </style>

+ 50 - 9
src/views/message/list/my.vue

@@ -14,8 +14,8 @@
 				:columns="activeColumns"
 			>
 				<template #toolLeft>
-					<el-button plain type="primary">全部标记已读</el-button>
-					<el-button plain :icon="Delete" :disabled="curSelectionRows.length === 0" @click="batch_del" type="danger">删除</el-button>
+					<el-button plain type="primary" @click="readAll">一键已读</el-button>
+					<el-button plain :icon="Delete" :disabled="curSelectionRows.length === 0" type="danger" @click="batch_del">删除</el-button>
 				</template>
 
 				<template #categorySlot="scope">
@@ -24,6 +24,17 @@
 					<el-tag v-if="scope.row.category === 2" size="small" type="warning" effect="plain">待办通知</el-tag>
 				</template>
 
+				<template #viewedSlot="scope">
+					<el-tag
+						v-if="scope.row.viewed !== undefined && scope.row.viewed !== null"
+						:type="getViewedType(scope.row.viewed)"
+						size="small"
+						effect="plain"
+					>
+						{{ getViewedLabel(scope.row.viewed) }}
+					</el-tag>
+				</template>
+
 				<template #actionSlot="{ row }">
 					<div class="flex flex-align-pack-center">
 						<LeIcon class="text-lg text-icon-color cursor-pointer" icon-class="icon-processInfo-icons--view-light" @click="openDetail(row)" />
@@ -34,7 +45,7 @@
 			</LeTable>
 		</div>
 
-		<message-detail v-if="visibleDetail" v-model="visibleDetail" :message-id="currentId" @closed="visibleDetail = false"></message-detail>
+		<message-detail v-if="visibleDetail" v-model="visibleDetail" :message-id="currentId" @closed="queryList"></message-detail>
 	</div>
 </template>
 <script lang="tsx" setup>
@@ -48,15 +59,15 @@ import { ElMessage, ElMessageBox } from 'element-plus'
 
 const route = useRoute()
 const visibleDetail = ref(false) // 权限设置弹窗显示隐藏
-const currentId = ref(null)
+const currentId = ref('')
 
 // 表格搜索条件
 const forms = ref([
 	{
 		prop: 'title',
-		label: '标题:',
+		label: '消息标题:',
 		itemType: 'input',
-		placeholder: '请输入标题'
+		placeholder: '请输入消息标题'
 	},
 	{
 		prop: 'createBy',
@@ -71,7 +82,7 @@ const queryList = async () => {
 	const { options, searchParams } = tableOpts
 	options.loading = true
 	try {
-		const { records: list, total } = await message.getMessageInfo(searchParams)
+		const { records: list, total } = await message.getMessageMyInfoApi(searchParams)
 		tableOpts.total = total
 		tableOpts.list = list
 	} catch {
@@ -88,7 +99,7 @@ const queryList = async () => {
 const columns = [
 	{
 		prop: 'title',
-		label: '标题',
+		label: '消息标题',
 		minWidth: 80
 	},
 	{
@@ -104,6 +115,13 @@ const columns = [
 		label: '发布人',
 		minWidth: 100
 	},
+	{
+		prop: 'viewed',
+		label: '查看状态',
+		slots: {
+			default: 'viewedSlot'
+		}
+	},
 	{
 		prop: 'createTime',
 		label: '发布时间',
@@ -174,12 +192,35 @@ const batch_del = () => {
 		deleteItem(ids)
 	})
 }
+const markAsRead = async (id: string | undefined) => {
+	await message.readMessageApi({ id })
+}
 
-const openDetail = (row: any) => {
+const openDetail = async (row: any) => {
+	if (Number(row.viewed) === 0) {
+		await markAsRead(row.id)
+	}
 	currentId.value = row.id
 	visibleDetail.value = true
 }
 
+const readAll = async () => {
+	try {
+		await markAsRead(undefined)
+		queryList()
+	} catch (error) {
+		console.error('Error marking all messages as read:', error)
+	}
+}
+
+const getViewedType = viewed => {
+	return Number(viewed) === 0 ? 'warning' : 'success'
+}
+
+const getViewedLabel = viewed => {
+	return Number(viewed) === 0 ? '未查看' : '已查看'
+}
+
 nextTick(() => {
 	queryList()
 })