123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- <template>
- <div :class="prefixCls">
- <Popover v-model:visible="popoverVisible" title="" trigger="click" :overlayClassName="`${prefixCls}__overlay`">
- <Badge :count="count" :overflowCount="9" :offset="[-4, 10]" :numberStyle="numberStyle">
- <BellOutlined />
- </Badge>
- <template #content>
- <Tabs>
- <template v-for="item in listData" :key="item.key">
- <TabPane>
- <template #tab>
- {{ item.name }}
- <span v-if="item.list.length !== 0">({{ item.count }})</span>
- </template>
- <!-- 绑定title-click事件的通知列表中标题是“可点击”的-->
- <NoticeList :list="item.list" @title-click="onNoticeClick" />
- </TabPane>
- </template>
- </Tabs>
- <a-row class="bottom-buttons">
- <a-col :span="count === 0 ? 0 : 12">
- <a-button @click="onEmptyNotify" type="dashed" block>清空消息</a-button>
- </a-col>
- <a-col :span="count === 0 ? 24 : 12">
- <a-button @click="popoverVisible = false" type="dashed" block>
- <router-link to="/monitor/mynews">查看更多</router-link>
- </a-button>
- </a-col>
- </a-row>
- </template>
- </Popover>
- <DynamicNotice ref="dynamicNoticeRef" v-bind="dynamicNoticeProps" />
- <DetailModal @register="registerDetail" />
- </div>
- </template>
- <script lang="ts">
- import { computed, defineComponent, ref, unref, reactive, onMounted, getCurrentInstance } from 'vue';
- import { Popover, Tabs, Badge } from 'ant-design-vue';
- import { BellOutlined } from '@ant-design/icons-vue';
- import { tabListData } from './data';
- import { listCementByUser, editCementSend } from './notify.api';
- import NoticeList from './NoticeList.vue';
- import DetailModal from '/@/views/monitor/mynews/DetailModal.vue';
- import DynamicNotice from '/@/views/monitor/mynews/DynamicNotice.vue';
- import { useModal } from '/@/components/Modal';
- import { useDesign } from '/@/hooks/web/useDesign';
- import { useGlobSetting } from '/@/hooks/setting';
- import { useUserStore } from '/@/store/modules/user';
- import { connectWebSocket, onWebSocket } from '/@/hooks/web/useWebSocket';
- import { readAllMsg } from '/@/views/monitor/mynews/mynews.api';
- import { getToken } from '/@/utils/auth';
- export default defineComponent({
- components: {
- Popover,
- BellOutlined,
- Tabs,
- TabPane: Tabs.TabPane,
- Badge,
- NoticeList,
- DetailModal,
- DynamicNotice,
- },
- setup() {
- const { prefixCls } = useDesign('header-notify');
- const instance: any = getCurrentInstance();
- const userStore = useUserStore();
- const glob = useGlobSetting();
- const dynamicNoticeProps = reactive({ path: '', formData: {} });
- const [registerDetail, detailModal] = useModal();
- const popoverVisible = ref<boolean>(false);
- const listData = ref(tabListData);
- listData.value[0].list = [];
- listData.value[1].list = [];
- listData.value[0].count = 0;
- listData.value[1].count = 0;
- onMounted(() => {
- initWebSocket();
- });
- const count = computed(() => {
- let count = 0;
- for (let i = 0; i < listData.value.length; i++) {
- count += listData.value[i].count;
- }
- return count;
- });
- function mapAnnouncement(item) {
- return {
- ...item,
- title: item.titile,
- description: item.msgAbstract,
- datetime: item.sendTime,
- };
- }
- // 获取系统消息
- async function loadData() {
- try {
- let { anntMsgList, sysMsgList, anntMsgTotal, sysMsgTotal } = await listCementByUser({
- pageSize: 5,
- });
- listData.value[0].list = anntMsgList.map(mapAnnouncement);
- listData.value[1].list = sysMsgList.map(mapAnnouncement);
- listData.value[0].count = anntMsgTotal;
- listData.value[1].count = sysMsgTotal;
- } catch (e) {
- console.warn('系统消息通知异常:', e);
- }
- }
- loadData();
- function onNoticeClick(record) {
- try {
- editCementSend(record.id);
- loadData();
- } catch (e) {
- console.error(e);
- }
- if (record.openType === 'component') {
- dynamicNoticeProps.path = record.openPage;
- dynamicNoticeProps.formData = { id: record.busId };
- instance.refs.dynamicNoticeRef?.detail(record.openPage);
- } else {
- detailModal.openModal(true, {
- record,
- isUpdate: true,
- });
- }
- popoverVisible.value = false;
- }
- // 初始化 WebSocket
- function initWebSocket() {
- let userId = unref(userStore.getUserInfo).id;
- let token = getToken();
- // WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
- let url = glob.domainUrl?.replace('https://', 'wss://').replace('http://', 'ws://') + '/websocket/' + userId;
- connectWebSocket(url);
- onWebSocket(onWebSocketMessage);
- }
- function onWebSocketMessage(data) {
- if (data.cmd === 'topic' || data.cmd === 'user') {
- //update-begin-author:taoyan date:2022-7-13 for: VUEN-1674【严重bug】系统通知,为什么必须刷新右上角才提示
- //后台保存数据太慢 前端延迟刷新消息
- setTimeout(() => {
- loadData();
- }, 1000);
- //update-end-author:taoyan date:2022-7-13 for: VUEN-1674【严重bug】系统通知,为什么必须刷新右上角才提示
- }
- }
- // 清空消息
- function onEmptyNotify() {
- popoverVisible.value = false;
- readAllMsg({}, loadData);
- }
- return {
- prefixCls,
- listData,
- count,
- onNoticeClick,
- onEmptyNotify,
- numberStyle: {},
- popoverVisible,
- registerDetail,
- dynamicNoticeProps,
- };
- },
- });
- </script>
- <style lang="less">
- //noinspection LessUnresolvedVariable
- @prefix-cls: ~'@{namespace}-header-notify';
- .@{prefix-cls} {
- padding-top: 2px;
- &__overlay {
- max-width: 340px;
- .ant-popover-inner-content {
- padding: 0;
- }
- .ant-tabs-bar {
- margin-bottom: 12px;
- }
- .ant-list-item {
- padding: 12px 24px;
- transition: background-color 300ms;
- &:hover {
- background-color: #e6f7ff;
- }
- }
- .bottom-buttons {
- text-align: center;
- border-top: 1px solid #f0f0f0;
- height: 42px;
- .ant-btn {
- border: 0;
- height: 100%;
- &:first-child {
- border-right: 1px solid #f0f0f0;
- }
- }
- }
- }
- .ant-tabs-content {
- width: 300px;
- }
- .ant-badge {
- font-size: 18px;
- .ant-badge-count {
- @badget-size: 16px;
- width: @badget-size;
- height: @badget-size;
- min-width: @badget-size;
- line-height: @badget-size;
- padding: 0;
- .ant-scroll-number-only > p.ant-scroll-number-only-unit {
- font-size: 14px;
- height: @badget-size;
- }
- }
- .ant-badge-multiple-words {
- padding: 0 0 0 2px;
- font-size: 12px;
- }
- svg {
- width: 0.9em;
- }
- }
- }
- // 兼容黑暗模式
- [data-theme='dark'] .@{prefix-cls} {
- &__overlay {
- .ant-list-item {
- &:hover {
- background-color: #111b26;
- }
- }
- .bottom-buttons {
- border-top: 1px solid #303030;
- .ant-btn {
- &:first-child {
- border-right: 1px solid #303030;
- }
- }
- }
- }
- }
- </style>
|