mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-09-13 12:59:24 +08:00
feat: 重构公告及消息,公告支持系统消息推送提醒、定时发布、置顶、记录读取状态
This commit is contained in:
@@ -11,6 +11,7 @@ export interface DashboardNoticeResp {
|
|||||||
id: number
|
id: number
|
||||||
title: string
|
title: string
|
||||||
type: number
|
type: number
|
||||||
|
isTop: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 仪表盘访问趋势类型 */
|
/** 仪表盘访问趋势类型 */
|
||||||
|
@@ -9,6 +9,5 @@ export * from './storage'
|
|||||||
export * from './option'
|
export * from './option'
|
||||||
export * from './smsConfig'
|
export * from './smsConfig'
|
||||||
export * from './smsLog'
|
export * from './smsLog'
|
||||||
export * from './message'
|
|
||||||
export * from './user-profile'
|
export * from './user-profile'
|
||||||
export * from './user-message'
|
export * from './user-message'
|
||||||
|
@@ -1,31 +0,0 @@
|
|||||||
import type * as T from './type'
|
|
||||||
import http from '@/utils/http'
|
|
||||||
|
|
||||||
export type * from './type'
|
|
||||||
|
|
||||||
const BASE_URL = '/system/message'
|
|
||||||
|
|
||||||
/** @desc 查询消息列表 */
|
|
||||||
export function listMessage(query: T.MessagePageQuery) {
|
|
||||||
return http.get<PageRes<T.MessageResp[]>>(`${BASE_URL}`, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 删除消息 */
|
|
||||||
export function deleteMessage(ids: Array<string>) {
|
|
||||||
return http.del(`${BASE_URL}`, { ids })
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 标记已读 */
|
|
||||||
export function readMessage(ids: Array<string>) {
|
|
||||||
return http.patch(`${BASE_URL}/read`, { ids })
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 全部已读 */
|
|
||||||
export function readAllMessage() {
|
|
||||||
return http.patch(`${BASE_URL}/readAll`)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 查询未读消息数量 */
|
|
||||||
export function getUnreadMessageCount() {
|
|
||||||
return http.get(`${BASE_URL}/unread`)
|
|
||||||
}
|
|
@@ -12,7 +12,7 @@ export function listNotice(query: T.NoticePageQuery) {
|
|||||||
|
|
||||||
/** @desc 查询公告详情 */
|
/** @desc 查询公告详情 */
|
||||||
export function getNotice(id: string) {
|
export function getNotice(id: string) {
|
||||||
return http.get<T.NoticeResp>(`${BASE_URL}/${id}`)
|
return http.get<T.NoticeDetailResp>(`${BASE_URL}/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @desc 新增公告 */
|
/** @desc 新增公告 */
|
||||||
|
@@ -178,17 +178,22 @@ export interface DictItemPageQuery extends DictItemQuery, PageQuery {
|
|||||||
export interface NoticeResp {
|
export interface NoticeResp {
|
||||||
id?: string
|
id?: string
|
||||||
title?: string
|
title?: string
|
||||||
content: string
|
type: string
|
||||||
|
noticeScope: number
|
||||||
|
noticeMethods?: Array<number>
|
||||||
|
isTiming: boolean
|
||||||
|
publishTime?: string
|
||||||
|
isTop: boolean
|
||||||
status?: number
|
status?: number
|
||||||
type?: string
|
}
|
||||||
effectiveTime?: string
|
export type NoticeDetailResp = NoticeResp & {
|
||||||
terminateTime?: string
|
createUserString: string
|
||||||
noticeScope?: number
|
createTime: string
|
||||||
noticeUsers?: Array<string>
|
updateUserString: string
|
||||||
createUserString?: string
|
updateTime: string
|
||||||
createTime?: string
|
}
|
||||||
updateUserString?: string
|
export type NoticePreviewResp = NoticeDetailResp & {
|
||||||
updateTime?: string
|
content: string
|
||||||
}
|
}
|
||||||
export interface NoticeQuery {
|
export interface NoticeQuery {
|
||||||
title?: string
|
title?: string
|
||||||
@@ -437,6 +442,7 @@ export interface MessageResp {
|
|||||||
title: string
|
title: string
|
||||||
content: string
|
content: string
|
||||||
type: number
|
type: number
|
||||||
|
path: string
|
||||||
isRead: boolean
|
isRead: boolean
|
||||||
readTime?: string
|
readTime?: string
|
||||||
createUserString?: string
|
createUserString?: string
|
||||||
|
@@ -1,8 +1,40 @@
|
|||||||
import type * as T from './type'
|
import type * as T from './type'
|
||||||
import http from '@/utils/http'
|
import http from '@/utils/http'
|
||||||
|
|
||||||
|
export type * from './type'
|
||||||
|
|
||||||
const BASE_URL = '/user/message'
|
const BASE_URL = '/user/message'
|
||||||
|
|
||||||
|
/** @desc 查询未读消息数量 */
|
||||||
|
export function getUnreadMessageCount() {
|
||||||
|
return http.get(`${BASE_URL}/unread`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 查询消息列表 */
|
||||||
|
export function listMessage(query: T.MessagePageQuery) {
|
||||||
|
return http.get<PageRes<T.MessageResp[]>>(`${BASE_URL}`, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 删除消息 */
|
||||||
|
export function deleteMessage(ids: Array<string>) {
|
||||||
|
return http.del(`${BASE_URL}`, { ids })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 标记已读 */
|
||||||
|
export function readMessage(ids: Array<string>) {
|
||||||
|
return http.patch(`${BASE_URL}/read`, { ids })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 全部已读 */
|
||||||
|
export function readAllMessage() {
|
||||||
|
return http.patch(`${BASE_URL}/readAll`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 查询未读公告数量 */
|
||||||
|
export function getUnreadNoticeCount() {
|
||||||
|
return http.get(`${BASE_URL}/notice/unread`)
|
||||||
|
}
|
||||||
|
|
||||||
/** @desc 分页查询用户公告 */
|
/** @desc 分页查询用户公告 */
|
||||||
export function listUserNotice(query: T.NoticePageQuery) {
|
export function listUserNotice(query: T.NoticePageQuery) {
|
||||||
return http.get<PageRes<T.NoticeResp[]>>(`${BASE_URL}/notice`, query)
|
return http.get<PageRes<T.NoticeResp[]>>(`${BASE_URL}/notice`, query)
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
<a-list :loading="loading">
|
<a-list :loading="loading">
|
||||||
<template #header>通知</template>
|
<template #header>通知</template>
|
||||||
<a-list-item v-for="item in messageList" :key="item.id">
|
<a-list-item v-for="item in messageList" :key="item.id">
|
||||||
<div class="content-wrapper" @click="open">
|
<div class="content-wrapper" @click="open(item.path)">
|
||||||
<div class="content">{{ item.title }}</div>
|
<div class="content">{{ item.title }}</div>
|
||||||
<div class="date">{{ item.createTime }}</div>
|
<div class="date">{{ item.createTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -48,7 +48,11 @@ const getMessageData = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 打开消息中心
|
// 打开消息中心
|
||||||
const open = () => {
|
const open = (path?: string) => {
|
||||||
|
if (path) {
|
||||||
|
router.push(path)
|
||||||
|
return
|
||||||
|
}
|
||||||
router.push({ path: '/user/message', query: { tab: 'msg' } })
|
router.push({ path: '/user/message', query: { tab: 'msg' } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,8 +63,8 @@ export const systemRoutes: RouteRecordRaw[] = [
|
|||||||
{
|
{
|
||||||
path: '/user/notice',
|
path: '/user/notice',
|
||||||
name: 'UserNotice',
|
name: 'UserNotice',
|
||||||
component: () => import('@/views/user/message/components/detail/index.vue'),
|
component: () => import('@/views/user/message/components/view/index.vue'),
|
||||||
meta: { title: '公告详情' },
|
meta: { title: '查看公告' },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
<a-empty v-if="dataList.length === 0">暂无公告</a-empty>
|
<a-empty v-if="dataList.length === 0">暂无公告</a-empty>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div v-for="(item, idx) in dataList" :key="idx" class="item">
|
<div v-for="(item, idx) in dataList" :key="idx" class="item">
|
||||||
<GiCellTag :value="item.type" :dict="notice_type" />
|
<a-tag v-if="item.isTop" color="red">置顶</a-tag>
|
||||||
<a-link class="item-content" @click="onDetail(item.id)">
|
<a-link class="item-content" @click="onDetail(item.id)">
|
||||||
<a-typography-paragraph
|
<a-typography-paragraph
|
||||||
:ellipsis="{
|
:ellipsis="{
|
||||||
@@ -35,9 +35,6 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type DashboardNoticeResp, listDashboardNotice } from '@/apis'
|
import { type DashboardNoticeResp, listDashboardNotice } from '@/apis'
|
||||||
import { useDict } from '@/hooks/app'
|
|
||||||
|
|
||||||
const { notice_type } = useDict('notice_type')
|
|
||||||
|
|
||||||
const dataList = ref<DashboardNoticeResp[]>([])
|
const dataList = ref<DashboardNoticeResp[]>([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
61
src/views/system/notice/NoticeDetailDrawer.vue
Normal file
61
src/views/system/notice/NoticeDetailDrawer.vue
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<a-drawer v-model:visible="visible" title="公告详情" :width="width >= 500 ? 500 : '100%'" :footer="false">
|
||||||
|
<a-descriptions :column="2" size="large" class="general-description">
|
||||||
|
<a-descriptions-item label="ID" :span="2">
|
||||||
|
<a-typography-paragraph copyable>{{ dataDetail?.id }}</a-typography-paragraph>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="标题">{{ dataDetail?.title }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="分类"><GiCellTag :value="dataDetail?.type" :dict="notice_type" /></a-descriptions-item>
|
||||||
|
<a-descriptions-item label="通知范围"><GiCellTag :value="dataDetail?.noticeScope" :dict="notice_scope_enum" /></a-descriptions-item>
|
||||||
|
<a-descriptions-item label="通知方式">
|
||||||
|
<span v-if="!dataDetail?.noticeMethods">无</span>
|
||||||
|
<GiCellTags v-else :data="formatNoticeMethods(dataDetail?.noticeMethods)" />
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="是否定时">{{ dataDetail?.isTiming ? '是' : '否' }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="发布时间">{{ dataDetail?.publishTime }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="是否置顶">{{ dataDetail?.isTop ? '是' : '否' }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="状态"><GiCellTag :value="dataDetail?.status" :dict="notice_status_enum" /></a-descriptions-item>
|
||||||
|
<a-descriptions-item label="创建人">{{ dataDetail?.createUserString }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="创建时间">{{ dataDetail?.createTime }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="修改人">{{ dataDetail?.updateUserString }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="修改时间">{{ dataDetail?.updateTime }}</a-descriptions-item>
|
||||||
|
</a-descriptions>
|
||||||
|
</a-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useWindowSize } from '@vueuse/core'
|
||||||
|
import { type NoticeDetailResp, getNotice as getDetail } from '@/apis/system/notice'
|
||||||
|
import { useDict } from '@/hooks/app'
|
||||||
|
|
||||||
|
const { width } = useWindowSize()
|
||||||
|
|
||||||
|
const dataId = ref('')
|
||||||
|
const dataDetail = ref<NoticeDetailResp>()
|
||||||
|
const visible = ref(false)
|
||||||
|
const { notice_type, notice_scope_enum, notice_method_enum, notice_status_enum } = useDict('notice_type', 'notice_scope_enum', 'notice_method_enum', 'notice_status_enum')
|
||||||
|
|
||||||
|
// 格式化通知方式(转换为GiCellTags所需格式)
|
||||||
|
const formatNoticeMethods = (noticeMethods: string[]) => {
|
||||||
|
return noticeMethods.map((method) => {
|
||||||
|
const dictItem = notice_method_enum.value.find((item) => item.value === method)
|
||||||
|
return dictItem?.label || method
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 查询详情
|
||||||
|
const getDataDetail = async () => {
|
||||||
|
const { data } = await getDetail(dataId.value)
|
||||||
|
dataDetail.value = data
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开
|
||||||
|
const onOpen = async (id: string) => {
|
||||||
|
dataId.value = id
|
||||||
|
await getDataDetail()
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ onOpen })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
@@ -4,15 +4,27 @@
|
|||||||
<a-affix :target="(containerRef as HTMLElement)">
|
<a-affix :target="(containerRef as HTMLElement)">
|
||||||
<a-page-header title="通知公告" :subtitle="title" @back="onBack">
|
<a-page-header title="通知公告" :subtitle="title" @back="onBack">
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<a-button type="primary" @click="save">
|
<a-space>
|
||||||
<template #icon>
|
<a-button type="secondary" @click="onBack">
|
||||||
<icon-save v-if="isUpdate" />
|
<template #icon>
|
||||||
<icon-send v-else />
|
<icon-close />
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>取消</template>
|
||||||
{{ isUpdate ? '保存' : '发布' }}
|
</a-button>
|
||||||
</template>
|
<a-button v-if="!isUpdate || (isUpdate && form.status !== 3)" type="primary" status="warning" @click="save(true)">
|
||||||
</a-button>
|
<template #icon>
|
||||||
|
<icon-save />
|
||||||
|
</template>
|
||||||
|
<template #default>草稿</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="primary" @click="save(false)">
|
||||||
|
<template #icon>
|
||||||
|
<icon-save v-if="isUpdate && form.status === 3" />
|
||||||
|
<icon-send v-else />
|
||||||
|
</template>
|
||||||
|
<template #default>{{ isUpdate && form.status === 3 ? '保存' : '发布' }}</template>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
</a-page-header>
|
</a-page-header>
|
||||||
</a-affix>
|
</a-affix>
|
||||||
@@ -35,6 +47,9 @@
|
|||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
<template #noticeMethods>
|
||||||
|
<a-checkbox-group v-model="form.noticeMethods" :options="notice_method_enum" />
|
||||||
|
</template>
|
||||||
</GiForm>
|
</GiForm>
|
||||||
<div style="flex: 1;">
|
<div style="flex: 1;">
|
||||||
<AiEditor v-model="form.content" />
|
<AiEditor v-model="form.content" />
|
||||||
@@ -77,15 +92,18 @@ const isUpdate = computed(() => type === 'update')
|
|||||||
const title = computed(() => (isUpdate.value ? '修改' : '新增'))
|
const title = computed(() => (isUpdate.value ? '修改' : '新增'))
|
||||||
const containerRef = ref<HTMLElement | null>()
|
const containerRef = ref<HTMLElement | null>()
|
||||||
const formRef = ref<InstanceType<typeof GiForm>>()
|
const formRef = ref<InstanceType<typeof GiForm>>()
|
||||||
const { notice_type } = useDict('notice_type')
|
const { notice_type, notice_scope_enum, notice_method_enum } = useDict('notice_type', 'notice_scope_enum', 'notice_method_enum')
|
||||||
|
|
||||||
const [form, resetForm] = useResetReactive({
|
const [form, resetForm] = useResetReactive({
|
||||||
title: '',
|
title: '',
|
||||||
type: '',
|
type: '',
|
||||||
effectiveTime: '',
|
|
||||||
terminateTime: '',
|
|
||||||
content: '',
|
content: '',
|
||||||
noticeScope: 1,
|
noticeScope: 1,
|
||||||
|
noticeMethods: [1],
|
||||||
|
isTiming: false,
|
||||||
|
publishTime: undefined,
|
||||||
|
isTop: false,
|
||||||
|
status: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
const columns: ColumnItem[] = reactive([
|
const columns: ColumnItem[] = reactive([
|
||||||
@@ -93,6 +111,7 @@ const columns: ColumnItem[] = reactive([
|
|||||||
label: '标题',
|
label: '标题',
|
||||||
field: 'title',
|
field: 'title',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
|
span: 24,
|
||||||
props: {
|
props: {
|
||||||
maxLength: 150,
|
maxLength: 150,
|
||||||
showWordLimit: true,
|
showWordLimit: true,
|
||||||
@@ -100,36 +119,23 @@ const columns: ColumnItem[] = reactive([
|
|||||||
rules: [{ required: true, message: '请输入标题' }],
|
rules: [{ required: true, message: '请输入标题' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '类型',
|
label: '分类',
|
||||||
field: 'type',
|
field: 'type',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
props: {
|
props: {
|
||||||
options: notice_type,
|
options: notice_type,
|
||||||
},
|
},
|
||||||
rules: [{ required: true, message: '请输入类型' }],
|
rules: [{ required: true, message: '请选择分类' }],
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '生效时间',
|
|
||||||
field: 'effectiveTime',
|
|
||||||
type: 'date-picker',
|
|
||||||
props: {
|
|
||||||
showTime: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '终止时间',
|
|
||||||
field: 'terminateTime',
|
|
||||||
type: 'date-picker',
|
|
||||||
props: {
|
|
||||||
showTime: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '通知范围',
|
label: '通知范围',
|
||||||
field: 'noticeScope',
|
field: 'noticeScope',
|
||||||
type: 'radio-group',
|
type: 'radio-group',
|
||||||
|
disabled: () => {
|
||||||
|
return form.status === 3
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
options: [{ label: '所有人', value: 1 }, { label: '指定用户', value: 2 }],
|
options: notice_scope_enum,
|
||||||
},
|
},
|
||||||
rules: [{ required: true, message: '请选择通知范围' }],
|
rules: [{ required: true, message: '请选择通知范围' }],
|
||||||
},
|
},
|
||||||
@@ -142,6 +148,54 @@ const columns: ColumnItem[] = reactive([
|
|||||||
},
|
},
|
||||||
rules: [{ required: true, message: '请选择指定用户' }],
|
rules: [{ required: true, message: '请选择指定用户' }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '通知方式',
|
||||||
|
field: 'noticeMethods',
|
||||||
|
type: 'checkbox',
|
||||||
|
disabled: () => {
|
||||||
|
return form.status === 3
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '定时发布',
|
||||||
|
field: 'isTiming',
|
||||||
|
type: 'switch',
|
||||||
|
disabled: () => {
|
||||||
|
return form.status === 3
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
type: 'round',
|
||||||
|
checkedValue: true,
|
||||||
|
uncheckedValue: false,
|
||||||
|
checkedText: '是',
|
||||||
|
uncheckedText: '否',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '发布时间',
|
||||||
|
field: 'publishTime',
|
||||||
|
type: 'date-picker',
|
||||||
|
hide: () => {
|
||||||
|
return !form.isTiming
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
props: {
|
||||||
|
showTime: true,
|
||||||
|
placeholder: '请选择发布时间',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '置顶',
|
||||||
|
field: 'isTop',
|
||||||
|
type: 'switch',
|
||||||
|
props: {
|
||||||
|
type: 'round',
|
||||||
|
checkedValue: true,
|
||||||
|
uncheckedValue: false,
|
||||||
|
checkedText: '是',
|
||||||
|
uncheckedText: '否',
|
||||||
|
},
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
// 修改
|
// 修改
|
||||||
@@ -158,12 +212,13 @@ const onBack = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存
|
// 保存
|
||||||
const save = async () => {
|
const save = async (isDraft: boolean) => {
|
||||||
const isInvalid = await formRef.value?.formRef?.validate()
|
const isInvalid = await formRef.value?.formRef?.validate()
|
||||||
if (isInvalid) return false
|
if (isInvalid) return false
|
||||||
try {
|
try {
|
||||||
// 通知范围 所有人 去除指定用户
|
// 通知范围 所有人 去除指定用户
|
||||||
form.noticeUsers = form.noticeScope === 1 ? null : form.noticeUsers
|
form.noticeUsers = form.noticeScope === 1 ? null : form.noticeUsers
|
||||||
|
form.status = isDraft ? 1 : 3
|
||||||
if (isUpdate.value) {
|
if (isUpdate.value) {
|
||||||
await updateNotice(form, id as string)
|
await updateNotice(form, id as string)
|
||||||
Message.success('修改成功')
|
Message.success('修改成功')
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
:data="dataList"
|
:data="dataList"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:scroll="{ x: '100%', y: '100%', minWidth: 1200 }"
|
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
:disabled-tools="['size']"
|
:disabled-tools="['size']"
|
||||||
:disabled-column-keys="['title']"
|
:disabled-column-keys="['title']"
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<a-select
|
<a-select
|
||||||
v-model="queryForm.type"
|
v-model="queryForm.type"
|
||||||
:options="notice_type"
|
:options="notice_type"
|
||||||
placeholder="请选择类型"
|
placeholder="请选择分类"
|
||||||
allow-clear
|
allow-clear
|
||||||
style="width: 150px"
|
style="width: 150px"
|
||||||
@change="search"
|
@change="search"
|
||||||
@@ -32,25 +32,53 @@
|
|||||||
<template #default>新增</template>
|
<template #default>新增</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
|
<template #noticeScope="{ record }">
|
||||||
|
<GiCellTag :value="record.noticeScope" :dict="notice_scope_enum" />
|
||||||
|
</template>
|
||||||
|
<template #noticeMethods="{ record }">
|
||||||
|
<span v-if="!record.noticeMethods">无</span>
|
||||||
|
<GiCellTags v-else :data="formatNoticeMethods(record.noticeMethods)" />
|
||||||
|
</template>
|
||||||
<template #type="{ record }">
|
<template #type="{ record }">
|
||||||
<GiCellTag :value="record.type" :dict="notice_type" />
|
<GiCellTag :value="record.type" :dict="notice_type" />
|
||||||
</template>
|
</template>
|
||||||
<template #status="{ record }">
|
<template #status="{ record }">
|
||||||
<GiCellTag :value="record.status" :dict="notice_status_enum" />
|
<GiCellTag :value="record.status" :dict="notice_status_enum" />
|
||||||
</template>
|
</template>
|
||||||
|
<template #isTiming="{ record }">
|
||||||
|
<a-tag v-if="record.isTiming" color="arcoblue">是</a-tag>
|
||||||
|
<a-tag v-else color="red">否</a-tag>
|
||||||
|
</template>
|
||||||
<template #action="{ record }">
|
<template #action="{ record }">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-link v-permission="['system:notice:get']" title="详情" @click="onDetail(record)">详情</a-link>
|
<a-link v-permission="['system:notice:get']" title="详情" @click="onDetail(record)">详情</a-link>
|
||||||
<a-link v-permission="['system:notice:update']" title="修改" @click="onUpdate(record)">修改</a-link>
|
<a-link v-permission="['system:notice:view']" title="预览" @click="onView(record)">查看</a-link>
|
||||||
<a-link v-permission="['system:notice:delete']" status="danger" title="删除" @click="onDelete(record)"> 删除 </a-link>
|
<a-dropdown>
|
||||||
|
<a-button v-if="has.hasPermOr(['system:notice:update', 'system:notice:delete'])" type="text" size="mini" title="更多">
|
||||||
|
<template #icon>
|
||||||
|
<icon-more :size="16" />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<template #content>
|
||||||
|
<a-doption v-permission="['system:notice:update']">
|
||||||
|
<a-link title="修改" @click="onUpdate(record)">修改</a-link>
|
||||||
|
</a-doption>
|
||||||
|
<a-doption v-permission="['system:notice:delete']">
|
||||||
|
<a-link status="danger" title="删除" @click="onDelete(record)">删除</a-link>
|
||||||
|
</a-doption>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
</GiTable>
|
</GiTable>
|
||||||
|
|
||||||
|
<NoticeDetailDrawer ref="NoticeDetailDrawerRef" />
|
||||||
</GiPageLayout>
|
</GiPageLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TableInstance } from '@arco-design/web-vue'
|
import type { TableInstance } from '@arco-design/web-vue'
|
||||||
|
import NoticeDetailDrawer from './NoticeDetailDrawer.vue'
|
||||||
import { type NoticeQuery, type NoticeResp, deleteNotice, listNotice } from '@/apis/system'
|
import { type NoticeQuery, type NoticeResp, deleteNotice, listNotice } from '@/apis/system'
|
||||||
import { useTable } from '@/hooks'
|
import { useTable } from '@/hooks'
|
||||||
import { useDict } from '@/hooks/app'
|
import { useDict } from '@/hooks/app'
|
||||||
@@ -59,7 +87,7 @@ import has from '@/utils/has'
|
|||||||
|
|
||||||
defineOptions({ name: 'SystemNotice' })
|
defineOptions({ name: 'SystemNotice' })
|
||||||
|
|
||||||
const { notice_type, notice_status_enum } = useDict('notice_type', 'notice_status_enum')
|
const { notice_type, notice_scope_enum, notice_method_enum, notice_status_enum } = useDict('notice_type', 'notice_scope_enum', 'notice_method_enum', 'notice_status_enum')
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const queryForm = reactive<NoticeQuery>({
|
const queryForm = reactive<NoticeQuery>({
|
||||||
@@ -80,13 +108,15 @@ const columns: TableInstance['columns'] = [
|
|||||||
align: 'center',
|
align: 'center',
|
||||||
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
||||||
},
|
},
|
||||||
{ title: '标题', dataIndex: 'title', slotName: 'title', minWidth: 200, ellipsis: true, tooltip: true },
|
{ title: '公告标题', dataIndex: 'title', slotName: 'title', maxWidth: 180, ellipsis: true, tooltip: true },
|
||||||
{ title: '类型', dataIndex: 'type', slotName: 'type', align: 'center' },
|
{ title: '发布人', dataIndex: 'createUserString', maxWidth: 120, ellipsis: true, tooltip: true },
|
||||||
{ title: '状态', dataIndex: 'status', slotName: 'status', align: 'center' },
|
{ title: '通知范围', dataIndex: 'noticeScope', slotName: 'noticeScope', width: 110, align: 'center' },
|
||||||
{ title: '生效时间', dataIndex: 'effectiveTime', width: 180 },
|
{ title: '通知方式', dataIndex: 'noticeMethods', slotName: 'noticeMethods', maxWidth: 165, ellipsis: true, tooltip: true },
|
||||||
{ title: '终止时间', dataIndex: 'terminateTime', width: 180 },
|
{ title: '分类', dataIndex: 'type', slotName: 'type', maxWidth: 100, align: 'center' },
|
||||||
{ title: '创建人', dataIndex: 'createUserString', show: false, ellipsis: true, tooltip: true },
|
{ title: '状态', dataIndex: 'status', slotName: 'status', maxWidth: 100, align: 'center' },
|
||||||
{ title: '创建时间', dataIndex: 'createTime', width: 180 },
|
{ title: '是否定时', dataIndex: 'isTiming', slotName: 'isTiming', width: 110, align: 'center' },
|
||||||
|
{ title: '发布时间', dataIndex: 'publishTime', slotName: 'publishTime', width: 180 },
|
||||||
|
{ title: '是否置顶', dataIndex: 'isTop', slotName: 'isTop', show: false, maxWidth: 100, align: 'center' },
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
dataIndex: 'action',
|
dataIndex: 'action',
|
||||||
@@ -94,7 +124,7 @@ const columns: TableInstance['columns'] = [
|
|||||||
width: 160,
|
width: 160,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
fixed: !isMobile() ? 'right' : undefined,
|
fixed: !isMobile() ? 'right' : undefined,
|
||||||
show: has.hasPermOr(['system:notice:get', 'system:notice:update', 'system:notice:delete']),
|
show: has.hasPermOr(['system:notice:get', 'system:notice:view', 'system:notice:update', 'system:notice:delete']),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -123,9 +153,23 @@ const onUpdate = (record: NoticeResp) => {
|
|||||||
router.push({ path: '/system/notice/add', query: { id: record.id, type: 'update' } })
|
router.push({ path: '/system/notice/add', query: { id: record.id, type: 'update' } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NoticeDetailDrawerRef = ref<InstanceType<typeof NoticeDetailDrawer>>()
|
||||||
// 详情
|
// 详情
|
||||||
const onDetail = (record: NoticeResp) => {
|
const onDetail = (record: NoticeResp) => {
|
||||||
router.push({ path: '/system/notice/detail', query: { id: record.id } })
|
NoticeDetailDrawerRef.value?.onOpen(record.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看
|
||||||
|
const onView = (record: NoticeResp) => {
|
||||||
|
router.push({ path: '/system/notice/view', query: { id: record.id } })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化通知方式(转换为GiCellTags所需格式)
|
||||||
|
const formatNoticeMethods = (noticeMethods: string[]) => {
|
||||||
|
return noticeMethods.map((method) => {
|
||||||
|
const dictItem = notice_method_enum.value.find((item) => item.value === method)
|
||||||
|
return dictItem?.label || method
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -7,31 +7,30 @@
|
|||||||
</a-affix>
|
</a-affix>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail_content">
|
<div class="detail_content">
|
||||||
<h1 class="title">{{ form?.title }}</h1>
|
<h1 class="title">{{ dataDetail?.title }}</h1>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<a-space>
|
<a-space>
|
||||||
<span>
|
<span>
|
||||||
<icon-user class="icon" />
|
<icon-user class="icon" />
|
||||||
<span class="label">发布人:</span>
|
<span class="label">发布人:</span>
|
||||||
<span>{{ form?.createUserString }}</span>
|
<span>{{ dataDetail?.createUserString }}</span>
|
||||||
</span>
|
</span>
|
||||||
<a-divider direction="vertical" />
|
<a-divider direction="vertical" />
|
||||||
<span>
|
<span>
|
||||||
<icon-history class="icon" />
|
<icon-history class="icon" />
|
||||||
<span class="label">发布时间:</span>
|
<span class="label">发布时间:</span>
|
||||||
<span>{{ form?.effectiveTime ? form?.effectiveTime : form?.createTime
|
<span>{{ dataDetail?.publishTime }}</span>
|
||||||
}}</span>
|
|
||||||
</span>
|
</span>
|
||||||
<a-divider v-if="form?.updateTime" direction="vertical" />
|
<a-divider v-if="dataDetail?.updateTime" direction="vertical" />
|
||||||
<span v-if="form?.updateTime">
|
<span v-if="dataDetail?.updateTime">
|
||||||
<icon-schedule class="icon" />
|
<icon-schedule class="icon" />
|
||||||
<span>更新时间:</span>
|
<span>更新时间:</span>
|
||||||
<span>{{ form?.updateTime }}</span>
|
<span>{{ dataDetail?.updateTime }}</span>
|
||||||
</span>
|
</span>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
<div style="flex: 1;">
|
<div style="flex: 1;">
|
||||||
<AiEditor v-model="form.content" />
|
<AiEditor v-model="content" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -39,9 +38,8 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AiEditor from './components/index.vue'
|
import AiEditor from './components/index.vue'
|
||||||
import { getNotice } from '@/apis/system/notice'
|
import { type NoticeResp, getNotice } from '@/apis/system/notice'
|
||||||
import { useTabsStore } from '@/stores'
|
import { useTabsStore } from '@/stores'
|
||||||
import { useResetReactive } from '@/hooks'
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -49,13 +47,8 @@ const tabsStore = useTabsStore()
|
|||||||
|
|
||||||
const { id } = route.query
|
const { id } = route.query
|
||||||
const containerRef = ref<HTMLElement | null>()
|
const containerRef = ref<HTMLElement | null>()
|
||||||
const [form, resetForm] = useResetReactive({
|
const dataDetail = ref<NoticeResp>()
|
||||||
title: '',
|
const content = computed(() => dataDetail.value?.content)
|
||||||
createUserString: '',
|
|
||||||
effectiveTime: '',
|
|
||||||
createTime: '',
|
|
||||||
content: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
// 回退
|
// 回退
|
||||||
const onBack = () => {
|
const onBack = () => {
|
||||||
@@ -65,9 +58,8 @@ const onBack = () => {
|
|||||||
|
|
||||||
// 打开
|
// 打开
|
||||||
const onOpen = async (id: string) => {
|
const onOpen = async (id: string) => {
|
||||||
resetForm()
|
|
||||||
const { data } = await getNotice(id)
|
const { data } = await getNotice(id)
|
||||||
Object.assign(form, data)
|
dataDetail.value = data
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
@@ -7,7 +7,7 @@
|
|||||||
:loading="loading"
|
:loading="loading"
|
||||||
:scroll="{ x: '100%', y: '100%', minWidth: 800 }"
|
:scroll="{ x: '100%', y: '100%', minWidth: 800 }"
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
:disabled-tools="['size', 'setting']"
|
:disabled-tools="['size', 'setting', 'fullscreen']"
|
||||||
:row-selection="{ type: 'checkbox', showCheckedAll: true }"
|
:row-selection="{ type: 'checkbox', showCheckedAll: true }"
|
||||||
@select="select"
|
@select="select"
|
||||||
@select-all="selectAll"
|
@select-all="selectAll"
|
||||||
@@ -15,6 +15,15 @@
|
|||||||
>
|
>
|
||||||
<template #toolbar-left>
|
<template #toolbar-left>
|
||||||
<a-input-search v-model="queryForm.title" placeholder="搜索标题" allow-clear @search="search" />
|
<a-input-search v-model="queryForm.title" placeholder="搜索标题" allow-clear @search="search" />
|
||||||
|
<a-select
|
||||||
|
v-model="queryForm.type"
|
||||||
|
placeholder="请选择类型"
|
||||||
|
allow-clear
|
||||||
|
style="width: 150px"
|
||||||
|
:options="message_type_enum"
|
||||||
|
@change="search"
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
<a-select
|
<a-select
|
||||||
v-model="queryForm.isRead"
|
v-model="queryForm.isRead"
|
||||||
placeholder="请选择状态"
|
placeholder="请选择状态"
|
||||||
@@ -36,7 +45,7 @@
|
|||||||
删除
|
删除
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button type="primary" :disabled="!selectedKeys.length" :title="!selectedKeys.length ? '请选择' : ''" @click="onRead">
|
<a-button type="primary" :disabled="!selectedKeys.length" :title="!selectedKeys.length ? '请选择' : ''" @click="onRead">
|
||||||
标记为已读
|
标记已读
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button type="primary" :disabled="selectedKeys.length > 0" :title="!selectedKeys.length ? '请选择' : ''" @click="onReadAll">
|
<a-button type="primary" :disabled="selectedKeys.length > 0" :title="!selectedKeys.length ? '请选择' : ''" @click="onReadAll">
|
||||||
全部已读
|
全部已读
|
||||||
@@ -45,14 +54,14 @@
|
|||||||
<template #title="{ record }">
|
<template #title="{ record }">
|
||||||
<a-tooltip :content="record.content"><span>{{ record.title }}</span></a-tooltip>
|
<a-tooltip :content="record.content"><span>{{ record.title }}</span></a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
<template #type="{ record }">
|
||||||
|
<GiCellTag :value="record.type" :dict="message_type_enum" />
|
||||||
|
</template>
|
||||||
<template #isRead="{ record }">
|
<template #isRead="{ record }">
|
||||||
<a-tag :color="record.isRead ? '' : 'arcoblue'">
|
<a-tag :color="record.isRead ? '' : 'arcoblue'">
|
||||||
{{ record.isRead ? '已读' : '未读' }}
|
{{ record.isRead ? '已读' : '未读' }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #type="{ record }">
|
|
||||||
<GiCellTag :value="record.type" :dict="message_type" />
|
|
||||||
</template>
|
|
||||||
</GiTable>
|
</GiTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -66,7 +75,7 @@ import mittBus from '@/utils/mitt'
|
|||||||
|
|
||||||
defineOptions({ name: 'SystemMessage' })
|
defineOptions({ name: 'SystemMessage' })
|
||||||
|
|
||||||
const { message_type } = useDict('message_type')
|
const { message_type_enum } = useDict('message_type_enum')
|
||||||
|
|
||||||
const queryForm = reactive<MessageQuery>({
|
const queryForm = reactive<MessageQuery>({
|
||||||
sort: ['createTime,desc'],
|
sort: ['createTime,desc'],
|
||||||
@@ -94,9 +103,9 @@ const columns: TableInstance['columns'] = [
|
|||||||
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
||||||
},
|
},
|
||||||
{ title: '标题', dataIndex: 'title', slotName: 'title', minWidth: 100, ellipsis: true, tooltip: true },
|
{ title: '标题', dataIndex: 'title', slotName: 'title', minWidth: 100, ellipsis: true, tooltip: true },
|
||||||
|
{ title: '类型', dataIndex: 'type', slotName: 'type', width: 180, ellipsis: true, tooltip: true },
|
||||||
{ title: '状态', dataIndex: 'isRead', slotName: 'isRead', minWidth: 100, align: 'center' },
|
{ title: '状态', dataIndex: 'isRead', slotName: 'isRead', minWidth: 100, align: 'center' },
|
||||||
{ title: '时间', dataIndex: 'createTime', width: 180 },
|
{ title: '时间', dataIndex: 'createTime', width: 180 },
|
||||||
{ title: '类型', dataIndex: 'type', slotName: 'type', width: 180, ellipsis: true, tooltip: true },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// 重置
|
// 重置
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
</a-button>
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
<template #title="{ record }">
|
<template #title="{ record }">
|
||||||
<a-link @click="onDetail(record)">
|
<a-link @click="onView(record)">
|
||||||
<a-typography-paragraph
|
<a-typography-paragraph
|
||||||
class="link-text"
|
class="link-text"
|
||||||
:ellipsis="{
|
:ellipsis="{
|
||||||
@@ -41,6 +41,11 @@
|
|||||||
<template #type="{ record }">
|
<template #type="{ record }">
|
||||||
<GiCellTag :value="record.type" :dict="notice_type" />
|
<GiCellTag :value="record.type" :dict="notice_type" />
|
||||||
</template>
|
</template>
|
||||||
|
<template #isRead="{ record }">
|
||||||
|
<a-tag :color="record.isRead ? '' : 'arcoblue'">
|
||||||
|
{{ record.isRead ? '已读' : '未读' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
</GiTable>
|
</GiTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -72,10 +77,11 @@ const columns: TableInstance['columns'] = [
|
|||||||
align: 'center',
|
align: 'center',
|
||||||
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
||||||
},
|
},
|
||||||
{ title: '标题', dataIndex: 'title', slotName: 'title', ellipsis: true, tooltip: true },
|
{ title: '公告标题', dataIndex: 'title', slotName: 'title', ellipsis: true, tooltip: true },
|
||||||
{ title: '类型', dataIndex: 'type', slotName: 'type', align: 'center' },
|
{ title: '分类', dataIndex: 'type', slotName: 'type', align: 'center' },
|
||||||
|
{ title: '状态', dataIndex: 'isRead', slotName: 'isRead', align: 'center' },
|
||||||
{ title: '发布人', dataIndex: 'createUserString', ellipsis: true, tooltip: true },
|
{ title: '发布人', dataIndex: 'createUserString', ellipsis: true, tooltip: true },
|
||||||
{ title: '发布时间', dataIndex: 'createTime', width: 180 },
|
{ title: '发布时间', dataIndex: 'publishTime', width: 180 },
|
||||||
]
|
]
|
||||||
|
|
||||||
// 重置
|
// 重置
|
||||||
@@ -86,8 +92,8 @@ const reset = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
// 详情
|
// 查看
|
||||||
const onDetail = (record: NoticeResp) => {
|
const onView = (record: NoticeResp) => {
|
||||||
router.push({ path: '/user/notice', query: { id: record.id } })
|
router.push({ path: '/user/notice', query: { id: record.id } })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -29,7 +29,10 @@ import { useRoute, useRouter } from 'vue-router'
|
|||||||
import MyMessage from './components/MyMessage.vue'
|
import MyMessage from './components/MyMessage.vue'
|
||||||
import MyNotice from './components/MyNotice.vue'
|
import MyNotice from './components/MyNotice.vue'
|
||||||
import { useDevice } from '@/hooks'
|
import { useDevice } from '@/hooks'
|
||||||
import { type MessageResp, type NoticeResp, listMessage, listNotice } from '@/apis'
|
import {
|
||||||
|
getUnreadMessageCount,
|
||||||
|
getUnreadNoticeCount,
|
||||||
|
} from '@/apis'
|
||||||
import mittBus from '@/utils/mitt'
|
import mittBus from '@/utils/mitt'
|
||||||
|
|
||||||
defineOptions({ name: 'UserMessage' })
|
defineOptions({ name: 'UserMessage' })
|
||||||
@@ -51,35 +54,22 @@ const TabPaneTitle = defineComponent({
|
|||||||
|
|
||||||
const { isDesktop } = useDevice()
|
const { isDesktop } = useDevice()
|
||||||
|
|
||||||
const messageList = ref<MessageResp[]>()
|
const unreadMessageCount = ref(0)
|
||||||
const noticeList = ref<NoticeResp[]>()
|
const unreadNoticeCount = ref(0)
|
||||||
|
|
||||||
const tabItems = computed(() => [
|
const tabItems = computed(() => [
|
||||||
{ key: 'msg', title: '我的消息', count: messageList.value?.length ?? 0 },
|
{ key: 'msg', title: '我的消息', count: unreadMessageCount },
|
||||||
{ key: 'notice', title: '我的公告' },
|
{ key: 'notice', title: '我的公告', count: unreadNoticeCount },
|
||||||
])
|
])
|
||||||
|
|
||||||
const messageQueryParam = reactive({
|
|
||||||
isRead: false,
|
|
||||||
sort: ['createTime,desc'],
|
|
||||||
page: 1,
|
|
||||||
size: 5,
|
|
||||||
})
|
|
||||||
|
|
||||||
const noticeQueryParam = reactive({
|
|
||||||
sort: ['createTime,desc'],
|
|
||||||
page: 1,
|
|
||||||
size: 5,
|
|
||||||
})
|
|
||||||
|
|
||||||
const getMessageData = async () => {
|
const getMessageData = async () => {
|
||||||
const { data } = await listMessage(messageQueryParam)
|
const { data } = await getUnreadMessageCount()
|
||||||
messageList.value = data.list.filter((item) => !item.isRead)
|
unreadMessageCount.value = data.total
|
||||||
}
|
}
|
||||||
|
|
||||||
const getNoticeData = async () => {
|
const getNoticeData = async () => {
|
||||||
const { data } = await listNotice(noticeQueryParam)
|
const { data } = await getUnreadNoticeCount()
|
||||||
noticeList.value = data.list
|
unreadNoticeCount.value = data.total
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
Reference in New Issue
Block a user