From 0e44af89b9b47c5e3f955b9208ff2c2f1f0d24af Mon Sep 17 00:00:00 2001 From: dap1 <15891557205@163.com> Date: Fri, 19 May 2023 18:07:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20header=E4=B8=8A=E7=9A=84=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=E5=8F=8A=E4=B8=AA=E4=BA=BA=E7=AB=99=E5=86=85=E4=BF=A1?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/system/notify/message.ts | 2 +- src/enums/pageEnum.ts | 3 +- .../header/components/notify/index.vue | 93 +++++------------- src/store/modules/userMessage.ts | 24 +++++ src/utils/dict.ts | 1 + src/views/infra/fileConfig/index.vue | 1 + .../MessageInfoModal.vue | 2 +- .../system/notify/components/message.data.ts | 97 +++++++++++++++++++ src/views/system/notify/message/index.vue | 2 +- src/views/system/notify/my/index.vue | 78 ++++++++++++--- src/views/system/notify/my/my.data.ts | 2 +- 11 files changed, 220 insertions(+), 85 deletions(-) create mode 100644 src/store/modules/userMessage.ts rename src/views/system/notify/{message => components}/MessageInfoModal.vue (90%) create mode 100644 src/views/system/notify/components/message.data.ts diff --git a/src/api/system/notify/message.ts b/src/api/system/notify/message.ts index 07cda56e..2852fe29 100644 --- a/src/api/system/notify/message.ts +++ b/src/api/system/notify/message.ts @@ -28,5 +28,5 @@ export function getUnreadNotifyMessageList() { // 获得当前用户的未读站内信数量 export function getUnreadNotifyMessageCount() { - return defHttp.get({ url: '/system/notify-message/get-unread-count' }) + return defHttp.get<number>({ url: '/system/notify-message/get-unread-count' }) } diff --git a/src/enums/pageEnum.ts b/src/enums/pageEnum.ts index d329ec4a..e1da8e39 100644 --- a/src/enums/pageEnum.ts +++ b/src/enums/pageEnum.ts @@ -6,5 +6,6 @@ export enum PageEnum { // error page path ERROR_PAGE = '/exception', // error log page path - ERROR_LOG_PAGE = '/error-log/list' + ERROR_LOG_PAGE = '/error-log/list', + MESSAGE_PAGE = '/profile/notify-message' } diff --git a/src/layouts/default/header/components/notify/index.vue b/src/layouts/default/header/components/notify/index.vue index 646f52c3..51fdbfa2 100644 --- a/src/layouts/default/header/components/notify/index.vue +++ b/src/layouts/default/header/components/notify/index.vue @@ -1,80 +1,35 @@ <template> - <div :class="prefixCls"> - <Popover title="" trigger="click" :overlayClassName="`${prefixCls}__overlay`"> - <Badge :count="count" dot :numberStyle="numberStyle"> + <div> + <Tooltip :title="tips"> + <Badge :count="unreadCount" :offset="[0, 15]" size="small" @click="go({ path: PageEnum.MESSAGE_PAGE })"> <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.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> + </Tooltip> </div> </template> <script lang="ts" setup> -import { computed, ref } from 'vue' -import { Popover, Tabs, Badge } from 'ant-design-vue' +import { onMounted, computed } from 'vue' +import { Badge, Tooltip } from 'ant-design-vue' import { BellOutlined } from '@ant-design/icons-vue' -import { tabListData, ListItem } from './data' -import NoticeList from './NoticeList.vue' -import { useDesign } from '@/hooks/web/useDesign' -import { useMessage } from '@/hooks/web/useMessage' - -const TabPane = Tabs.TabPane -const numberStyle = ref({}) -const { prefixCls } = useDesign('header-notify') -const { createMessage } = useMessage() -const listData = ref(tabListData) - -const count = computed(() => { - let count = 0 - for (let i = 0; i < tabListData.length; i++) { - count += tabListData[i].list.length +import { useGo } from '@/hooks/web/usePage' +import { PageEnum } from '@/enums/pageEnum' +import { useUserMessageStore } from '@/store/modules/userMessage' +import { storeToRefs } from 'pinia' + +const go = useGo() + +const store = useUserMessageStore() +const { unreadCount } = storeToRefs(store) +const tips = computed<string>(() => { + if (unreadCount.value === 0) { + return '查看站内信' } - return count + return `查看站内信: 未读 ${unreadCount.value} 条` }) -function onNoticeClick(record: ListItem) { - createMessage.success('你点击了通知,ID=' + record.id) - // 可以直接将其标记为已读(为标题添加删除线),此处演示的代码会切换删除线状态 - record.titleDelete = !record.titleDelete -} +onMounted(async () => { + // 通过store进行更新 + store.updateUnreadCount() +}) </script> -<style lang="less"> -@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> +<style lang="less"></style> diff --git a/src/store/modules/userMessage.ts b/src/store/modules/userMessage.ts new file mode 100644 index 00000000..4a24041e --- /dev/null +++ b/src/store/modules/userMessage.ts @@ -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 + } + } +}) diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 853d8bac..7088efec 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -53,6 +53,7 @@ export function getDictOpts(dictType: string) { export function getDictOptions(dictType: string, valueType?: 'string' | 'number' | 'boolean') { const dictOption: DictDataType[] = [] const dictOptions: DictDataType[] = getDictDatas(dictType) + console.log(dictOptions) if (dictOptions && dictOptions.length > 0) { dictOptions.forEach((dict: DictDataType) => { dictOption.push({ diff --git a/src/views/infra/fileConfig/index.vue b/src/views/infra/fileConfig/index.vue index 8ed8659d..77f5b557 100644 --- a/src/views/infra/fileConfig/index.vue +++ b/src/views/infra/fileConfig/index.vue @@ -93,6 +93,7 @@ function handleMaster(record: Recordable) { async onOk() { await updateFileConfigMaster(record.id) createMessage.success('配置成功') + reload() } }) } diff --git a/src/views/system/notify/message/MessageInfoModal.vue b/src/views/system/notify/components/MessageInfoModal.vue similarity index 90% rename from src/views/system/notify/message/MessageInfoModal.vue rename to src/views/system/notify/components/MessageInfoModal.vue index 7dbff81b..887ebd3f 100644 --- a/src/views/system/notify/message/MessageInfoModal.vue +++ b/src/views/system/notify/components/MessageInfoModal.vue @@ -1,5 +1,5 @@ <template> - <BasicModal title="详情" @register="innerRegister"> + <BasicModal title="站内信详情" @register="innerRegister"> <Description @register="descriptionRegister" /> </BasicModal> </template> diff --git a/src/views/system/notify/components/message.data.ts b/src/views/system/notify/components/message.data.ts new file mode 100644 index 00000000..4f1c07ea --- /dev/null +++ b/src/views/system/notify/components/message.data.ts @@ -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 +} diff --git a/src/views/system/notify/message/index.vue b/src/views/system/notify/message/index.vue index 25d48c44..8f7a0d0e 100644 --- a/src/views/system/notify/message/index.vue +++ b/src/views/system/notify/message/index.vue @@ -24,7 +24,7 @@ import { useI18n } from '@/hooks/web/useI18n' import { BasicTable, useTable, TableAction } from '@/components/Table' import { getNotifyMessagePage } from '@/api/system/notify/message' import { columns, searchFormSchema } from './message.data' -import MessageInfoModal from './MessageInfoModal.vue' +import MessageInfoModal from '@/views/system/notify/components/MessageInfoModal.vue' import { useModal } from '@/components/Modal' defineOptions({ name: 'SystemMessage' }) diff --git a/src/views/system/notify/my/index.vue b/src/views/system/notify/my/index.vue index 60ea3aa7..072654ea 100644 --- a/src/views/system/notify/my/index.vue +++ b/src/views/system/notify/my/index.vue @@ -1,16 +1,38 @@ <template> <div> - <BasicTable @register="registerTable"> + <BasicTable @register="registerTable" bordered> <template #toolbar> - <a-button type="primary" @click="handleUpdateList"> 标记已读 </a-button> - <a-button type="primary" @click="handleUpdateAll"> 全部已读 </a-button> + <a-button preIcon="solar:check-read-line-duotone" type="primary" @click="handleUpdateList" :disabled="readedDisabled"> + 标记已读 + </a-button> + <a-button preIcon="solar:check-read-linear" type="primary" @click="handleUpdateAll"> 全部已读 </a-button> </template> <template #bodyCell="{ column, record }"> <template v-if="column.key === 'action'"> - <TableAction :actions="[{ icon: IconEnum.EDIT, label: '已读', onClick: handleUpdateSingle.bind(null, record) }]" /> + <!--阻止事件冒泡 勾选框 --> + <TableAction + stopButtonPropagation + :actions="[ + { + icon: IconEnum.EDIT, + label: '已读', + color: 'warning', + ifShow: () => { + return !record.readStatus + }, + onClick: handleUpdateSingle.bind(null, record) + }, + { + icon: IconEnum.LOG, + label: '详情', + onClick: handleInfo.bind(null, record) + } + ]" + /> </template> </template> </BasicTable> + <MessageInfoModal @register="registerModal" /> </div> </template> <script lang="ts" setup> @@ -20,18 +42,32 @@ import { IconEnum } from '@/enums/appEnum' import { BasicTable, useTable, TableAction } from '@/components/Table' import { getMyNotifyMessagePage, updateAllNotifyMessageRead, updateNotifyMessageRead } from '@/api/system/notify/message' import { columns, searchFormSchema } from './my.data' +import MessageInfoModal from '@/views/system/notify/components/MessageInfoModal.vue' +import { useModal } from '@/components/Modal' +import { computed } from 'vue' +import { useUserMessageStore } from '@/store/modules/userMessage' defineOptions({ name: 'SystemMyMessage' }) const { t } = useI18n() const { createMessage } = useMessage() +const [registerModal, { openModal }] = useModal() +const store = useUserMessageStore() -const [registerTable, { getSelectRowKeys, reload }] = useTable({ +const [registerTable, { getSelectRowKeys, clearSelectedRowKeys, reload }] = useTable({ title: '我的站内信列表', api: getMyNotifyMessagePage, columns, - formConfig: { labelWidth: 120, schemas: searchFormSchema }, - rowSelection: { type: 'checkbox' }, + formConfig: { labelWidth: 130, schemas: searchFormSchema }, + rowSelection: { + type: 'checkbox', + getCheckboxProps: (record: Recordable) => { + return { + // 已读的消息disabled 不可选 + disabled: record.readStatus + } + } + }, rowKey: 'id', useSearchForm: true, showTableSetting: true, @@ -44,6 +80,13 @@ const [registerTable, { getSelectRowKeys, reload }] = useTable({ } }) +/** + * 已读按钮的disabled 未选中则disabled + */ +const readedDisabled = computed<boolean>(() => { + return getSelectRowKeys().length === 0 +}) + function handleUpdateList() { const ids = getSelectRowKeys() handleUpdate(ids) @@ -53,15 +96,28 @@ async function handleUpdateSingle(record: Recordable) { await handleUpdate([record.id]) } +function afterRead(msg: string) { + createMessage.success(msg) + // 更新未读消息 + store.updateUnreadCount() + // 重加载表格 + reload() + // 清除选中的行 + clearSelectedRowKeys() +} + async function handleUpdate(ids) { await updateNotifyMessageRead(ids) - createMessage.success('标记已读成功!') - reload() + afterRead('标记已读成功!') } async function handleUpdateAll() { await updateAllNotifyMessageRead() - createMessage.success('全部已读成功!') - reload() + afterRead('全部已读成功!') +} + +const handleInfo = (record: any) => { + console.log(JSON.stringify(record, Object.keys(record), 2)) + openModal(true, record) } </script> diff --git a/src/views/system/notify/my/my.data.ts b/src/views/system/notify/my/my.data.ts index c9533f6e..1a5e9251 100644 --- a/src/views/system/notify/my/my.data.ts +++ b/src/views/system/notify/my/my.data.ts @@ -31,7 +31,7 @@ export const columns: BasicColumn[] = [ { title: '是否已读', dataIndex: 'readStatus', - width: 180, + width: 100, customRender: ({ text }) => { return useRender.renderDict(text, DICT_TYPE.INFRA_BOOLEAN_STRING) }