This commit is contained in:
秋帆
2024-05-19 23:25:43 +08:00
10 changed files with 208 additions and 20 deletions

View File

@@ -8,3 +8,4 @@ export * from './file'
export * from './storage'
export * from './option'
export * from './user-center'
export * from './message'

View File

@@ -0,0 +1,19 @@
import type * as System from './type'
import http from '@/utils/http'
const BASE_URL = '/system/message'
/** @desc 查询消息列表 */
export function listMessage(query: System.MessagePageQuery) {
return http.get<PageRes<System.MessageResp[]>>(`${BASE_URL}`, query)
}
/** @desc 删除消息 */
export function deleteMessage(ids: string | Array<string>) {
return http.del(`${BASE_URL}/${ids}`)
}
/** @desc 标记已读 */
export function readMessage(ids: string | Array<string>) {
return http.patch(`${BASE_URL}/read`, ids)
}

View File

@@ -297,3 +297,25 @@ export interface BindSocialAccountRes {
source: string
description: string
}
/** 系统消息类型 */
export interface MessageResp {
id: string
title: string
content: string
type: number
isRead: boolean
readTime: string
createUserString: string
createTime: string
}
export interface MessageQuery {
title?: string
type?: number
isRead?: boolean
sort: Array<string>
}
export interface MessagePageQuery extends MessageQuery, PageQuery {
}

View File

@@ -1,5 +1,5 @@
import type * as System from './type'
import http from '@/utils/http'
import type * as System from '@/apis/system/type'
const BASE_URL = '/system/user'

View File

@@ -63,6 +63,12 @@ export const constantRoutes: RouteRecordRaw[] = [
name: 'SettingProfile',
component: () => import('@/views/setting/profile/index.vue'),
meta: { title: '个人中心', showInTabs: false }
},
{
path: '/setting/message',
name: 'SettingMessage',
component: () => import('@/views/setting/message/index.vue'),
meta: { title: '消息中心', showInTabs: false }
}
]
}

View File

@@ -0,0 +1,140 @@
<template>
<div class="table-page">
<GiTable
row-key="id"
title="消息中心"
:data="dataList"
:columns="columns"
:loading="loading"
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
:pagination="pagination"
:disabled-tools="['size', 'setting']"
:disabled-column-keys="['name']"
:row-selection="{ type: 'checkbox', showCheckedAll: true }"
:selected-keys="selectedKeys"
@select-all="selectAll"
@select="select"
@refresh="search"
>
<template #custom-left>
<a-input v-model="queryForm.title" placeholder="请输入标题" allow-clear @change="search">
<template #prefix><icon-search /></template>
</a-input>
<a-select
v-model="queryForm.isRead"
placeholder="请选择状态"
allow-clear
style="width: 150px"
@change="search"
>
<a-option :value="false">未读</a-option>
<a-option :value="true">已读</a-option>
</a-select>
<a-button @click="reset">重置</a-button>
</template>
<template #custom-right>
<a-button type="primary" status="danger" :disabled="!selectedKeys.length" @click="onDelete">
<template #icon><icon-delete /></template>
<span>删除</span>
</a-button>
<a-button type="primary" :disabled="!selectedKeys.length" @click="onRead">
<span>标记为已读</span>
</a-button>
<a-button type="primary" :disabled="selectedKeys.length" @click="onReadAll">全部已读</a-button>
</template>
<template #title="{ record }">
<a-tooltip :content="record.content"><span>{{ record.title }}</span></a-tooltip>
</template>
<template #isRead="{ record }">
<a-tag v-if="record.isRead">已读</a-tag>
<a-tag v-else color="arcoblue">未读</a-tag>
</template>
<template #type="{ record }">
<GiCellTag :value="record.type" :dict="message_type" />
</template>
</GiTable>
</div>
</template>
<script setup lang="ts">
import { Message, Modal } from '@arco-design/web-vue'
import { type MessageQuery, deleteMessage, listMessage, readMessage } from '@/apis'
import type { TableInstanceColumns } from '@/components/GiTable/type'
import { useTable } from '@/hooks'
import { useDict } from '@/hooks/app'
defineOptions({ name: 'SystemMessage' })
const { message_type } = useDict('message_type')
const queryForm = reactive<MessageQuery>({
sort: ['createTime,desc']
})
const {
tableData: dataList,
loading,
pagination,
selectedKeys,
select,
selectAll,
search,
handleDelete
} = useTable((page) => listMessage({ ...queryForm, ...page }), { immediate: true })
const columns: TableInstanceColumns[] = [
{
title: '序号',
width: 66,
align: 'center',
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize)
},
{ title: '标题', dataIndex: 'title', slotName: 'title', ellipsis: true, tooltip: true },
{ title: '状态', dataIndex: 'isRead', slotName: 'isRead', align: 'center', width: 80 },
{ title: '时间', dataIndex: 'createTime', width: 180 },
{ title: '类型', dataIndex: 'type', slotName: 'type', width: 180, ellipsis: true, tooltip: true }
]
// 重置
const reset = () => {
queryForm.title = undefined
queryForm.type = undefined
queryForm.isRead = undefined
search()
}
// 删除
const onDelete = () => {
if (!selectedKeys.value.length) {
return Message.warning('请选择数据')
}
return handleDelete(() => deleteMessage(selectedKeys.value), { showModal: false })
}
// 标记为已读
const onRead = async () => {
if (!selectedKeys.value.length) {
return Message.warning('请选择数据')
}
await readMessage(selectedKeys.value)
Message.success('操作成功')
search()
}
// 全部已读
const onReadAll = async () => {
Modal.warning({
title: '全部已读',
content: '确定要标记全部消息为已读吗?',
hideCancel: false,
maskClosable: false,
onOk: async () => {
await readMessage([])
Message.success('操作成功')
search()
}
})
}
</script>
<style lang="scss" scoped></style>

View File

@@ -94,7 +94,7 @@ const columns: TableInstanceColumns[] = [
},
{ title: '标签', dataIndex: 'label', slotName: 'label', width: 100, align: 'center' },
{ title: '值', dataIndex: 'value', width: 100, align: 'center', ellipsis: true, tooltip: true },
{ title: '状态', slotName: 'status', width: 90, align: 'center' },
{ title: '状态', slotName: 'status', width: 80, align: 'center' },
{
title: '排序',
dataIndex: 'sort',

View File

@@ -13,9 +13,9 @@
<a-trigger v-model:popup-visible="node.popupVisible" trigger="contextMenu" align-point
animation-name="slide-dynamic-origin" auto-fit-transform-origin position="bl" scroll-to-close>
<a-tooltip v-if="node.description" :content="node.description" background-color="rgb(var(--primary-6))" position="right">
<div @contextmenu="onContextmenu(node)">{{ node.name }}{{ node.code }}</div>
<div @contextmenu="onContextmenu(node)">{{ node.name }} ({{ node.code }})</div>
</a-tooltip>
<div v-else @contextmenu="onContextmenu(node)">{{ node.name }}{{ node.code }}</div>
<div v-else @contextmenu="onContextmenu(node)">{{ node.name }} ({{ node.code }})</div>
<template #content>
<RightMenu v-if="has.hasPermOr(['system:dict:update', 'system:dict:delete'])" :data="node"
@on-menu-item-click="onMenuItemClick" />

View File

@@ -85,7 +85,7 @@ import {
import FileGrid from './FileGrid.vue'
import useFileManage from './useFileManage'
import { useTable } from '@/hooks'
import { type FileItem, type FilePageQuery, type FileQuery, deleteFile, listFile, uploadFile } from '@/apis'
import { type FileItem, type FileQuery, deleteFile, listFile, uploadFile } from '@/apis'
import { ImageTypes } from '@/constant/file'
import 'viewerjs/dist/viewer.css'
import { downloadByUrl } from '@/utils/downloadFile'
@@ -187,19 +187,19 @@ const handleMulDelete = () => {
const handleUpload = (options: RequestOption) => {
const controller = new AbortController()
; (async function requestWrap() {
const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options
onProgress(20)
const formData = new FormData()
formData.append(name as string, fileItem.file as Blob)
try {
const res = await uploadFile(formData)
Message.success('上传成功')
onSuccess(res)
search()
} catch (error) {
onError(error)
}
})()
const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options
onProgress(20)
const formData = new FormData()
formData.append(name as string, fileItem.file as Blob)
try {
const res = await uploadFile(formData)
Message.success('上传成功')
onSuccess(res)
search()
} catch (error) {
onError(error)
}
})()
return {
abort() {
controller.abort()
@@ -243,7 +243,7 @@ onMounted(() => {
}
.pagination {
margin: 10px 0;
padding: 0 var(--padding) var(--padding);
:deep(.arco-pagination) {
justify-content: end;

View File

@@ -71,7 +71,7 @@
<template #action="{ record }">
<a-space>
<a-link v-permission="['system:menu:update']" @click="onUpdate(record)">修改</a-link>
<a-link v-if="[1, 2].includes(record.type)" v-permission="['system:menu:add']" @click="onAdd(record.id)">
<a-link v-permission="['system:menu:add']" :disabled="![1, 2].includes(record.type)" @click="onAdd(record.id)">
新增
</a-link>
<a-link v-permission="['system:menu:delete']" status="danger" @click="onDelete(record)">删除</a-link>