Files
art-design/src/components/core/layouts/art-notification/index.vue
T

289 lines
8.3 KiB
Vue
Raw Normal View History

2025-07-04 17:16:38 +08:00
<template>
<div
class="notice"
v-show="visible"
:style="{
transform: show ? 'scaleY(1)' : 'scaleY(0.9)',
opacity: show ? 1 : 0
}"
@click.stop=""
>
<div class="header">
2025-08-22 18:27:26 +08:00
<!-- <span class="text">{{ $t('notice.title') }}</span> -->
<span class="text">消息</span>
<span class="btn" @click="readAll">{{ $t('notice.btnRead') }}</span>
2025-07-04 17:16:38 +08:00
</div>
<ul class="bar">
<li
v-for="(item, index) in barList"
:key="index"
:class="{ active: barActiveIndex === index }"
>
2025-08-22 18:27:26 +08:00
{{ item.name }} ({{ noticeList.length }})
2025-07-04 17:16:38 +08:00
</li>
</ul>
<div class="content">
<div class="scroll">
<!-- 通知 -->
2025-08-22 18:27:26 +08:00
<ul class="notice-list">
<!-- <ul class="notice-list" v-show="barActiveIndex === 0"> -->
<li v-for="(item, index) in noticeList" :key="index" @click="showfn(item)" v-ripple>
2025-07-04 17:16:38 +08:00
<div
class="icon"
2025-08-22 18:27:26 +08:00
:style="{
background: getNoticeStyle(item.message.scene).backgroundColor + '!important'
}"
2025-07-04 17:16:38 +08:00
>
<i
class="iconfont-sys"
2025-08-22 18:27:26 +08:00
:style="{ color: getNoticeStyle(item.message.scene).iconColor + '!important' }"
v-html="getNoticeStyle(item.message.scene).icon"
2025-07-04 17:16:38 +08:00
>
</i>
</div>
<div class="text">
2025-08-22 18:27:26 +08:00
<h4>{{ item.message.title }}</h4>
<p>{{ item.message.created_at }}</p>
2025-07-04 17:16:38 +08:00
</div>
</li>
</ul>
<!-- 消息 -->
2025-08-22 18:27:26 +08:00
<!-- <ul class="user-list" v-show="barActiveIndex === 1">
2025-07-04 17:16:38 +08:00
<li v-for="(item, index) in msgList" :key="index">
<div class="avatar">
<img :src="item.avatar" />
</div>
<div class="text">
<h4>{{ item.title }}</h4>
<p>{{ item.time }}</p>
</div>
</li>
2025-08-22 18:27:26 +08:00
</ul> -->
2025-07-04 17:16:38 +08:00
<!-- 待办 -->
2025-08-22 18:27:26 +08:00
<!-- <ul class="base" v-show="barActiveIndex === 3">
2025-07-04 17:16:38 +08:00
<li v-for="(item, index) in pendingList" :key="index">
<h4>{{ item.title }}</h4>
<p>{{ item.time }}</p>
</li>
2025-08-22 18:27:26 +08:00
</ul> -->
2025-07-04 17:16:38 +08:00
2025-08-22 18:27:26 +08:00
<div class="empty-tips" v-show="noticeList.length === 0">
2025-07-04 17:16:38 +08:00
<i class="iconfont-sys">&#xe8d7;</i>
<p>{{ $t('notice.text[0]') }}{{ barList[barActiveIndex].name }}</p>
</div>
2025-08-22 18:27:26 +08:00
<!-- <div class="empty-tips" v-show="barActiveIndex === 1 && msgList.length === 0">
2025-07-04 17:16:38 +08:00
<i class="iconfont-sys">&#xe8d7;</i>
<p>{{ $t('notice.text[0]') }}{{ barList[barActiveIndex].name }}</p>
</div>
<div class="empty-tips" v-show="barActiveIndex === 2 && pendingList.length === 0">
<i class="iconfont-sys">&#xe8d7;</i>
<p>{{ $t('notice.text[0]') }}{{ barList[barActiveIndex].name }}</p>
2025-08-22 18:27:26 +08:00
</div> -->
2025-07-04 17:16:38 +08:00
</div>
<div class="btn-wrapper">
<el-button class="view-all" @click="handleViewAll" v-ripple>
{{ $t('notice.viewAll') }}
</el-button>
</div>
</div>
<div style="height: 100px"></div>
</div>
2025-08-22 18:27:26 +08:00
<!-- 全局通知详情弹窗 -->
<Teleport to="body">
<ElDialog v-model="dialogVisible" title="通知详情" align-center :append-to-body="true">
<div class="detail-info-table">
<div class="row">
<div>发送人:{{ noticeDetail.sender_name }}</div>
</div>
<div class="row">
<div>通知标题:{{ noticeDetail.title }}</div>
</div>
<div class="row">
<div>
通知内容:
<div class="message-text" v-html="noticeDetail.content"></div>
</div>
</div>
</div>
</ElDialog>
</Teleport>
2025-07-04 17:16:38 +08:00
</template>
<script setup lang="ts">
import avatar1 from '@/assets/img/avatar/avatar1.webp'
import avatar2 from '@/assets/img/avatar/avatar2.webp'
import avatar3 from '@/assets/img/avatar/avatar3.webp'
import avatar4 from '@/assets/img/avatar/avatar4.webp'
import avatar5 from '@/assets/img/avatar/avatar5.webp'
import avatar6 from '@/assets/img/avatar/avatar6.webp'
import AppConfig from '@/config'
import { useI18n } from 'vue-i18n'
2025-08-22 18:27:26 +08:00
import { commonService } from '@/api/commonApi'
import { mittBus } from '@/utils/sys'
const dialogVisible = ref(false)
const router = useRouter()
2025-07-04 17:16:38 +08:00
const { t } = useI18n()
const props = defineProps({
value: {
type: Boolean,
default: false
}
})
watch(
() => props.value,
() => {
showNotice(props.value)
}
)
const show = ref(false)
const visible = ref(false)
const barActiveIndex = ref(0)
const pendingList: any = []
const barList = ref([
{
name: computed(() => t('notice.bar[0]')),
num: 1
}
])
2025-08-22 18:27:26 +08:00
const noticeList = ref<any>([])
const getNoticeList = async () => {
await commonService.getUnReadNoticeList().then((res: any) => {
noticeList.value = res.list
// 通知头部组件更新铃铛状态
mittBus.emit('notification-data-changed', res.list?.length || 0)
})
}
onMounted(() => {
getNoticeList()
// 监听WebSocket消息:收到新通知实时插入到列表首位
mittBus.on('ws:message', onWsMessage)
})
onUnmounted(() => {
mittBus.off('ws:message')
})
2025-07-04 17:16:38 +08:00
2025-08-22 18:27:26 +08:00
const onWsMessage = (data: any) => {
if (data && data.event === 'notify.receive') {
// 将新通知插入到列表首位。后端数据结构需包含 type 与 message 字段
// 若结构不同,可在此处做一次字段映射
console.log(data)
noticeList.value.unshift(data.data.notice_data)
console.log(noticeList.value)
mittBus.emit('notification-data-changed', noticeList.value.length)
2025-07-04 17:16:38 +08:00
}
}
2025-08-22 18:27:26 +08:00
// const changeBar = (index: number) => {
// barActiveIndex.value = index
// }
2025-07-04 17:16:38 +08:00
const getRandomColor = () => {
const index = Math.floor(Math.random() * AppConfig.systemMainColor.length)
return AppConfig.systemMainColor[index]
}
const noticeStyleMap = {
2025-08-22 18:27:26 +08:00
4: {
2025-07-04 17:16:38 +08:00
icon: '&#xe72e;',
iconColor: 'rgb(var(--art-warning))',
backgroundColor: 'rgb(var(--art-bg-warning))'
},
2025-08-22 18:27:26 +08:00
2: {
2025-07-04 17:16:38 +08:00
icon: '&#xe747;',
iconColor: 'rgb(var(--art-success))',
backgroundColor: 'rgb(var(--art-bg-success))'
},
2025-08-22 18:27:26 +08:00
5: {
2025-07-04 17:16:38 +08:00
icon: '&#xe714;',
iconColor: 'rgb(var(--art-danger))',
backgroundColor: 'rgb(var(--art-bg-danger))'
},
2025-08-22 18:27:26 +08:00
3: {
2025-07-04 17:16:38 +08:00
icon: '&#xe608;',
iconColor: 'rgb(var(--art-info))',
backgroundColor: 'rgb(var(--art-bg-info))'
},
2025-08-22 18:27:26 +08:00
1: {
2025-07-04 17:16:38 +08:00
icon: '&#xe6c2;',
iconColor: 'rgb(var(--art-primary))',
backgroundColor: 'rgb(var(--art-bg-primary))'
}
}
const getNoticeStyle = (type: string) => {
const defaultStyle = {
icon: '&#xe747;',
iconColor: '#FFFFFF',
backgroundColor: getRandomColor()
}
2025-08-22 18:27:26 +08:00
// 先转成 unknown,再转成 keyof 类型,避免 TS 报错
const key = type as unknown as keyof typeof noticeStyleMap
const style = noticeStyleMap[key] || defaultStyle
// const style = noticeStyleMap[type as keyof typeof noticeStyleMap] || defaultStyle
2025-07-04 17:16:38 +08:00
return {
...style,
backgroundColor: style.backgroundColor
}
}
const showNotice = (open: boolean) => {
if (open) {
visible.value = open
setTimeout(() => {
show.value = open
}, 5)
} else {
show.value = open
setTimeout(() => {
visible.value = open
}, 350)
}
}
2025-08-22 18:27:26 +08:00
const readAll = async () => {
const { message } = await commonService.readNotice({
msg_ids: 'all'
})
ElMessage.success(message)
getNoticeList()
}
2025-07-04 17:16:38 +08:00
// 查看全部
const handleViewAll = () => {
2025-08-22 18:27:26 +08:00
handleNoticeAll()
}
const noticeDetail = ref<any>({})
const showfn = async (row: any) => {
dialogVisible.value = true
await commonService.getNoticeDetail({ id: row.id }).then((res: any) => {
noticeDetail.value = res.message
showNotice(false) // 关闭通知组件
getNoticeList()
})
}
const handleNoticeAll = () => {
router.push('/common/notice')
showNotice(false) // 关闭通知组件
2025-07-04 17:16:38 +08:00
}
const handleMsgAll = () => {}
const handlePendingAll = () => {}
</script>
<style lang="scss" scoped>
@use './style';
2025-08-22 18:27:26 +08:00
.el-button {
--el-button-border-color: #dcdfe6 !important;
--el-button-text-color: var(--el-text-color-regular);
}
.message-text {
padding: 10px 14px;
line-height: 1.4;
white-space: pre-line;
}
2025-07-04 17:16:38 +08:00
</style>