This commit is contained in:
parent
2a83395858
commit
c9f943f8dd
|
|
@ -6,5 +6,13 @@ export const getNoticeListApi = (params: any) => {
|
|||
}
|
||||
//创建公告
|
||||
export const createNoticeApi = (params: any) => {
|
||||
return request.get('/notice/createNotice', {...params})
|
||||
return request.post('/notice/createNotice', {...params})
|
||||
}
|
||||
//编辑草稿
|
||||
export const editNoticeApi = (params: any) => {
|
||||
return request.post('/notice/editNotice', {...params})
|
||||
}
|
||||
//删除草稿
|
||||
export const deleteNoticeApi = (params: any) => {
|
||||
return request.post('/notice/delNotice', {...params})
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { request } from '@/api'; // 引入你已封装的request
|
||||
|
||||
/**
|
||||
* 图片上传接口(适配富文本编辑器)
|
||||
* @param file 要上传的文件对象
|
||||
* @returns Promise<{ url: string }> 图片上传后的URL
|
||||
*/
|
||||
export const uploadImageApi = (file: File): Promise<{ url: string }> => {
|
||||
// 构建FormData(图片上传必须用FormData格式)
|
||||
const formData = new FormData();
|
||||
formData.append('image', file); // 对应后端接收字段名image
|
||||
|
||||
// 使用你已封装的post请求,禁用loading(富文本自身有状态提示)
|
||||
return request.post<{ url: string }>(
|
||||
'/upload/image',
|
||||
formData,
|
||||
{
|
||||
// 覆盖默认配置:图片上传需要特殊的请求头
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data', // 表单上传必须的头
|
||||
showLoading: false // 禁用全局loading,避免和编辑器loading冲突
|
||||
},
|
||||
timeout: 30 * 1000, // 图片上传超时时间30秒
|
||||
noRetry: false // 允许重试(网络波动时自动重试)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
@ -7,24 +7,34 @@
|
|||
<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 }">
|
||||
{{ row.status === 1 ? '已发布' : '未发布' }}
|
||||
<!-- 修正状态显示:1=草稿,2=已发布 -->
|
||||
{{ row.status === 1 ? '草稿' : '已发布' }}
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<el-button type="primary" size="small" @click="handleView(row)">查看</el-button>
|
||||
<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" @confirm="handleSubmit"
|
||||
<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="{ row }">
|
||||
<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;" />
|
||||
|
|
@ -33,7 +43,10 @@
|
|||
</div>
|
||||
</template>
|
||||
</NoticeForm>
|
||||
<div v-html="valueHtml"></div>
|
||||
<div v-else class="view-content">
|
||||
<h2>公告名称:{{ noticeForm.noticeName }}</h2>
|
||||
<div v-html="noticeForm.noticeContent"></div>
|
||||
</div>
|
||||
</NoticeDialog>
|
||||
<!-- dialog表格 -->
|
||||
</div>
|
||||
|
|
@ -51,45 +64,55 @@ import { search, tableColumns, formItem } from './options'
|
|||
import { rules } from './rules'
|
||||
|
||||
// 接口
|
||||
import { getNoticeListApi, createNoticeApi } from '@/api/modules/notice'
|
||||
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
|
||||
// 富文本编辑器内容 HTML
|
||||
const valueHtml = ref('')
|
||||
|
||||
// 工具栏配置
|
||||
const toolbarConfig = {
|
||||
excludeKeys: ["group-video"]
|
||||
excludeKeys: ["group-video", "fullScreen"]
|
||||
}
|
||||
const editorConfig = { placeholder: '请输入内容...' }
|
||||
|
||||
// 组件销毁时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value
|
||||
if (editor == null) return
|
||||
editor.destroy()
|
||||
// 富文本编辑器配置
|
||||
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'
|
||||
})
|
||||
|
||||
// 编辑器创建完成后回调
|
||||
const handleCreated = (editor) => {
|
||||
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)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 保留基础配置
|
||||
fieldName: 'image',
|
||||
timeout: 30 * 1000,
|
||||
maxFileSize: 5 * 1024 * 1024,
|
||||
allowedFileTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -99,10 +122,15 @@ const searchForm = ref({
|
|||
noticeName: '',
|
||||
startDateTime: '',
|
||||
endDateTime: '',
|
||||
status: 1,
|
||||
status: 2,
|
||||
})
|
||||
const searchOptions = ref(search)
|
||||
|
||||
/**
|
||||
* @description: 定义tab数据
|
||||
*/
|
||||
const activeTab = ref(2)
|
||||
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
|
|
@ -131,20 +159,18 @@ const noticeForm = ref({
|
|||
publishStartTime: '',
|
||||
publishEndTime: '',
|
||||
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 },
|
||||
{ label: '发布', value: 2 },
|
||||
{ label: '草稿', value: 1 },
|
||||
],
|
||||
})
|
||||
|
||||
/**
|
||||
* @description: 定义公共数据处理方法
|
||||
*/
|
||||
/**
|
||||
* @description: 定义请求数据方法
|
||||
*/
|
||||
|
|
@ -161,17 +187,16 @@ const getNoticeList = async () => {
|
|||
const data: any = await getNoticeListApi(params)
|
||||
// 表格数据
|
||||
noticeTree.value = data.data.map((item: any) => ({
|
||||
id: item.id,
|
||||
noticeName: item.name,
|
||||
noticeContent: item.content,
|
||||
startDateTime: item.publish_start_time,
|
||||
publishTime: item.publish_time,
|
||||
status: item.status,
|
||||
}))
|
||||
// 分页数据
|
||||
total.value = data.total
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
|
||||
console.log(noticeTree.value)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -192,8 +217,9 @@ const handleReset = () => {
|
|||
noticeName: '',
|
||||
startDateTime: '',
|
||||
endDateTime: '',
|
||||
status: 1,
|
||||
status: 2,
|
||||
}
|
||||
activeTab.value = 2
|
||||
getNoticeList()
|
||||
}
|
||||
const handleCreate = () => {
|
||||
|
|
@ -201,14 +227,54 @@ const handleCreate = () => {
|
|||
dialogTitle.value = '新建公告'
|
||||
dialogType.value = 'create'
|
||||
}
|
||||
|
||||
/**
|
||||
* @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,
|
||||
noticeContent: row.noticeContent,
|
||||
publishStartTime: row.startDateTime,
|
||||
publishEndTime: row.endDateTime,
|
||||
status: row.status,
|
||||
id: row.id,
|
||||
}
|
||||
}
|
||||
// 删除公告
|
||||
const handleDelete = async (row: any) => {
|
||||
const params = {
|
||||
id: row.id,
|
||||
}
|
||||
await deleteNoticeApi(params)
|
||||
getNoticeList()
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 定义分页方法
|
||||
*/
|
||||
|
|
@ -221,24 +287,79 @@ const handlePaginationChange = async (page: { currentPage: number, pageSize: num
|
|||
* @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: 定义弹窗表格方法
|
||||
* @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>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* @description: 搜索配置
|
||||
*/
|
||||
export const search = [
|
||||
{ prop: 'username', label: '公告名称', type: 'input' as const, placeholder: '请输入公告名称', width: '120px' },
|
||||
{ prop: 'noticeName', label: '公告名称', type: 'input' as const, placeholder: '请输入公告名称', width: '120px' },
|
||||
{
|
||||
prop: "startDateTime", label: '发布时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
|
|
@ -20,8 +20,8 @@ export const search = [
|
|||
*/
|
||||
export const tableColumns = [
|
||||
{ prop: 'noticeName', label: '公告名称'},
|
||||
{ prop: 'noticeContent', label: '公告内容'},
|
||||
{ prop: 'startDateTime', label: '发布时间'},
|
||||
// { prop: 'noticeContent', label: '公告内容'},
|
||||
{ prop: 'publishTime', label: '发布时间'},
|
||||
{ slotName: 'status', label: '状态'},
|
||||
{ slotName: 'action', label: '操作'},
|
||||
]
|
||||
|
|
@ -32,6 +32,6 @@ export const tableColumns = [
|
|||
export const formItem = [
|
||||
{ prop: 'noticeName', label: '公告名称', type: 'input' as const, placeholder: '请输入公告名称'},
|
||||
// 公告内容
|
||||
{ slotName: 'noticeContent',label: '公告内容', type: 'edit' as const},
|
||||
{ slotName: 'noticeContent', label: '公告内容', type: 'editor' as const},
|
||||
{ prop: 'status', label: '状态', type: 'radio' as const, placeholder: '请选择状态'},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { FormRules } from 'element-plus'
|
||||
export const rules = (): FormRules => {
|
||||
return {
|
||||
name: [
|
||||
noticeName: [
|
||||
{ required: true, message: '请输入名称', trigger: ['blur'] }
|
||||
],
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue