mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-10-30 12:57:10 +08:00
feat: 新增公告管理(列表,新增)
This commit is contained in:
24
src/apis/system/announcement.ts
Normal file
24
src/apis/system/announcement.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
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}`)
|
||||||
|
}
|
||||||
@@ -7,3 +7,4 @@ export * from './dict'
|
|||||||
export * from './file'
|
export * from './file'
|
||||||
export * from './storage'
|
export * from './storage'
|
||||||
export * from './option'
|
export * from './option'
|
||||||
|
export * from './announcement'
|
||||||
|
|||||||
@@ -222,3 +222,26 @@ 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
|
||||||
|
}
|
||||||
|
|||||||
165
src/views/system/notice/AnnouncementAddModal.vue
Normal file
165
src/views/system/notice/AnnouncementAddModal.vue
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:title="title"
|
||||||
|
:visible="visible"
|
||||||
|
width="80%"
|
||||||
|
:mask-closable="false"
|
||||||
|
:esc-to-close="false"
|
||||||
|
unmount-on-close
|
||||||
|
render-to-body
|
||||||
|
@before-ok="save"
|
||||||
|
@close="reset"
|
||||||
|
@cancel="reset"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
layout="vertical"
|
||||||
|
:label-col-style="{ width: '75px' }"
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="24">
|
||||||
|
<a-form-item label="标题" field="title">
|
||||||
|
<a-input v-model="form.title" placeholder="请输入标题" :max-length="150" style="width: 100%" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<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-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8">
|
||||||
|
<a-form-item label="生效时间" field="effectiveTime" tooltip="默认立即生效">
|
||||||
|
<a-date-picker
|
||||||
|
v-model="form.effectiveTime"
|
||||||
|
placeholder="请选择生效时间"
|
||||||
|
show-time
|
||||||
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8">
|
||||||
|
<a-form-item label="终止时间" field="terminateTime" tooltip="默认无终止">
|
||||||
|
<a-date-picker
|
||||||
|
v-model="form.terminateTime"
|
||||||
|
placeholder="请选择终止时间"
|
||||||
|
show-time
|
||||||
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="24">
|
||||||
|
<a-form-item label="内容" field="content">
|
||||||
|
<v-md-editor
|
||||||
|
v-model="form.content"
|
||||||
|
height="400px"
|
||||||
|
left-toolbar="undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code"
|
||||||
|
placeholder="请输入内容"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { addAnnouncement, updateAnnouncement, getAnnouncement } from '@/apis'
|
||||||
|
import { Message, type FormInstance } from '@arco-design/web-vue'
|
||||||
|
import { useForm } from '@/hooks'
|
||||||
|
import { useDict } from '@/hooks/app'
|
||||||
|
|
||||||
|
const { announcement_type } = useDict('announcement_type')
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
const announcementId = ref('')
|
||||||
|
const isUpdate = computed(() => !!announcementId.value)
|
||||||
|
const title = computed(() => (isUpdate.value ? '修改公告' : '新增公告'))
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
const rules: FormInstance['rules'] = {
|
||||||
|
title: [{ required: true, message: '请输入名称' }],
|
||||||
|
type: [{ required: true, message: '选择类型' }],
|
||||||
|
content: [{ required: true, message: '请输入内容' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
const { form, resetForm } = useForm({
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
type: '',
|
||||||
|
effectiveTime: undefined,
|
||||||
|
terminateTime: undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
// 重置
|
||||||
|
const reset = () => {
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
resetForm()
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
const onAdd = () => {
|
||||||
|
reset()
|
||||||
|
announcementId.value = ''
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改
|
||||||
|
const onUpdate = async (id: string) => {
|
||||||
|
reset()
|
||||||
|
announcementId.value = id
|
||||||
|
const res = await getAnnouncement(id)
|
||||||
|
Object.assign(form, res.data)
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存
|
||||||
|
const save = async () => {
|
||||||
|
try {
|
||||||
|
const isInvalid = await formRef.value?.validate()
|
||||||
|
if (isInvalid) return false
|
||||||
|
if (isUpdate.value) {
|
||||||
|
await updateAnnouncement(form, announcementId.value)
|
||||||
|
Message.success('修改成功')
|
||||||
|
} else {
|
||||||
|
await addAnnouncement(form)
|
||||||
|
Message.success('新增成功')
|
||||||
|
}
|
||||||
|
emit('save-success')
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'save-success'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
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>
|
||||||
178
src/views/system/notice/index.vue
Normal file
178
src/views/system/notice/index.vue
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<div class="gi_page">
|
||||||
|
<a-card title="公告" class="general-card">
|
||||||
|
<GiTable
|
||||||
|
row-key="id"
|
||||||
|
:data="dataList"
|
||||||
|
:columns="columns"
|
||||||
|
:loading="loading"
|
||||||
|
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||||
|
:pagination="pagination"
|
||||||
|
:disabledColumnKeys="['name']"
|
||||||
|
@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.status"
|
||||||
|
:options="announcement_type"
|
||||||
|
placeholder="请选择类型"
|
||||||
|
allow-clear
|
||||||
|
style="width: 150px"
|
||||||
|
@change="search"
|
||||||
|
/>
|
||||||
|
<a-button @click="reset">重置</a-button>
|
||||||
|
</template>
|
||||||
|
<template #custom-right>
|
||||||
|
<a-button v-permission="['system:notice:add']" type="primary" @click="onAdd">
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
<span>新增</span>
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
<template #title="{ record }">
|
||||||
|
<a-link @click="openDetail(record)">{{ record.title }}</a-link>
|
||||||
|
</template>
|
||||||
|
<template #type="{ record }">
|
||||||
|
<GiCellTag :value="record.type" :dict="announcement_type" />
|
||||||
|
</template>
|
||||||
|
<template #status="{ record }">
|
||||||
|
<GiCellTag :value="record.status" :dict="announcement_status_enum" />
|
||||||
|
</template>
|
||||||
|
<template #action="{ record }">
|
||||||
|
<a-space>
|
||||||
|
<a-link v-permission="['system:notice:update']" @click="onUpdate(record)">修改</a-link>
|
||||||
|
<a-link v-permission="['system:notice:delete']" status="danger" @click="onDelete(record)"> 删除 </a-link>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</GiTable>
|
||||||
|
</a-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<AnnouncementAddModal ref="AnnouncementAddModalRef" @save-success="search" />
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { listAnnouncement, delAnnouncement, type AnnouncementResp } from '@/apis'
|
||||||
|
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'
|
||||||
|
|
||||||
|
defineOptions({ name: 'Announcement' })
|
||||||
|
|
||||||
|
const { announcement_type, announcement_status_enum } = useDict('announcement_type', 'announcement_status_enum')
|
||||||
|
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: '类型', slotName: 'type', align: 'center' },
|
||||||
|
{ title: '状态', slotName: 'status', align: 'center' },
|
||||||
|
{ title: '生效时间', dataIndex: 'effectiveTime', width: 180 },
|
||||||
|
{ 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 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const queryForm = reactive({
|
||||||
|
title: undefined,
|
||||||
|
status: undefined,
|
||||||
|
sort: ['createTime,desc']
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
tableData: dataList,
|
||||||
|
loading,
|
||||||
|
pagination,
|
||||||
|
search,
|
||||||
|
handleDelete
|
||||||
|
} = useTable((p) => listAnnouncement({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||||
|
|
||||||
|
// 重置
|
||||||
|
const reset = () => {
|
||||||
|
queryForm.title = undefined
|
||||||
|
queryForm.status = undefined
|
||||||
|
search()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
const onDelete = (item: AnnouncementResp) => {
|
||||||
|
return handleDelete(() => delAnnouncement(item.id), {
|
||||||
|
content: `是否确定删除公告 [${item.title}]?`,
|
||||||
|
showModal: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnnouncementAddModalRef = ref<InstanceType<typeof AnnouncementAddModal>>()
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
const onAdd = () => {
|
||||||
|
AnnouncementAddModalRef.value?.onAdd()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改
|
||||||
|
const onUpdate = (item: AnnouncementResp) => {
|
||||||
|
AnnouncementAddModalRef.value?.onUpdate(item.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开详情
|
||||||
|
const openDetail = (item: AnnouncementResp) => {
|
||||||
|
// RoleDetailDrawerRef.value?.open(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>
|
||||||
Reference in New Issue
Block a user