316 lines
8.8 KiB
Vue
316 lines
8.8 KiB
Vue
<!-- 顶栏消息通知 -->
|
|
<template>
|
|
<a-dropdown
|
|
v-model:visible="visible"
|
|
placement="bottom"
|
|
:trigger="['click']"
|
|
:overlay-style="{ padding: '0 10px' }"
|
|
>
|
|
<a-badge :count="unreadNum" class="ele-notice-trigger" :offset="[6, 4]">
|
|
<bell-outlined style="padding: 8px 0" />
|
|
</a-badge>
|
|
<template #overlay>
|
|
<div class="ant-dropdown-menu ele-notice-pop">
|
|
<div @click.stop="">
|
|
<a-tabs v-model:active-key="active" :centered="true">
|
|
<a-tab-pane key="notice" :tab="noticeTitle">
|
|
<a-list item-layout="horizontal" :data-source="notice">
|
|
<template #renderItem="{ item }">
|
|
<a-list-item>
|
|
<a-list-item-meta
|
|
@click="openUrl('/user/notice?type=notice')"
|
|
:title="item.title"
|
|
:description="timeAgo(item.createTime)"
|
|
>
|
|
<template #avatar>
|
|
<a-avatar :style="{ background: item.color }">
|
|
<template #icon>
|
|
<component :is="item.icon" />
|
|
</template>
|
|
</a-avatar>
|
|
</template>
|
|
</a-list-item-meta>
|
|
</a-list-item>
|
|
</template>
|
|
</a-list>
|
|
<div v-if="notice.length" class="ele-cell ele-notice-actions">
|
|
<div class="ele-cell-content" @click="clearNotice">
|
|
清空通知
|
|
</div>
|
|
<a-divider type="vertical" />
|
|
<router-link
|
|
to="/user/notice?type=notice"
|
|
class="ele-cell-content"
|
|
>
|
|
查看更多
|
|
</router-link>
|
|
</div>
|
|
</a-tab-pane>
|
|
<a-tab-pane key="letter" :tab="letterTitle">
|
|
<a-list item-layout="horizontal" :data-source="letter">
|
|
<template #renderItem="{ item }">
|
|
<a-list-item>
|
|
<a-list-item-meta
|
|
:title="item.title"
|
|
@click="openUrl('/user/task')"
|
|
>
|
|
<template #avatar>
|
|
<a-avatar :src="item.icon" />
|
|
</template>
|
|
<template #description>
|
|
<div>{{ item.content }}</div>
|
|
<div>{{ timeAgo(item.createTime) }}</div>
|
|
</template>
|
|
</a-list-item-meta>
|
|
</a-list-item>
|
|
</template>
|
|
</a-list>
|
|
<div v-if="letter.length" class="ele-cell ele-notice-actions">
|
|
<div class="ele-cell-content" @click="clearLetter">
|
|
清空私信
|
|
</div>
|
|
<a-divider type="vertical" />
|
|
<router-link
|
|
to="/user/notice?type=letter"
|
|
class="ele-cell-content"
|
|
>
|
|
查看更多
|
|
</router-link>
|
|
</div>
|
|
</a-tab-pane>
|
|
<a-tab-pane key="todo" :tab="todoTitle">
|
|
<a-list item-layout="horizontal" :data-source="todo">
|
|
<template #renderItem="{ item }">
|
|
<a-list-item>
|
|
<a-list-item-meta
|
|
:description="`${item.content} ${timeAgo(
|
|
item.createTime
|
|
)}`"
|
|
@click="openUrl('/user/task')"
|
|
>
|
|
<template #title>
|
|
<div class="ele-cell">
|
|
<div class="ele-cell-content">{{ item.title }}</div>
|
|
<template
|
|
v-for="(d, index) in taskProgress"
|
|
:key="index"
|
|
>
|
|
<a-tag v-if="Number(d.value) === item.progress">
|
|
{{ d.label }}
|
|
</a-tag>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
</a-list-item-meta>
|
|
</a-list-item>
|
|
</template>
|
|
</a-list>
|
|
<div v-if="todo.length" class="ele-cell ele-notice-actions">
|
|
<div class="ele-cell-content" @click="clearTodo">
|
|
清空待办
|
|
</div>
|
|
<a-divider type="vertical" />
|
|
<router-link
|
|
to="/user/notice?type=todo"
|
|
class="ele-cell-content"
|
|
>
|
|
查看更多
|
|
</router-link>
|
|
</div>
|
|
</a-tab-pane>
|
|
</a-tabs>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</a-dropdown>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, computed } from 'vue';
|
|
import { message } from 'ant-design-vue/es';
|
|
import {
|
|
getUnReadNum,
|
|
pageLetters,
|
|
pageNotices,
|
|
pageTodos
|
|
} from '@/api/user/message';
|
|
import { getDictionaryOptions, openUrl } from '@/utils/common';
|
|
import { timeAgo } from 'ele-admin-pro';
|
|
|
|
// 是否显示
|
|
const visible = ref<boolean>(false);
|
|
// 选项卡选中
|
|
const active = ref<string>('notice');
|
|
// 通知数据
|
|
const notice = ref<any>([]);
|
|
// 私信数据
|
|
const letter = ref<any>([]);
|
|
// 待办数据
|
|
const todo = ref<any>([]);
|
|
// 通知未读数量
|
|
const unReadNotice = ref<any>(0);
|
|
// 私信未读数量
|
|
const unReadLetter = ref<any>(0);
|
|
// 代办未读数量
|
|
const unReadTodo = ref<any>(0);
|
|
// 获取字典数据
|
|
const taskProgress = getDictionaryOptions('taskProgress');
|
|
|
|
// 通知标题
|
|
const noticeTitle = computed(() => {
|
|
return '通知' + (unReadNotice.value > 0 ? `(${unReadNotice.value})` : '');
|
|
});
|
|
|
|
// 私信标题
|
|
const letterTitle = computed(() => {
|
|
return '私信' + (unReadLetter.value > 0 ? `(${unReadLetter.value})` : '');
|
|
});
|
|
|
|
// 待办标题
|
|
const todoTitle = computed(() => {
|
|
return '待办' + (unReadTodo.value > 0 ? `(${unReadTodo.value})` : '');
|
|
});
|
|
|
|
// 未读数量
|
|
const unreadNum = computed(() => {
|
|
return unReadNotice.value + unReadLetter.value + unReadTodo.value;
|
|
});
|
|
|
|
/* 查询数据 */
|
|
const query = () => {
|
|
pageNotices({ status: 0 })
|
|
.then((result) => {
|
|
notice.value = result?.list;
|
|
})
|
|
.catch((e) => {
|
|
message.error(e.message);
|
|
});
|
|
pageLetters({ status: 0 })
|
|
.then((result) => {
|
|
letter.value = result?.list;
|
|
})
|
|
.catch((e) => {
|
|
message.error(e.message);
|
|
});
|
|
pageTodos({ status: 0 })
|
|
.then((result) => {
|
|
todo.value = result?.list;
|
|
})
|
|
.catch((e) => {
|
|
message.error(e.message);
|
|
});
|
|
// getUnreadNotice()
|
|
// .then((result) => {
|
|
// notice.value = result.notice;
|
|
// letter.value = result.letter;
|
|
// todo.value = result.todo;
|
|
// })
|
|
// .catch((e) => {
|
|
// message.error(e.message);
|
|
// });
|
|
};
|
|
|
|
/* 查询未读数量 */
|
|
const queryUnReadNum = () => {
|
|
getUnReadNum()
|
|
.then((result) => {
|
|
unReadNotice.value = result?.notice;
|
|
unReadLetter.value = result?.letter;
|
|
unReadTodo.value = result?.todo;
|
|
})
|
|
.catch((e) => {
|
|
message.error(e.message);
|
|
});
|
|
};
|
|
|
|
queryUnReadNum();
|
|
|
|
/* 清空通知 */
|
|
const clearNotice = () => {
|
|
unReadNotice.value = 0;
|
|
};
|
|
|
|
/* 清空通知 */
|
|
const clearLetter = () => {
|
|
unReadLetter.value = 0;
|
|
};
|
|
|
|
/* 清空通知 */
|
|
const clearTodo = () => {
|
|
unReadTodo.value = 0;
|
|
};
|
|
|
|
query();
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
import {
|
|
BellOutlined,
|
|
NotificationFilled,
|
|
PushpinFilled,
|
|
VideoCameraFilled,
|
|
CarryOutFilled,
|
|
BellFilled
|
|
} from '@ant-design/icons-vue';
|
|
|
|
export default {
|
|
name: 'HeaderNotice',
|
|
components: {
|
|
BellOutlined,
|
|
NotificationFilled,
|
|
PushpinFilled,
|
|
VideoCameraFilled,
|
|
CarryOutFilled,
|
|
BellFilled
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="less">
|
|
.ele-notice-trigger.ant-badge {
|
|
color: inherit;
|
|
}
|
|
|
|
.ele-notice-pop {
|
|
&.ant-dropdown-menu {
|
|
padding: 0;
|
|
width: 336px;
|
|
max-width: 100%;
|
|
margin-top: 11px;
|
|
}
|
|
|
|
// 内容
|
|
.ant-list-item {
|
|
padding-left: 24px;
|
|
padding-right: 24px;
|
|
transition: background-color 0.3s;
|
|
cursor: pointer;
|
|
|
|
&:hover {
|
|
background: hsla(0, 0%, 60%, 0.05);
|
|
}
|
|
}
|
|
|
|
.ant-tag {
|
|
margin: 0;
|
|
}
|
|
|
|
// 操作按钮
|
|
.ele-notice-actions {
|
|
border-top: 1px solid hsla(0, 0%, 60%, 0.15);
|
|
|
|
& > .ele-cell-content {
|
|
line-height: 46px;
|
|
text-align: center;
|
|
transition: background-color 0.3s;
|
|
cursor: pointer;
|
|
color: inherit;
|
|
|
|
&:hover {
|
|
background: hsla(0, 0%, 60%, 0.05);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|