mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 22:57:15 +08:00 
			
		
		
		
	feat: 适配首页公告卡片并完善通知公告
This commit is contained in:
		| @@ -4,6 +4,11 @@ import type * as Common from './type' | ||||
| const BASE_URL = '/dashboard' | ||||
|  | ||||
| /** @desc 查询访问趋势 */ | ||||
| export function listAccessTrend(days: number) { | ||||
| export function listDashboardAccessTrend(days: number) { | ||||
|   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 | ||||
| } | ||||
|  | ||||
| /** 仪表盘访问趋势 */ | ||||
| /** 仪表盘访问趋势类型 */ | ||||
| export interface DashboardAccessTrendResp { | ||||
|   date: string | ||||
|   pvCount: 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 './menu' | ||||
| export * from './dept' | ||||
| export * from './announcement' | ||||
| export * from './notice' | ||||
| export * from './dict' | ||||
| export * from './file' | ||||
| 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> | ||||
| } | ||||
|  | ||||
| /** 系统公告类型 */ | ||||
| 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 { | ||||
|   id: string | ||||
| @@ -222,26 +241,3 @@ export interface BindSocialAccountRes { | ||||
|   source: 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> | ||||
|   <div class="message"> | ||||
|     <a-tabs default-active-key="1"> | ||||
|       <a-tab-pane key="1"> | ||||
|       <a-tab-pane key="1" disabled> | ||||
|         <template #title>通知(1)</template> | ||||
|       </a-tab-pane> | ||||
|       <a-tab-pane key="2"> | ||||
|       <a-tab-pane key="2" disabled> | ||||
|         <template #title>关注(1)</template> | ||||
|       </a-tab-pane> | ||||
|       <a-tab-pane key="3"> | ||||
|       <a-tab-pane key="3" disabled> | ||||
|         <template #title>待办(2)</template> | ||||
|       </a-tab-pane> | ||||
|     </a-tabs> | ||||
| @@ -22,7 +22,7 @@ | ||||
|       > | ||||
|         <template #actions></template> | ||||
|         <template #avatar> | ||||
|           <a-avatar><img :src="item.avatar" /></a-avatar> | ||||
|           <a-avatar><img :src="item.avatar" alt="avatar" /></a-avatar> | ||||
|         </template> | ||||
|       </a-comment> | ||||
|     </section> | ||||
| @@ -31,24 +31,13 @@ | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| defineOptions({ name: 'Message' }) | ||||
|  | ||||
| const list = [ | ||||
|   { | ||||
|     name: 'Socrates', | ||||
|     datetime: '1小时之前', | ||||
|     content: 'Comment body content.', | ||||
|     content: 'v3.1.0 重构消息通知', | ||||
|     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> | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { listAccessTrend, type DashboardAccessTrendResp } from '@/apis' | ||||
| import { listDashboardAccessTrend, type DashboardAccessTrendResp } from '@/apis' | ||||
| import VCharts from 'vue-echarts' | ||||
| import { graphic } from 'echarts' | ||||
| import { useChart } from '@/hooks' | ||||
| @@ -180,7 +180,7 @@ const getChartData = async (days: number) => { | ||||
|     xData.value = [] | ||||
|     pvStatisticsData.value = [] | ||||
|     ipStatisticsData.value = [] | ||||
|     const { data: chartData } = await listAccessTrend(days) | ||||
|     const { data: chartData } = await listDashboardAccessTrend(days) | ||||
|     chartData.forEach((el: DashboardAccessTrendResp) => { | ||||
|       xData.value.unshift(el.date) | ||||
|       pvStatisticsData.value.unshift(el.pvCount) | ||||
|   | ||||
| @@ -13,24 +13,41 @@ | ||||
|     > | ||||
|       <template #content> | ||||
|         <div class="content"> | ||||
|           <a-tag v-if="item.type === 1" color="blue" size="small">通知</a-tag> | ||||
|           <a-tag v-if="item.type === 2" color="orangered" size="small">活动</a-tag> | ||||
|           <a-tag v-if="item.type === 3" color="cyan" size="small">消息</a-tag> | ||||
|           <p>{{ item.content }}</p> | ||||
|           <GiCellTag :value="item.type" :dict="notice_type" /> | ||||
|           <p> | ||||
|             <a-link @click="onDetail(item.id)">{{ item.title }}</a-link> | ||||
|           </p> | ||||
|         </div> | ||||
|       </template> | ||||
|     </a-comment> | ||||
|   </a-card> | ||||
|  | ||||
|   <NoticeDetailModal ref="NoticeDetailModalRef" /> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| const dataList = [ | ||||
|   { type: 1, content: 'v2.4.0 版本发布公告🎉' }, | ||||
|   { type: 1, content: 'v2.3.0 版本发布公告🎉' }, | ||||
|   { type: 1, content: 'v2.2.0 版本发布公告🎉' }, | ||||
|   { type: 2, content: '作者喊你来贡献代码了~' }, | ||||
|   { type: 2, content: '作者喊你来提需求了~' } | ||||
| ] | ||||
| import { listDashboardNotice, type DashboardNoticeResp } from '@/apis' | ||||
| import { useDict } from '@/hooks/app' | ||||
| import NoticeDetailModal from '@/views/system/notice/NoticeDetailModal.vue' | ||||
|  | ||||
| const { notice_type } = useDict('notice_type') | ||||
|  | ||||
| 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> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @@ -52,4 +69,16 @@ const dataList = [ | ||||
|     margin-left: 6px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .arco-link { | ||||
|   color: rgb(var(--gray-8)); | ||||
| } | ||||
|  | ||||
| .icon { | ||||
|   margin-right: 3px; | ||||
| } | ||||
|  | ||||
| .update-time-row { | ||||
|   text-align: right; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -74,9 +74,9 @@ const onUpdate = async (id: string) => { | ||||
|  | ||||
| // 保存 | ||||
| const save = async () => { | ||||
|   const isInvalid = await formRef.value?.formRef?.validate() | ||||
|   if (isInvalid) return false | ||||
|   try { | ||||
|     const isInvalid = await formRef.value?.formRef?.validate() | ||||
|     if (isInvalid) return false | ||||
|     if (isUpdate.value) { | ||||
|       await updateDict(form, dataId.value) | ||||
|       Message.success('修改成功') | ||||
|   | ||||
| @@ -2,7 +2,6 @@ | ||||
|   <div class="gi_page"> | ||||
|     <a-card title="字典管理" class="general-card"> | ||||
|       <GiTable | ||||
|         ref="tableRef" | ||||
|         row-key="id" | ||||
|         :data="dataList" | ||||
|         :columns="columns" | ||||
|   | ||||
| @@ -16,30 +16,6 @@ | ||||
|         </a-sub-menu> | ||||
|       </a-menu> | ||||
|     </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> | ||||
| </template> | ||||
|  | ||||
| @@ -50,13 +26,6 @@ const route = useRoute() | ||||
| const router = useRouter() | ||||
|  | ||||
| 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( | ||||
|   | ||||
| @@ -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 | ||||
|     v-model:visible="visible" | ||||
|     :title="title" | ||||
|     width="80%" | ||||
|     :mask-closable="false" | ||||
|     :esc-to-close="false" | ||||
|     width="80%" | ||||
|     @before-ok="save" | ||||
|     @close="reset" | ||||
|     @cancel="reset" | ||||
|   > | ||||
|     <a-form | ||||
|       ref="formRef" | ||||
| @@ -27,7 +26,7 @@ | ||||
|       <a-row :gutter="16"> | ||||
|         <a-col :span="8"> | ||||
|           <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-col> | ||||
|         <a-col :span="8"> | ||||
| @@ -65,19 +64,18 @@ | ||||
| </template> | ||||
| 
 | ||||
| <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 { useForm } from '@/hooks' | ||||
| import { useDict } from '@/hooks/app' | ||||
| import { MdEditor } from 'md-editor-v3' | ||||
| import 'md-editor-v3/lib/style.css' | ||||
| 
 | ||||
| const { announcement_type } = useDict('announcement_type') | ||||
| const visible = ref(false) | ||||
| const announcementId = ref('') | ||||
| const isUpdate = computed(() => !!announcementId.value) | ||||
| const { notice_type } = useDict('notice_type') | ||||
| 
 | ||||
| const dataId = ref('') | ||||
| const isUpdate = computed(() => !!dataId.value) | ||||
| const title = computed(() => (isUpdate.value ? '修改公告' : '新增公告')) | ||||
| const formRef = ref<FormInstance>() | ||||
| 
 | ||||
| const toolbars = [ | ||||
|   'bold', | ||||
| @@ -113,8 +111,9 @@ const toolbars = [ | ||||
|   'previewOnly' | ||||
| ] | ||||
| 
 | ||||
| const formRef = ref<FormInstance>() | ||||
| const rules: FormInstance['rules'] = { | ||||
|   title: [{ required: true, message: '请输入名称' }], | ||||
|   title: [{ required: true, message: '请输入标题' }], | ||||
|   type: [{ required: true, message: '选择类型' }], | ||||
|   content: [{ required: true, message: '请输入内容' }] | ||||
| } | ||||
| @@ -131,35 +130,35 @@ const { form, resetForm } = useForm({ | ||||
| const reset = () => { | ||||
|   formRef.value?.resetFields() | ||||
|   resetForm() | ||||
|   visible.value = false | ||||
| } | ||||
| 
 | ||||
| const visible = ref(false) | ||||
| // 新增 | ||||
| const onAdd = () => { | ||||
|   reset() | ||||
|   announcementId.value = '' | ||||
|   dataId.value = '' | ||||
|   visible.value = true | ||||
| } | ||||
| 
 | ||||
| // 修改 | ||||
| const onUpdate = async (id: string) => { | ||||
|   reset() | ||||
|   announcementId.value = id | ||||
|   const res = await getAnnouncement(id) | ||||
|   dataId.value = id | ||||
|   const res = await getNotice(id) | ||||
|   Object.assign(form, res.data) | ||||
|   visible.value = true | ||||
| } | ||||
| 
 | ||||
| // 保存 | ||||
| const save = async () => { | ||||
|   const isInvalid = await formRef.value?.validate() | ||||
|   if (isInvalid) return false | ||||
|   try { | ||||
|     const isInvalid = await formRef.value?.validate() | ||||
|     if (isInvalid) return false | ||||
|     if (isUpdate.value) { | ||||
|       await updateAnnouncement(form, announcementId.value) | ||||
|       await updateNotice(form, announcementId.value) | ||||
|       Message.success('修改成功') | ||||
|     } else { | ||||
|       await addAnnouncement(form) | ||||
|       await addNotice(form) | ||||
|       Message.success('新增成功') | ||||
|     } | ||||
|     emit('save-success') | ||||
| @@ -176,18 +175,4 @@ const emit = defineEmits<{ | ||||
| defineExpose({ onAdd, onUpdate }) | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| 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> | ||||
| <style lang="scss" scoped></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> | ||||
|   <div> | ||||
|     <div class="gi_page"> | ||||
|       <a-card title="公告" class="general-card"> | ||||
|       <a-card title="通知公告" class="general-card"> | ||||
|         <GiTable | ||||
|           row-key="id" | ||||
|           :data="dataList" | ||||
| @@ -9,18 +9,16 @@ | ||||
|           :loading="loading" | ||||
|           :scroll="{ x: '100%', y: '100%', minWidth: 1000 }" | ||||
|           :pagination="pagination" | ||||
|           :disabledColumnKeys="['name']" | ||||
|           :disabledColumnKeys="['title']" | ||||
|           @refresh="search" | ||||
|         > | ||||
|           <template #custom-left> | ||||
|             <a-input v-model="queryForm.title" placeholder="请输入公告标题" allow-clear @change="search"> | ||||
|               <template #prefix> | ||||
|                 <icon-search /> | ||||
|               </template> | ||||
|               <template #prefix><icon-search /></template> | ||||
|             </a-input> | ||||
|             <a-select | ||||
|               v-model="queryForm.type" | ||||
|               :options="announcement_type" | ||||
|               :options="notice_type" | ||||
|               placeholder="请选择类型" | ||||
|               allow-clear | ||||
|               style="width: 150px" | ||||
| @@ -30,20 +28,18 @@ | ||||
|           </template> | ||||
|           <template #custom-right> | ||||
|             <a-button v-permission="['system:notice:add']" type="primary" @click="onAdd"> | ||||
|               <template #icon> | ||||
|                 <icon-plus /> | ||||
|               </template> | ||||
|               <template #icon><icon-plus /></template> | ||||
|               <span>新增</span> | ||||
|             </a-button> | ||||
|           </template> | ||||
|           <template #title="{ record }"> | ||||
|             <a-link @click="openDetail(record)">{{ record.title }}</a-link> | ||||
|             <a-link @click="onDetail(record)">{{ record.title }}</a-link> | ||||
|           </template> | ||||
|           <template #type="{ record }"> | ||||
|             <GiCellTag :value="record.type" :dict="announcement_type" /> | ||||
|             <GiCellTag :value="record.type" :dict="notice_type" /> | ||||
|           </template> | ||||
|           <template #status="{ record }"> | ||||
|             <GiCellTag :value="record.status" :dict="announcement_status_enum" /> | ||||
|             <GiCellTag :value="record.status" :dict="notice_status_enum" /> | ||||
|           </template> | ||||
|           <template #action="{ record }"> | ||||
|             <a-space> | ||||
| @@ -55,22 +51,24 @@ | ||||
|       </a-card> | ||||
|     </div> | ||||
|  | ||||
|     <AnnouncementAddModal ref="AnnouncementAddModalRef" @save-success="search" /> | ||||
|     <AnnouncementDetailDrawer ref="AnnouncementDetailDrawerRef" /> | ||||
|     <NoticeAddModal ref="NoticeAddModalRef" @save-success="search" /> | ||||
|     <NoticeDetailModal ref="NoticeDetailModalRef" /> | ||||
|   </div> | ||||
| </template> | ||||
| <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 { useDict } from '@/hooks/app' | ||||
| import { isMobile } from '@/utils' | ||||
| import AnnouncementAddModal from './AnnouncementAddModal.vue' | ||||
| import type { TableInstanceColumns } from '@/components/GiTable/type' | ||||
| import AnnouncementDetailDrawer from '@/views/system/notice/AnnouncementDetailDrawer.vue' | ||||
| import has from '@/utils/has' | ||||
|  | ||||
| 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[] = [ | ||||
|   { | ||||
|     title: '序号', | ||||
| @@ -85,7 +83,14 @@ const columns: TableInstanceColumns[] = [ | ||||
|   { title: '终止时间', dataIndex: 'terminateTime', width: 180 }, | ||||
|   { title: '创建人', dataIndex: 'createUserString', show: false, ellipsis: true, tooltip: true }, | ||||
|   { 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({ | ||||
| @@ -100,7 +105,7 @@ const { | ||||
|   pagination, | ||||
|   search, | ||||
|   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 = () => { | ||||
| @@ -110,74 +115,29 @@ const reset = () => { | ||||
| } | ||||
|  | ||||
| // 删除 | ||||
| const onDelete = (item: AnnouncementResp) => { | ||||
|   return handleDelete(() => delAnnouncement(item.id), { | ||||
| const onDelete = (item: NoticeResp) => { | ||||
|   return handleDelete(() => deleteNotice(item.id), { | ||||
|     content: `是否确定删除公告 [${item.title}]?`, | ||||
|     showModal: true | ||||
|   }) | ||||
| } | ||||
|  | ||||
| const AnnouncementAddModalRef = ref<InstanceType<typeof AnnouncementAddModal>>() | ||||
|  | ||||
| const NoticeAddModalRef = ref<InstanceType<typeof NoticeAddModal>>() | ||||
| // 新增 | ||||
| const onAdd = () => { | ||||
|   AnnouncementAddModalRef.value?.onAdd() | ||||
|   NoticeAddModalRef.value?.onAdd() | ||||
| } | ||||
|  | ||||
| // 修改 | ||||
| const onUpdate = (item: AnnouncementResp) => { | ||||
|   AnnouncementAddModalRef.value?.onUpdate(item.id) | ||||
| const onUpdate = (item: NoticeResp) => { | ||||
|   NoticeAddModalRef.value?.onUpdate(item.id) | ||||
| } | ||||
| const AnnouncementDetailDrawerRef = ref<InstanceType<typeof AnnouncementDetailDrawer>>() | ||||
| // 打开详情 | ||||
| const openDetail = (item: AnnouncementResp) => { | ||||
|   console.log(item) | ||||
|   AnnouncementDetailDrawerRef.value?.onDetail(item.id) | ||||
|  | ||||
| const NoticeDetailModalRef = ref<InstanceType<typeof NoticeDetailModal>>() | ||||
| // 详情 | ||||
| const onDetail = (item: NoticeResp) => { | ||||
|   NoticeDetailModalRef.value?.onDetail(item.id) | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <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> | ||||
|  | ||||
| <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> | ||||
| <style lang="scss" scoped></style> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user