mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-09-20 18:58:37 +08:00
feat: 适配首页公告卡片并完善通知公告
This commit is contained in:
@@ -4,6 +4,11 @@ import type * as Common from './type'
|
|||||||
const BASE_URL = '/dashboard'
|
const BASE_URL = '/dashboard'
|
||||||
|
|
||||||
/** @desc 查询访问趋势 */
|
/** @desc 查询访问趋势 */
|
||||||
export function listAccessTrend(days: number) {
|
export function listDashboardAccessTrend(days: number) {
|
||||||
return http.get<Common.DashboardAccessTrendResp[]>(`${BASE_URL}/access/trend/${days}`)
|
return http.get<Common.DashboardAccessTrendResp[]>(`${BASE_URL}/access/trend/${days}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @desc 查询公告列表 */
|
||||||
|
export function listDashboardNotice() {
|
||||||
|
return http.get<Common.DashboardNoticeResp[]>(`${BASE_URL}/notice`)
|
||||||
|
}
|
||||||
|
@@ -4,9 +4,16 @@ export interface ImageCaptchaResp {
|
|||||||
img: string
|
img: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 仪表盘访问趋势 */
|
/** 仪表盘访问趋势类型 */
|
||||||
export interface DashboardAccessTrendResp {
|
export interface DashboardAccessTrendResp {
|
||||||
date: string
|
date: string
|
||||||
pvCount: number
|
pvCount: number
|
||||||
ipCount: number
|
ipCount: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 仪表盘公告类型 */
|
||||||
|
export interface DashboardNoticeResp {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
type: number
|
||||||
|
}
|
||||||
|
@@ -1,24 +0,0 @@
|
|||||||
import http from '@/utils/http'
|
|
||||||
import type * as System from './type'
|
|
||||||
|
|
||||||
const BASE_URL = '/system/announcement'
|
|
||||||
|
|
||||||
export function listAnnouncement(query: System.AnnouncementQuery) {
|
|
||||||
return http.get<PageRes<System.AnnouncementResp[]>>(`${BASE_URL}`, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAnnouncement(id: string) {
|
|
||||||
return http.get<System.AnnouncementResp>(`${BASE_URL}/${id}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addAnnouncement(req: any) {
|
|
||||||
return http.post(BASE_URL, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateAnnouncement(req: any, id: string) {
|
|
||||||
return http.put(`${BASE_URL}/${id}`, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function delAnnouncement(ids: string | Array<number>) {
|
|
||||||
return http.del(`${BASE_URL}/${ids}`)
|
|
||||||
}
|
|
@@ -2,7 +2,7 @@ export * from './user'
|
|||||||
export * from './role'
|
export * from './role'
|
||||||
export * from './menu'
|
export * from './menu'
|
||||||
export * from './dept'
|
export * from './dept'
|
||||||
export * from './announcement'
|
export * from './notice'
|
||||||
export * from './dict'
|
export * from './dict'
|
||||||
export * from './file'
|
export * from './file'
|
||||||
export * from './storage'
|
export * from './storage'
|
||||||
|
29
src/apis/system/notice.ts
Normal file
29
src/apis/system/notice.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import http from '@/utils/http'
|
||||||
|
import type * as System from './type'
|
||||||
|
|
||||||
|
const BASE_URL = '/system/notice'
|
||||||
|
|
||||||
|
/** @desc 查询公告列表 */
|
||||||
|
export function listNotice(query: System.NoticeQuery) {
|
||||||
|
return http.get<PageRes<System.NoticeResp[]>>(`${BASE_URL}`, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 查询公告详情 */
|
||||||
|
export function getNotice(id: string) {
|
||||||
|
return http.get<System.NoticeResp>(`${BASE_URL}/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 新增公告 */
|
||||||
|
export function addNotice(data: any) {
|
||||||
|
return http.post(BASE_URL, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 修改公告 */
|
||||||
|
export function updateNotice(data: any, id: string) {
|
||||||
|
return http.put(`${BASE_URL}/${id}`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 删除公告 */
|
||||||
|
export function deleteNotice(ids: string | Array<number>) {
|
||||||
|
return http.del(`${BASE_URL}/${ids}`)
|
||||||
|
}
|
@@ -119,6 +119,25 @@ export interface DeptQuery {
|
|||||||
sort: Array<string>
|
sort: Array<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 系统公告类型 */
|
||||||
|
export interface NoticeResp {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
content: string
|
||||||
|
status: number
|
||||||
|
type: string
|
||||||
|
effectiveTime: string
|
||||||
|
terminateTime: string
|
||||||
|
createUserString: string
|
||||||
|
createTime: string
|
||||||
|
updateUserString: string
|
||||||
|
updateTime: string
|
||||||
|
}
|
||||||
|
export interface NoticeQuery extends PageQuery {
|
||||||
|
title?: string
|
||||||
|
type?: string
|
||||||
|
}
|
||||||
|
|
||||||
/** 系统字典类型 */
|
/** 系统字典类型 */
|
||||||
export interface DictResp {
|
export interface DictResp {
|
||||||
id: string
|
id: string
|
||||||
@@ -222,26 +241,3 @@ export interface BindSocialAccountRes {
|
|||||||
source: string
|
source: string
|
||||||
description: string
|
description: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 公告类型 */
|
|
||||||
export interface AnnouncementResp {
|
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
content: string
|
|
||||||
status: number
|
|
||||||
type?: string
|
|
||||||
effectiveTime?: string
|
|
||||||
terminateTime?: string
|
|
||||||
createUser: string
|
|
||||||
createTime: string
|
|
||||||
updateUser: string
|
|
||||||
updateTime: string
|
|
||||||
createUserString: string
|
|
||||||
updateUserString: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AnnouncementQuery extends PageQuery {
|
|
||||||
title?: string
|
|
||||||
status?: number
|
|
||||||
type?: string
|
|
||||||
}
|
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="message">
|
<div class="message">
|
||||||
<a-tabs default-active-key="1">
|
<a-tabs default-active-key="1">
|
||||||
<a-tab-pane key="1">
|
<a-tab-pane key="1" disabled>
|
||||||
<template #title>通知(1)</template>
|
<template #title>通知(1)</template>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="2">
|
<a-tab-pane key="2" disabled>
|
||||||
<template #title>关注(1)</template>
|
<template #title>关注(1)</template>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="3">
|
<a-tab-pane key="3" disabled>
|
||||||
<template #title>待办(2)</template>
|
<template #title>待办(2)</template>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
>
|
>
|
||||||
<template #actions></template>
|
<template #actions></template>
|
||||||
<template #avatar>
|
<template #avatar>
|
||||||
<a-avatar><img :src="item.avatar" /></a-avatar>
|
<a-avatar><img :src="item.avatar" alt="avatar" /></a-avatar>
|
||||||
</template>
|
</template>
|
||||||
</a-comment>
|
</a-comment>
|
||||||
</section>
|
</section>
|
||||||
@@ -31,24 +31,13 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineOptions({ name: 'Message' })
|
defineOptions({ name: 'Message' })
|
||||||
|
|
||||||
const list = [
|
const list = [
|
||||||
{
|
{
|
||||||
name: 'Socrates',
|
name: 'Socrates',
|
||||||
datetime: '1小时之前',
|
datetime: '1小时之前',
|
||||||
content: 'Comment body content.',
|
content: 'v3.1.0 重构消息通知',
|
||||||
avatar: 'https://lolicode.gitee.io/scui-doc/demo/img/avatar2.gif'
|
avatar: 'https://lolicode.gitee.io/scui-doc/demo/img/avatar2.gif'
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '木木糖醇',
|
|
||||||
datetime: '2小时之前',
|
|
||||||
content: '关注了你',
|
|
||||||
avatar: 'https://s1.ax1x.com/2022/06/14/XhteeO.jpg'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '徐欣',
|
|
||||||
datetime: '2个半小时之前',
|
|
||||||
content: '收藏了你的文章',
|
|
||||||
avatar: 'https://s1.ax1x.com/2022/06/14/XhtSwF.jpg'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { listAccessTrend, type DashboardAccessTrendResp } from '@/apis'
|
import { listDashboardAccessTrend, type DashboardAccessTrendResp } from '@/apis'
|
||||||
import VCharts from 'vue-echarts'
|
import VCharts from 'vue-echarts'
|
||||||
import { graphic } from 'echarts'
|
import { graphic } from 'echarts'
|
||||||
import { useChart } from '@/hooks'
|
import { useChart } from '@/hooks'
|
||||||
@@ -180,7 +180,7 @@ const getChartData = async (days: number) => {
|
|||||||
xData.value = []
|
xData.value = []
|
||||||
pvStatisticsData.value = []
|
pvStatisticsData.value = []
|
||||||
ipStatisticsData.value = []
|
ipStatisticsData.value = []
|
||||||
const { data: chartData } = await listAccessTrend(days)
|
const { data: chartData } = await listDashboardAccessTrend(days)
|
||||||
chartData.forEach((el: DashboardAccessTrendResp) => {
|
chartData.forEach((el: DashboardAccessTrendResp) => {
|
||||||
xData.value.unshift(el.date)
|
xData.value.unshift(el.date)
|
||||||
pvStatisticsData.value.unshift(el.pvCount)
|
pvStatisticsData.value.unshift(el.pvCount)
|
||||||
|
@@ -13,24 +13,41 @@
|
|||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<a-tag v-if="item.type === 1" color="blue" size="small">通知</a-tag>
|
<GiCellTag :value="item.type" :dict="notice_type" />
|
||||||
<a-tag v-if="item.type === 2" color="orangered" size="small">活动</a-tag>
|
<p>
|
||||||
<a-tag v-if="item.type === 3" color="cyan" size="small">消息</a-tag>
|
<a-link @click="onDetail(item.id)">{{ item.title }}</a-link>
|
||||||
<p>{{ item.content }}</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-comment>
|
</a-comment>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
|
<NoticeDetailModal ref="NoticeDetailModalRef" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const dataList = [
|
import { listDashboardNotice, type DashboardNoticeResp } from '@/apis'
|
||||||
{ type: 1, content: 'v2.4.0 版本发布公告🎉' },
|
import { useDict } from '@/hooks/app'
|
||||||
{ type: 1, content: 'v2.3.0 版本发布公告🎉' },
|
import NoticeDetailModal from '@/views/system/notice/NoticeDetailModal.vue'
|
||||||
{ type: 1, content: 'v2.2.0 版本发布公告🎉' },
|
|
||||||
{ type: 2, content: '作者喊你来贡献代码了~' },
|
const { notice_type } = useDict('notice_type')
|
||||||
{ type: 2, content: '作者喊你来提需求了~' }
|
|
||||||
]
|
const dataList = ref<DashboardNoticeResp[]>([])
|
||||||
|
// 查询列表数据
|
||||||
|
const getDataList = async () => {
|
||||||
|
const res = await listDashboardNotice()
|
||||||
|
dataList.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoticeDetailModalRef = ref<InstanceType<typeof NoticeDetailModal>>()
|
||||||
|
// 详情
|
||||||
|
const onDetail = (id: string) => {
|
||||||
|
NoticeDetailModalRef.value?.onDetail(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getDataList()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -52,4 +69,16 @@ const dataList = [
|
|||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arco-link {
|
||||||
|
color: rgb(var(--gray-8));
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update-time-row {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -74,9 +74,9 @@ const onUpdate = async (id: string) => {
|
|||||||
|
|
||||||
// 保存
|
// 保存
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
try {
|
|
||||||
const isInvalid = await formRef.value?.formRef?.validate()
|
const isInvalid = await formRef.value?.formRef?.validate()
|
||||||
if (isInvalid) return false
|
if (isInvalid) return false
|
||||||
|
try {
|
||||||
if (isUpdate.value) {
|
if (isUpdate.value) {
|
||||||
await updateDict(form, dataId.value)
|
await updateDict(form, dataId.value)
|
||||||
Message.success('修改成功')
|
Message.success('修改成功')
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
<div class="gi_page">
|
<div class="gi_page">
|
||||||
<a-card title="字典管理" class="general-card">
|
<a-card title="字典管理" class="general-card">
|
||||||
<GiTable
|
<GiTable
|
||||||
ref="tableRef"
|
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:data="dataList"
|
:data="dataList"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
@@ -16,30 +16,6 @@
|
|||||||
</a-sub-menu>
|
</a-sub-menu>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<section class="percent">
|
|
||||||
<a-row justify="space-between">
|
|
||||||
<a-statistic title="总存储量" :value="512" :value-style="{ color: '#5856D6' }">
|
|
||||||
<template #prefix>
|
|
||||||
<icon-cloud />
|
|
||||||
</template>
|
|
||||||
<template #suffix>GB</template>
|
|
||||||
</a-statistic>
|
|
||||||
</a-row>
|
|
||||||
|
|
||||||
<a-space size="mini" fill direction="vertical" :key="selectedKey" class="gi_mt">
|
|
||||||
<a-progress
|
|
||||||
v-for="i in filePercentList"
|
|
||||||
:key="i.label"
|
|
||||||
:percent="i.value"
|
|
||||||
:stroke-width="8"
|
|
||||||
:color="i.color"
|
|
||||||
:animation="true"
|
|
||||||
>
|
|
||||||
<template #text>{{ i.label }}</template>
|
|
||||||
</a-progress>
|
|
||||||
</a-space>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -50,13 +26,6 @@ const route = useRoute()
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const selectedKey = ref('0')
|
const selectedKey = ref('0')
|
||||||
const filePercentList = [
|
|
||||||
{ label: '图片', value: 0.7, color: '#4F6BF6' },
|
|
||||||
{ label: '文档', value: 0.3, color: '#FFA000' },
|
|
||||||
{ label: '视频', value: 0.4, color: '#A15FDE' },
|
|
||||||
{ label: '音频', value: 0.2, color: '#FD6112' },
|
|
||||||
{ label: '其他', value: 0.5, color: '#52B852' }
|
|
||||||
]
|
|
||||||
|
|
||||||
// 监听路由变化
|
// 监听路由变化
|
||||||
watch(
|
watch(
|
||||||
|
@@ -1,50 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-drawer v-model:visible="visible" title="公告详情" :width="width >= 900 ? 900 : '100%'" :footer="false">
|
|
||||||
<div>
|
|
||||||
<h1>{{ dataDetail.title }}</h1>
|
|
||||||
<GiCellTag :value="dataDetail.type" :dict="announcement_type" />
|
|
||||||
<span class="time-span">{{ dataDetail.effectiveTime }} - {{ dataDetail.terminateTime }}</span>
|
|
||||||
<a-divider />
|
|
||||||
<a-card hoverable bordered>
|
|
||||||
<MdPreview :editorId="dataDetail.id" :modelValue="dataDetail.content" />
|
|
||||||
<MdCatalog :editorId="dataDetail.id" :scrollElement="scrollElement" />
|
|
||||||
</a-card>
|
|
||||||
</div>
|
|
||||||
</a-drawer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { getAnnouncement, type AnnouncementResp } from '@/apis'
|
|
||||||
import { useWindowSize } from '@vueuse/core'
|
|
||||||
import { MdPreview, MdCatalog } from 'md-editor-v3'
|
|
||||||
import 'md-editor-v3/lib/preview.css'
|
|
||||||
import { useDict } from '@/hooks/app'
|
|
||||||
const { width } = useWindowSize()
|
|
||||||
const scrollElement = document.documentElement
|
|
||||||
const dataId = ref('')
|
|
||||||
const dataDetail = ref<AnnouncementResp>({})
|
|
||||||
const { announcement_type } = useDict('announcement_type')
|
|
||||||
// 查询详情
|
|
||||||
const getDataDetail = async () => {
|
|
||||||
const res = await getAnnouncement(dataId.value)
|
|
||||||
dataDetail.value = res.data
|
|
||||||
}
|
|
||||||
|
|
||||||
const visible = ref(false)
|
|
||||||
// 详情
|
|
||||||
const onDetail = async (id: string) => {
|
|
||||||
dataId.value = id
|
|
||||||
await getDataDetail()
|
|
||||||
visible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({ onDetail })
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.time-span {
|
|
||||||
margin-left: 10px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #737a87;
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -2,12 +2,11 @@
|
|||||||
<a-modal
|
<a-modal
|
||||||
v-model:visible="visible"
|
v-model:visible="visible"
|
||||||
:title="title"
|
:title="title"
|
||||||
width="80%"
|
|
||||||
:mask-closable="false"
|
:mask-closable="false"
|
||||||
:esc-to-close="false"
|
:esc-to-close="false"
|
||||||
|
width="80%"
|
||||||
@before-ok="save"
|
@before-ok="save"
|
||||||
@close="reset"
|
@close="reset"
|
||||||
@cancel="reset"
|
|
||||||
>
|
>
|
||||||
<a-form
|
<a-form
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
@@ -27,7 +26,7 @@
|
|||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :span="8">
|
<a-col :span="8">
|
||||||
<a-form-item label="类型" field="type">
|
<a-form-item label="类型" field="type">
|
||||||
<a-select v-model="form.type" :options="announcement_type" placeholder="请选择类型" />
|
<a-select v-model="form.type" :options="notice_type" placeholder="请选择类型" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="8">
|
||||||
@@ -65,19 +64,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { addAnnouncement, updateAnnouncement, getAnnouncement } from '@/apis'
|
import { addNotice, updateNotice, getNotice } from '@/apis'
|
||||||
import { Message, type FormInstance } from '@arco-design/web-vue'
|
import { Message, type FormInstance } from '@arco-design/web-vue'
|
||||||
import { useForm } from '@/hooks'
|
import { useForm } from '@/hooks'
|
||||||
import { useDict } from '@/hooks/app'
|
import { useDict } from '@/hooks/app'
|
||||||
import { MdEditor } from 'md-editor-v3'
|
import { MdEditor } from 'md-editor-v3'
|
||||||
import 'md-editor-v3/lib/style.css'
|
import 'md-editor-v3/lib/style.css'
|
||||||
|
|
||||||
const { announcement_type } = useDict('announcement_type')
|
const { notice_type } = useDict('notice_type')
|
||||||
const visible = ref(false)
|
|
||||||
const announcementId = ref('')
|
const dataId = ref('')
|
||||||
const isUpdate = computed(() => !!announcementId.value)
|
const isUpdate = computed(() => !!dataId.value)
|
||||||
const title = computed(() => (isUpdate.value ? '修改公告' : '新增公告'))
|
const title = computed(() => (isUpdate.value ? '修改公告' : '新增公告'))
|
||||||
const formRef = ref<FormInstance>()
|
|
||||||
|
|
||||||
const toolbars = [
|
const toolbars = [
|
||||||
'bold',
|
'bold',
|
||||||
@@ -113,8 +111,9 @@ const toolbars = [
|
|||||||
'previewOnly'
|
'previewOnly'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
const rules: FormInstance['rules'] = {
|
const rules: FormInstance['rules'] = {
|
||||||
title: [{ required: true, message: '请输入名称' }],
|
title: [{ required: true, message: '请输入标题' }],
|
||||||
type: [{ required: true, message: '选择类型' }],
|
type: [{ required: true, message: '选择类型' }],
|
||||||
content: [{ required: true, message: '请输入内容' }]
|
content: [{ required: true, message: '请输入内容' }]
|
||||||
}
|
}
|
||||||
@@ -131,35 +130,35 @@ const { form, resetForm } = useForm({
|
|||||||
const reset = () => {
|
const reset = () => {
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
resetForm()
|
resetForm()
|
||||||
visible.value = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
// 新增
|
// 新增
|
||||||
const onAdd = () => {
|
const onAdd = () => {
|
||||||
reset()
|
reset()
|
||||||
announcementId.value = ''
|
dataId.value = ''
|
||||||
visible.value = true
|
visible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改
|
// 修改
|
||||||
const onUpdate = async (id: string) => {
|
const onUpdate = async (id: string) => {
|
||||||
reset()
|
reset()
|
||||||
announcementId.value = id
|
dataId.value = id
|
||||||
const res = await getAnnouncement(id)
|
const res = await getNotice(id)
|
||||||
Object.assign(form, res.data)
|
Object.assign(form, res.data)
|
||||||
visible.value = true
|
visible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存
|
// 保存
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
try {
|
|
||||||
const isInvalid = await formRef.value?.validate()
|
const isInvalid = await formRef.value?.validate()
|
||||||
if (isInvalid) return false
|
if (isInvalid) return false
|
||||||
|
try {
|
||||||
if (isUpdate.value) {
|
if (isUpdate.value) {
|
||||||
await updateAnnouncement(form, announcementId.value)
|
await updateNotice(form, announcementId.value)
|
||||||
Message.success('修改成功')
|
Message.success('修改成功')
|
||||||
} else {
|
} else {
|
||||||
await addAnnouncement(form)
|
await addNotice(form)
|
||||||
Message.success('新增成功')
|
Message.success('新增成功')
|
||||||
}
|
}
|
||||||
emit('save-success')
|
emit('save-success')
|
||||||
@@ -176,18 +175,4 @@ const emit = defineEmits<{
|
|||||||
defineExpose({ onAdd, onUpdate })
|
defineExpose({ onAdd, onUpdate })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped></style>
|
||||||
fieldset {
|
|
||||||
padding: 15px 15px 0 15px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
border: 1px solid var(--color-neutral-3);
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset legend {
|
|
||||||
color: rgb(var(--gray-10));
|
|
||||||
padding: 2px 5px 2px 5px;
|
|
||||||
border: 1px solid var(--color-neutral-3);
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
</style>
|
|
71
src/views/system/notice/NoticeDetailModal.vue
Normal file
71
src/views/system/notice/NoticeDetailModal.vue
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<a-modal v-model:visible="visible" width="70%" :footer="false" @close="reset">
|
||||||
|
<a-typography :style="{ marginTop: '-40px', textAlign: 'center' }">
|
||||||
|
<a-typography-title>
|
||||||
|
{{ dataDetail?.title }}
|
||||||
|
</a-typography-title>
|
||||||
|
<a-typography-paragraph>
|
||||||
|
<div class="meta-data">
|
||||||
|
<a-space>
|
||||||
|
<span>
|
||||||
|
<icon-user class="icon" />
|
||||||
|
<span class="label">发布人:</span>
|
||||||
|
<span>{{ dataDetail?.createUserString }}</span>
|
||||||
|
</span>
|
||||||
|
<a-divider direction="vertical" />
|
||||||
|
<span>
|
||||||
|
<icon-history class="icon" />
|
||||||
|
<span class="label">发布时间:</span>
|
||||||
|
<span>{{ dataDetail?.effectiveTime ? dataDetail?.effectiveTime : dataDetail?.createTime }}</span>
|
||||||
|
</span>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
</a-typography-paragraph>
|
||||||
|
</a-typography>
|
||||||
|
<a-divider />
|
||||||
|
<MdPreview :editorId="dataDetail?.id" :modelValue="dataDetail?.content" />
|
||||||
|
<a-divider />
|
||||||
|
<div v-if="dataDetail?.updateTime" class="update-time-row">
|
||||||
|
<span>
|
||||||
|
<icon-schedule class="icon" />
|
||||||
|
<span>最后更新于:</span>
|
||||||
|
<span>{{ dataDetail?.updateTime }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getNotice, type NoticeResp } from '@/apis'
|
||||||
|
import { MdPreview } from 'md-editor-v3'
|
||||||
|
|
||||||
|
const dataDetail = ref<NoticeResp>()
|
||||||
|
const visible = ref(false)
|
||||||
|
// 详情
|
||||||
|
const onDetail = async (id: string) => {
|
||||||
|
const res = await getNotice(id)
|
||||||
|
dataDetail.value = res.data
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置
|
||||||
|
const reset = () => {
|
||||||
|
dataDetail.value = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ onDetail })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.arco-link {
|
||||||
|
color: rgb(var(--gray-8));
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update-time-row {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="gi_page">
|
<div class="gi_page">
|
||||||
<a-card title="公告" class="general-card">
|
<a-card title="通知公告" class="general-card">
|
||||||
<GiTable
|
<GiTable
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:data="dataList"
|
:data="dataList"
|
||||||
@@ -9,18 +9,16 @@
|
|||||||
:loading="loading"
|
:loading="loading"
|
||||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
:disabledColumnKeys="['name']"
|
:disabledColumnKeys="['title']"
|
||||||
@refresh="search"
|
@refresh="search"
|
||||||
>
|
>
|
||||||
<template #custom-left>
|
<template #custom-left>
|
||||||
<a-input v-model="queryForm.title" placeholder="请输入公告标题" allow-clear @change="search">
|
<a-input v-model="queryForm.title" placeholder="请输入公告标题" allow-clear @change="search">
|
||||||
<template #prefix>
|
<template #prefix><icon-search /></template>
|
||||||
<icon-search />
|
|
||||||
</template>
|
|
||||||
</a-input>
|
</a-input>
|
||||||
<a-select
|
<a-select
|
||||||
v-model="queryForm.type"
|
v-model="queryForm.type"
|
||||||
:options="announcement_type"
|
:options="notice_type"
|
||||||
placeholder="请选择类型"
|
placeholder="请选择类型"
|
||||||
allow-clear
|
allow-clear
|
||||||
style="width: 150px"
|
style="width: 150px"
|
||||||
@@ -30,20 +28,18 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #custom-right>
|
<template #custom-right>
|
||||||
<a-button v-permission="['system:notice:add']" type="primary" @click="onAdd">
|
<a-button v-permission="['system:notice:add']" type="primary" @click="onAdd">
|
||||||
<template #icon>
|
<template #icon><icon-plus /></template>
|
||||||
<icon-plus />
|
|
||||||
</template>
|
|
||||||
<span>新增</span>
|
<span>新增</span>
|
||||||
</a-button>
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
<template #title="{ record }">
|
<template #title="{ record }">
|
||||||
<a-link @click="openDetail(record)">{{ record.title }}</a-link>
|
<a-link @click="onDetail(record)">{{ record.title }}</a-link>
|
||||||
</template>
|
</template>
|
||||||
<template #type="{ record }">
|
<template #type="{ record }">
|
||||||
<GiCellTag :value="record.type" :dict="announcement_type" />
|
<GiCellTag :value="record.type" :dict="notice_type" />
|
||||||
</template>
|
</template>
|
||||||
<template #status="{ record }">
|
<template #status="{ record }">
|
||||||
<GiCellTag :value="record.status" :dict="announcement_status_enum" />
|
<GiCellTag :value="record.status" :dict="notice_status_enum" />
|
||||||
</template>
|
</template>
|
||||||
<template #action="{ record }">
|
<template #action="{ record }">
|
||||||
<a-space>
|
<a-space>
|
||||||
@@ -55,22 +51,24 @@
|
|||||||
</a-card>
|
</a-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<AnnouncementAddModal ref="AnnouncementAddModalRef" @save-success="search" />
|
<NoticeAddModal ref="NoticeAddModalRef" @save-success="search" />
|
||||||
<AnnouncementDetailDrawer ref="AnnouncementDetailDrawerRef" />
|
<NoticeDetailModal ref="NoticeDetailModalRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { listAnnouncement, delAnnouncement, type AnnouncementResp } from '@/apis'
|
import { listNotice, deleteNotice, type NoticeResp } from '@/apis'
|
||||||
|
import NoticeAddModal from './NoticeAddModal.vue'
|
||||||
|
import NoticeDetailModal from './NoticeDetailModal.vue'
|
||||||
|
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||||
import { useTable } from '@/hooks'
|
import { useTable } from '@/hooks'
|
||||||
import { useDict } from '@/hooks/app'
|
import { useDict } from '@/hooks/app'
|
||||||
import { isMobile } from '@/utils'
|
import { isMobile } from '@/utils'
|
||||||
import AnnouncementAddModal from './AnnouncementAddModal.vue'
|
import has from '@/utils/has'
|
||||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
|
||||||
import AnnouncementDetailDrawer from '@/views/system/notice/AnnouncementDetailDrawer.vue'
|
|
||||||
|
|
||||||
defineOptions({ name: 'Announcement' })
|
defineOptions({ name: 'SystemNotice' })
|
||||||
|
|
||||||
|
const { notice_type, notice_status_enum } = useDict('notice_type', 'notice_status_enum')
|
||||||
|
|
||||||
const { announcement_type, announcement_status_enum } = useDict('announcement_type', 'announcement_status_enum')
|
|
||||||
const columns: TableInstanceColumns[] = [
|
const columns: TableInstanceColumns[] = [
|
||||||
{
|
{
|
||||||
title: '序号',
|
title: '序号',
|
||||||
@@ -85,7 +83,14 @@ const columns: TableInstanceColumns[] = [
|
|||||||
{ title: '终止时间', dataIndex: 'terminateTime', width: 180 },
|
{ title: '终止时间', dataIndex: 'terminateTime', width: 180 },
|
||||||
{ title: '创建人', dataIndex: 'createUserString', show: false, ellipsis: true, tooltip: true },
|
{ title: '创建人', dataIndex: 'createUserString', show: false, ellipsis: true, tooltip: true },
|
||||||
{ title: '创建时间', dataIndex: 'createTime', width: 180 },
|
{ title: '创建时间', dataIndex: 'createTime', width: 180 },
|
||||||
{ title: '操作', slotName: 'action', width: 200, align: 'center', fixed: !isMobile() ? 'right' : undefined }
|
{
|
||||||
|
title: '操作',
|
||||||
|
slotName: 'action',
|
||||||
|
width: 130,
|
||||||
|
align: 'center',
|
||||||
|
fixed: !isMobile() ? 'right' : undefined,
|
||||||
|
show: has.hasPermOr(['system:notice:update', 'system:notice:delete'])
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const queryForm = reactive({
|
const queryForm = reactive({
|
||||||
@@ -100,7 +105,7 @@ const {
|
|||||||
pagination,
|
pagination,
|
||||||
search,
|
search,
|
||||||
handleDelete
|
handleDelete
|
||||||
} = useTable((p) => listAnnouncement({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
} = useTable((p) => listNotice({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||||
|
|
||||||
// 重置
|
// 重置
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
@@ -110,74 +115,29 @@ const reset = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
const onDelete = (item: AnnouncementResp) => {
|
const onDelete = (item: NoticeResp) => {
|
||||||
return handleDelete(() => delAnnouncement(item.id), {
|
return handleDelete(() => deleteNotice(item.id), {
|
||||||
content: `是否确定删除公告 [${item.title}]?`,
|
content: `是否确定删除公告 [${item.title}]?`,
|
||||||
showModal: true
|
showModal: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const AnnouncementAddModalRef = ref<InstanceType<typeof AnnouncementAddModal>>()
|
const NoticeAddModalRef = ref<InstanceType<typeof NoticeAddModal>>()
|
||||||
|
|
||||||
// 新增
|
// 新增
|
||||||
const onAdd = () => {
|
const onAdd = () => {
|
||||||
AnnouncementAddModalRef.value?.onAdd()
|
NoticeAddModalRef.value?.onAdd()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改
|
// 修改
|
||||||
const onUpdate = (item: AnnouncementResp) => {
|
const onUpdate = (item: NoticeResp) => {
|
||||||
AnnouncementAddModalRef.value?.onUpdate(item.id)
|
NoticeAddModalRef.value?.onUpdate(item.id)
|
||||||
}
|
}
|
||||||
const AnnouncementDetailDrawerRef = ref<InstanceType<typeof AnnouncementDetailDrawer>>()
|
|
||||||
// 打开详情
|
const NoticeDetailModalRef = ref<InstanceType<typeof NoticeDetailModal>>()
|
||||||
const openDetail = (item: AnnouncementResp) => {
|
// 详情
|
||||||
console.log(item)
|
const onDetail = (item: NoticeResp) => {
|
||||||
AnnouncementDetailDrawerRef.value?.onDetail(item.id)
|
NoticeDetailModalRef.value?.onDetail(item.id)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style lang="scss" scoped></style>
|
||||||
:deep(.github-markdown-body) {
|
|
||||||
padding: 16px 32px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-form-item-label-tooltip) {
|
|
||||||
margin-left: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta-data {
|
|
||||||
font-size: 15px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin-right: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.update-time-row {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
:deep(.github-markdown-body) {
|
|
||||||
padding: 16px 32px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-form-item-label-tooltip) {
|
|
||||||
margin-left: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta-data {
|
|
||||||
font-size: 15px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin-right: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.update-time-row {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
Reference in New Issue
Block a user