11 changed files with 220 additions and 85 deletions
			
			
		@ -1,80 +1,35 @@ | 
				
			|||||||
<template> | 
					<template> | 
				
			||||||
  <div :class="prefixCls"> | 
					  <div> | 
				
			||||||
    <Popover title="" trigger="click" :overlayClassName="`${prefixCls}__overlay`"> | 
					    <Tooltip :title="tips"> | 
				
			||||||
      <Badge :count="count" dot :numberStyle="numberStyle"> | 
					      <Badge :count="unreadCount" :offset="[0, 15]" size="small" @click="go({ path: PageEnum.MESSAGE_PAGE })"> | 
				
			||||||
        <BellOutlined /> | 
					        <BellOutlined /> | 
				
			||||||
      </Badge> | 
					      </Badge> | 
				
			||||||
      <template #content> | 
					    </Tooltip> | 
				
			||||||
        <Tabs> | 
					 | 
				
			||||||
          <template v-for="item in listData" :key="item.key"> | 
					 | 
				
			||||||
            <TabPane> | 
					 | 
				
			||||||
              <template #tab> | 
					 | 
				
			||||||
                {{ item.name }} | 
					 | 
				
			||||||
                <span v-if="item.list.length !== 0">({{ item.list.length }})</span> | 
					 | 
				
			||||||
              </template> | 
					 | 
				
			||||||
              <!-- 绑定title-click事件的通知列表中标题是“可点击”的--> | 
					 | 
				
			||||||
              <NoticeList :list="item.list" v-if="item.key === '1'" @title-click="onNoticeClick" /> | 
					 | 
				
			||||||
              <NoticeList :list="item.list" v-else /> | 
					 | 
				
			||||||
            </TabPane> | 
					 | 
				
			||||||
          </template> | 
					 | 
				
			||||||
        </Tabs> | 
					 | 
				
			||||||
      </template> | 
					 | 
				
			||||||
    </Popover> | 
					 | 
				
			||||||
  </div> | 
					  </div> | 
				
			||||||
</template> | 
					</template> | 
				
			||||||
<script lang="ts" setup> | 
					<script lang="ts" setup> | 
				
			||||||
import { computed, ref } from 'vue' | 
					import { onMounted, computed } from 'vue' | 
				
			||||||
import { Popover, Tabs, Badge } from 'ant-design-vue' | 
					import { Badge, Tooltip } from 'ant-design-vue' | 
				
			||||||
import { BellOutlined } from '@ant-design/icons-vue' | 
					import { BellOutlined } from '@ant-design/icons-vue' | 
				
			||||||
import { tabListData, ListItem } from './data' | 
					import { useGo } from '@/hooks/web/usePage' | 
				
			||||||
import NoticeList from './NoticeList.vue' | 
					import { PageEnum } from '@/enums/pageEnum' | 
				
			||||||
import { useDesign } from '@/hooks/web/useDesign' | 
					import { useUserMessageStore } from '@/store/modules/userMessage' | 
				
			||||||
import { useMessage } from '@/hooks/web/useMessage' | 
					import { storeToRefs } from 'pinia' | 
				
			||||||
 | 
					
 | 
				
			||||||
const TabPane = Tabs.TabPane | 
					const go = useGo() | 
				
			||||||
const numberStyle = ref({}) | 
					
 | 
				
			||||||
const { prefixCls } = useDesign('header-notify') | 
					const store = useUserMessageStore() | 
				
			||||||
const { createMessage } = useMessage() | 
					const { unreadCount } = storeToRefs(store) | 
				
			||||||
const listData = ref(tabListData) | 
					const tips = computed<string>(() => { | 
				
			||||||
 | 
					  if (unreadCount.value === 0) { | 
				
			||||||
const count = computed(() => { | 
					    return '查看站内信' | 
				
			||||||
  let count = 0 | 
					 | 
				
			||||||
  for (let i = 0; i < tabListData.length; i++) { | 
					 | 
				
			||||||
    count += tabListData[i].list.length | 
					 | 
				
			||||||
  } | 
					  } | 
				
			||||||
  return count | 
					  return `查看站内信: 未读 ${unreadCount.value} 条` | 
				
			||||||
}) | 
					}) | 
				
			||||||
 | 
					
 | 
				
			||||||
function onNoticeClick(record: ListItem) { | 
					onMounted(async () => { | 
				
			||||||
  createMessage.success('你点击了通知,ID=' + record.id) | 
					  // 通过store进行更新 | 
				
			||||||
  // 可以直接将其标记为已读(为标题添加删除线),此处演示的代码会切换删除线状态 | 
					  store.updateUnreadCount() | 
				
			||||||
  record.titleDelete = !record.titleDelete | 
					}) | 
				
			||||||
} | 
					 | 
				
			||||||
</script> | 
					</script> | 
				
			||||||
<style lang="less"> | 
					<style lang="less"></style> | 
				
			||||||
@prefix-cls: ~'@{namespace}-header-notify'; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.@{prefix-cls} { | 
					 | 
				
			||||||
  padding-top: 2px; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  &__overlay { | 
					 | 
				
			||||||
    max-width: 360px; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .ant-tabs-content { | 
					 | 
				
			||||||
    width: 300px; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .ant-badge { | 
					 | 
				
			||||||
    font-size: 18px; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .ant-badge-multiple-words { | 
					 | 
				
			||||||
      padding: 0 4px; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    svg { | 
					 | 
				
			||||||
      width: 0.9em; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
</style> | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,24 @@ | 
				
			|||||||
 | 
					import { defineStore } from 'pinia' | 
				
			||||||
 | 
					import { getUnreadNotifyMessageCount } from '@/api/system/notify/message' | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MessageState = { | 
				
			||||||
 | 
					  unreadCount: number // 未读消息数量
 | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useUserMessageStore = defineStore('userMessage', { | 
				
			||||||
 | 
					  state: (): MessageState => ({ | 
				
			||||||
 | 
					    unreadCount: 0 | 
				
			||||||
 | 
					  }), | 
				
			||||||
 | 
					  getters: { | 
				
			||||||
 | 
					    getUnreadCount(state) { | 
				
			||||||
 | 
					      return state.unreadCount | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  actions: { | 
				
			||||||
 | 
					    // 更新未读消息的数量
 | 
				
			||||||
 | 
					    async updateUnreadCount() { | 
				
			||||||
 | 
					      const count = await getUnreadNotifyMessageCount() | 
				
			||||||
 | 
					      this.unreadCount = count | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}) | 
				
			||||||
@ -1,5 +1,5 @@ | 
				
			|||||||
<template> | 
					<template> | 
				
			||||||
  <BasicModal title="详情" @register="innerRegister"> | 
					  <BasicModal title="站内信详情" @register="innerRegister"> | 
				
			||||||
    <Description @register="descriptionRegister" /> | 
					    <Description @register="descriptionRegister" /> | 
				
			||||||
  </BasicModal> | 
					  </BasicModal> | 
				
			||||||
</template> | 
					</template> | 
				
			||||||
@ -0,0 +1,97 @@ | 
				
			|||||||
 | 
					import { useRender } from '@/components/Table' | 
				
			||||||
 | 
					import { DICT_TYPE } from '@/utils/dict' | 
				
			||||||
 | 
					import { JsonPreview } from '@/components/CodeEditor' | 
				
			||||||
 | 
					import { DescItem } from '@/components/Description/index' | 
				
			||||||
 | 
					import { h } from 'vue' | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 站内信详情modal
 | 
				
			||||||
 | 
					export const infoSchema: DescItem[] = [ | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'id', | 
				
			||||||
 | 
					    label: '编号', | 
				
			||||||
 | 
					    labelMinWidth: 50 | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'readStatus', | 
				
			||||||
 | 
					    label: '是否已读', | 
				
			||||||
 | 
					    render: (value) => { | 
				
			||||||
 | 
					      return useRender.renderDict(value, DICT_TYPE.INFRA_BOOLEAN_STRING) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'userType', | 
				
			||||||
 | 
					    label: '用户类型', | 
				
			||||||
 | 
					    render: (value) => { | 
				
			||||||
 | 
					      console.log(value) | 
				
			||||||
 | 
					      return useRender.renderDict(value, DICT_TYPE.USER_TYPE) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'userType', | 
				
			||||||
 | 
					    label: '用户编号' | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'templateId', | 
				
			||||||
 | 
					    label: '模板编号' | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'templateCode', | 
				
			||||||
 | 
					    label: '模板编码' | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'templateNickname', | 
				
			||||||
 | 
					    label: '发送人名称' | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'templateContent', | 
				
			||||||
 | 
					    label: '模板内容' | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'templateParams', | 
				
			||||||
 | 
					    label: '模板参数', | 
				
			||||||
 | 
					    render: (value) => { | 
				
			||||||
 | 
					      return h(JsonPreview, { data: value }) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'templateType', | 
				
			||||||
 | 
					    label: '模板类型', | 
				
			||||||
 | 
					    render: (value) => { | 
				
			||||||
 | 
					      return useRender.renderDict(value, DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'readTime', | 
				
			||||||
 | 
					    label: '阅读时间', | 
				
			||||||
 | 
					    render: (value) => { | 
				
			||||||
 | 
					      if (!value) { | 
				
			||||||
 | 
					        return useRender.renderTag('未阅读') | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					      return useRender.renderDate(value) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { | 
				
			||||||
 | 
					    field: 'createTime', | 
				
			||||||
 | 
					    label: '创建时间', | 
				
			||||||
 | 
					    render: (value) => { | 
				
			||||||
 | 
					      return useRender.renderDate(value) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					] | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 站内信详情
 | 
				
			||||||
 | 
					export interface MessageInfo { | 
				
			||||||
 | 
					  userId: number | 
				
			||||||
 | 
					  userType: number | 
				
			||||||
 | 
					  templateId: number | 
				
			||||||
 | 
					  templateCode: string | 
				
			||||||
 | 
					  templateNickname: string | 
				
			||||||
 | 
					  templateContent: string | 
				
			||||||
 | 
					  templateType: number | 
				
			||||||
 | 
					  templateParams: { [key: string]: string } | 
				
			||||||
 | 
					  readStatus: boolean | 
				
			||||||
 | 
					  readTime?: any | 
				
			||||||
 | 
					  id: number | 
				
			||||||
 | 
					  createTime: number | 
				
			||||||
 | 
					  key: string | 
				
			||||||
 | 
					} | 
				
			||||||
		Reference in new issue