369 lines
11 KiB
Vue
369 lines
11 KiB
Vue
<template>
|
||
<div>
|
||
<!-- 搜索 -->
|
||
<NoticeSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||
@reset="handleReset">
|
||
<template #button>
|
||
<el-button type="primary" @click="handleCreate">新建</el-button>
|
||
</template>
|
||
</NoticeSearch>
|
||
<div class="tab">
|
||
<el-button :type="activeTab === 2 ? 'primary' : 'default'" @click="handleTabChange(2)">已发布</el-button>
|
||
<el-button :type="activeTab === 1 ? 'primary' : 'default'" @click="handleTabChange(1)">草稿</el-button>
|
||
</div>
|
||
<!-- 表格 -->
|
||
<NoticeTable :table-data="noticeTree" :columns="noticeTableColumnsOptions" row-key="id">
|
||
<template #status="{ row }">
|
||
<!-- 修正状态显示:1=草稿,2=已发布 -->
|
||
{{ row.status === 1 ? '草稿' : '已发布' }}
|
||
</template>
|
||
<template #action="{ row }">
|
||
<el-button type="primary" size="small" v-if="row.status === 2" @click="handleView(row)">查看</el-button>
|
||
<!-- 草稿才显示编辑/删除,已发布仅查看 -->
|
||
<template v-if="row.status === 1">
|
||
<el-button type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
|
||
<el-button type="danger" size="small" @click="handleDelete(row)">删除</el-button>
|
||
</template>
|
||
</template>
|
||
</NoticeTable>
|
||
<!-- 分页 -->
|
||
<NoticePagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||
@pagination-change="handlePaginationChange" />
|
||
<!-- dialog -->
|
||
<NoticeDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType"
|
||
:show-footer="dialogType !== 'view'" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
|
||
<NoticeForm :form-data="noticeForm" :form-rules="noticeRules" :form-items="noticeFormItem"
|
||
:options-map="noticeFormOptionsMap" ref="noticeFormRef" v-if="dialogType !== 'view'">
|
||
<template #noticeContent="{ formData }">
|
||
<div style="border: 1px solid #e6e6e6; margin: 10px 0;">
|
||
<Toolbar :editor="editorRef" :defaultConfig="toolbarConfig" mode="default"
|
||
style="border-bottom: 1px solid #ccc;" />
|
||
<Editor v-model="valueHtml" :defaultConfig="editorConfig" mode="default"
|
||
@onCreated="handleCreated" style="height: 300px; overflow-y: auto;" />
|
||
</div>
|
||
</template>
|
||
</NoticeForm>
|
||
<div v-else class="view-content">
|
||
<h2>公告名称:{{ noticeForm.noticeName }}</h2>
|
||
<div v-html="noticeForm.noticeContent"></div>
|
||
</div>
|
||
</NoticeDialog>
|
||
<!-- dialog表格 -->
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
// 组件
|
||
import NoticeSearch from '@/components/common/Search.vue'
|
||
import NoticeTable from '@/components/common/Table.vue'
|
||
import NoticePagination from '@/components/common/Pagination.vue'
|
||
import NoticeDialog from '@/components/common/Dialog.vue'
|
||
import NoticeForm from '@/components/common/Form.vue'
|
||
// 配置以及表单验证
|
||
import { search, tableColumns, formItem } from './options'
|
||
import { rules } from './rules'
|
||
|
||
// 接口
|
||
import { getNoticeListApi, createNoticeApi, editNoticeApi, deleteNoticeApi } from '@/api/modules/notice'
|
||
import { uploadImageApi } from '@/api/modules/upload'
|
||
|
||
|
||
|
||
import { DomEditor } from '@wangeditor/editor'
|
||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||
import '@wangeditor/editor/dist/css/style.css'
|
||
|
||
// 富文本编辑器实例
|
||
const editorRef = shallowRef()
|
||
// 工具栏实例(通过 DomEditor 获取)
|
||
const toolbarRef = shallowRef()
|
||
// 富文本编辑器内容 HTML
|
||
const valueHtml = ref('')
|
||
// 工具栏配置
|
||
const toolbarConfig = {
|
||
excludeKeys: ["group-video", "fullScreen"]
|
||
}
|
||
// 富文本编辑器配置
|
||
const editorConfig = {
|
||
placeholder: '请输入内容...',
|
||
MENU_CONF: {
|
||
uploadImage: {
|
||
customUpload: async (file: any, insertFn: any) => {
|
||
try {
|
||
// 调用封装后的上传API
|
||
const res = await uploadImageApi(file);
|
||
// 插入图片到富文本
|
||
insertFn(res.url);
|
||
} catch (error: any) {
|
||
// 复用你已有的错误提示逻辑(ElNotification)
|
||
const errMsg = error?.message || error?.data?.msg || '图片上传失败';
|
||
alert(`图片${file.name}上传失败:${errMsg}`);
|
||
ElNotification({
|
||
message: errMsg || '未知的错误!',
|
||
type: 'error',
|
||
duration: 2000,
|
||
customClass: 'global-notification'
|
||
})
|
||
}
|
||
},
|
||
// 保留基础配置
|
||
fieldName: 'image',
|
||
timeout: 30 * 1000,
|
||
maxFileSize: 5 * 1024 * 1024,
|
||
allowedFileTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description: 定义搜索数据
|
||
*/
|
||
const searchForm = ref({
|
||
noticeName: '',
|
||
startDateTime: '',
|
||
endDateTime: '',
|
||
status: 2,
|
||
})
|
||
const searchOptions = ref(search)
|
||
|
||
/**
|
||
* @description: 定义tab数据
|
||
*/
|
||
const activeTab = ref(2)
|
||
|
||
/**
|
||
* @description: 定义表格数据
|
||
*/
|
||
const noticeTree = ref([])
|
||
const noticeTableColumnsOptions = ref(tableColumns)
|
||
|
||
/**
|
||
* @description: 定义分页数据
|
||
*/
|
||
const total = ref(0)
|
||
const currentPage = ref(1)
|
||
const pageSize = ref(10)
|
||
/**
|
||
* @description: 定义弹窗数据
|
||
*/
|
||
const dialogVisible = ref(false)
|
||
const dialogTitle = ref('')
|
||
const dialogType = ref('')
|
||
|
||
/**
|
||
* @description: 定义弹窗表格数据
|
||
*/
|
||
const noticeForm = ref({
|
||
noticeName: '',
|
||
noticeContent: '',
|
||
status: 1,
|
||
id: 0,
|
||
})
|
||
const noticeFormRef = ref()
|
||
const noticeRules = ref(rules())
|
||
const noticeFormItem = ref(formItem)
|
||
const noticeFormOptionsMap = ref({
|
||
status: [
|
||
{ label: '草稿', value: 1 },
|
||
{ label: '发布', value: 2 },
|
||
],
|
||
})
|
||
|
||
/**
|
||
* @description: 定义请求数据方法
|
||
*/
|
||
//获取公告列表
|
||
const getNoticeList = async () => {
|
||
const params = {
|
||
page: currentPage.value,
|
||
page_size: pageSize.value,
|
||
name: searchForm.value.noticeName,
|
||
status: searchForm.value.status,
|
||
publish_start_time: searchForm.value.startDateTime,
|
||
publish_end_time: searchForm.value.endDateTime,
|
||
}
|
||
const data: any = await getNoticeListApi(params)
|
||
// 表格数据
|
||
noticeTree.value = data.data.map((item: any) => ({
|
||
id: item.id,
|
||
noticeName: item.name,
|
||
noticeContent: item.content,
|
||
publishTime: item.publish_time,
|
||
status: item.status,
|
||
}))
|
||
// 分页数据
|
||
total.value = data.total
|
||
currentPage.value = data.current_page
|
||
pageSize.value = Number(data.per_page)
|
||
}
|
||
|
||
/**
|
||
* @description: 页面加载完成需要请求的数据
|
||
*/
|
||
onMounted(() => {
|
||
getNoticeList()
|
||
})
|
||
|
||
/**
|
||
* @description: 定义搜索方法
|
||
*/
|
||
const handleSearch = () => {
|
||
getNoticeList()
|
||
}
|
||
const handleReset = () => {
|
||
searchForm.value = {
|
||
noticeName: '',
|
||
startDateTime: '',
|
||
endDateTime: '',
|
||
status: 2,
|
||
}
|
||
activeTab.value = 2
|
||
getNoticeList()
|
||
}
|
||
const handleCreate = () => {
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '新建公告'
|
||
dialogType.value = 'create'
|
||
noticeForm.value = {
|
||
noticeName: '',
|
||
noticeContent: '',
|
||
status: 1,
|
||
id: 0,
|
||
} as any
|
||
}
|
||
|
||
/**
|
||
* @description: 定义tab方法
|
||
*/
|
||
const handleTabChange = (tab: number) => {
|
||
activeTab.value = tab
|
||
searchForm.value.status = tab
|
||
currentPage.value = 1
|
||
getNoticeList()
|
||
}
|
||
|
||
/**
|
||
* @description: 定义表格方法
|
||
*/
|
||
const handleView = (row: any) => {
|
||
console.log(row)
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '查看公告'
|
||
dialogType.value = 'view'
|
||
noticeForm.value = {
|
||
noticeName: row.noticeName,
|
||
noticeContent: row.noticeContent,
|
||
} as any
|
||
}
|
||
|
||
|
||
const handleEdit = (row: any) => {
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '编辑公告'
|
||
dialogType.value = 'edit'
|
||
noticeForm.value = {
|
||
noticeName: row.noticeName,
|
||
status: row.status,
|
||
id: row.id,
|
||
} as any
|
||
valueHtml.value = row.noticeContent
|
||
}
|
||
// 删除公告
|
||
const handleDelete = async (row: any) => {
|
||
const params = {
|
||
id: row.id,
|
||
}
|
||
await deleteNoticeApi(params)
|
||
getNoticeList()
|
||
}
|
||
|
||
/**
|
||
* @description: 定义分页方法
|
||
*/
|
||
const handlePaginationChange = async (page: { currentPage: number, pageSize: number }) => {
|
||
currentPage.value = page.currentPage
|
||
pageSize.value = page.pageSize
|
||
await getNoticeList()
|
||
}
|
||
/**
|
||
* @description: 定义弹窗方法
|
||
*/
|
||
const handleSubmit = async () => {
|
||
await noticeFormRef.value.validate()
|
||
if (dialogType.value === 'create') {
|
||
noticeForm.value.noticeContent = valueHtml.value
|
||
const params = {
|
||
name: noticeForm.value.noticeName,
|
||
content: noticeForm.value.noticeContent,
|
||
status: noticeForm.value.status,
|
||
}
|
||
await createNoticeApi(params)
|
||
dialogVisible.value = false
|
||
getNoticeList()
|
||
} else {
|
||
noticeForm.value.noticeContent = valueHtml.value
|
||
const params = {
|
||
id: noticeForm.value.id,
|
||
name: noticeForm.value.noticeName,
|
||
content: noticeForm.value.noticeContent,
|
||
status: noticeForm.value.status,
|
||
}
|
||
await editNoticeApi(params)
|
||
dialogVisible.value = false
|
||
getNoticeList()
|
||
}
|
||
|
||
}
|
||
|
||
const handleCancel = () => {
|
||
dialogVisible.value = false
|
||
}
|
||
const handleClose = () => {
|
||
dialogVisible.value = false
|
||
}
|
||
|
||
/**
|
||
* @description: 定义富文本编辑器方法
|
||
*/
|
||
// 组件销毁时销毁编辑器
|
||
onBeforeUnmount(() => {
|
||
const editor = editorRef.value
|
||
if (editor == null) return
|
||
editor.destroy()
|
||
})
|
||
|
||
// 富文本编辑器创建完成后回调
|
||
const handleCreated = (editor: any) => {
|
||
editorRef.value = editor
|
||
|
||
// 在这里获取工具栏实例(必须等编辑器和工具栏都挂载后)
|
||
nextTick(() => {
|
||
const toolbar = DomEditor.getToolbar(editor)
|
||
if (toolbar) {
|
||
const curToolbarConfig = toolbar.getConfig()
|
||
console.log('curToolbarConfig.toolbarKeys', curToolbarConfig.toolbarKeys)
|
||
toolbarRef.value = toolbar
|
||
console.log('toolbarRef.value', valueHtml.value)
|
||
}
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.tab {
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-bottom: 10px;
|
||
|
||
.el-button {
|
||
margin-left: 0px;
|
||
}
|
||
}
|
||
|
||
.view-content {
|
||
h2 {
|
||
margin-bottom: 10px;
|
||
}
|
||
}
|
||
</style>
|