|
@@ -0,0 +1,177 @@ |
|
|
|
|
|
import React, { useEffect, useState } from 'react' |
|
|
|
|
|
import { Form, Input, InputNumber, Radio, Modal, Switch } from 'antd'; |
|
|
|
|
|
import { Editor, Toolbar } from '@wangeditor/editor-for-react' |
|
|
|
|
|
import { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor' |
|
|
|
|
|
import noticeService from '@/request/service/notice'; |
|
|
|
|
|
import { useRequest } from '@/hooks/use-request'; |
|
|
|
|
|
import type { NoticeVO } from '@/models' |
|
|
|
|
|
import { antdUtils } from '@/utils/antd'; |
|
|
|
|
|
|
|
|
|
|
|
import '@wangeditor/editor/dist/css/style.css'; |
|
|
|
|
|
|
|
|
|
|
|
const layout = { |
|
|
|
|
|
labelCol: { span: 4, }, |
|
|
|
|
|
wrapperCol: { span: 16 }, |
|
|
|
|
|
bordered: false, |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
interface NoticeEditorProps { |
|
|
|
|
|
visible: boolean; |
|
|
|
|
|
onCancel: (flag?: boolean) => void; |
|
|
|
|
|
onSave: (notice: NoticeVO) => void; |
|
|
|
|
|
data?: NoticeVO | null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
interface RichEditorProps { |
|
|
|
|
|
value?: string; |
|
|
|
|
|
onChange?: (value: string) => void; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const RichEditor: React.FC<RichEditorProps> = ({ value = '', onChange }) => { |
|
|
|
|
|
// editor 实例 |
|
|
|
|
|
const [editor, setEditor] = useState<IDomEditor | null>(null) |
|
|
|
|
|
|
|
|
|
|
|
// 编辑器内容 |
|
|
|
|
|
const [html, setHtml] = useState(value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 工具栏配置 |
|
|
|
|
|
const toolbarConfig: Partial<IToolbarConfig> = {} |
|
|
|
|
|
|
|
|
|
|
|
// 编辑器配置 |
|
|
|
|
|
const editorConfig: Partial<IEditorConfig> = { |
|
|
|
|
|
placeholder: '请输入内容...', |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 及时销毁 editor ,重要! |
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
return () => { |
|
|
|
|
|
if (editor == null) return |
|
|
|
|
|
editor.destroy() |
|
|
|
|
|
setEditor(null) |
|
|
|
|
|
} |
|
|
|
|
|
}, [editor]) |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
<> |
|
|
|
|
|
<div style={{ border: '1px solid #ccc', zIndex: 1020 }}> |
|
|
|
|
|
<Toolbar |
|
|
|
|
|
editor={editor} |
|
|
|
|
|
defaultConfig={toolbarConfig} |
|
|
|
|
|
mode="default" |
|
|
|
|
|
style={{ borderBottom: '1px solid #ccc' }} |
|
|
|
|
|
/> |
|
|
|
|
|
<Editor |
|
|
|
|
|
defaultConfig={editorConfig} |
|
|
|
|
|
value={html} |
|
|
|
|
|
onCreated={setEditor} |
|
|
|
|
|
onChange={editor => { |
|
|
|
|
|
setHtml(editor.getHtml()); |
|
|
|
|
|
onChange!!(editor.getHtml()); |
|
|
|
|
|
}} |
|
|
|
|
|
mode="default" |
|
|
|
|
|
style={{ height: '300px', overflowY: 'hidden' }} |
|
|
|
|
|
/> |
|
|
|
|
|
</div> |
|
|
|
|
|
</> |
|
|
|
|
|
) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
export default (props: NoticeEditorProps) => { |
|
|
|
|
|
|
|
|
|
|
|
const { visible, onCancel, onSave, data } = props; |
|
|
|
|
|
|
|
|
|
|
|
const { runAsync: updateApi } = useRequest(noticeService.updateNoticeApi, { manual: true }); |
|
|
|
|
|
const { runAsync: createApi } = useRequest(noticeService.createNoticeApi, { manual: true }); |
|
|
|
|
|
|
|
|
|
|
|
const isEdit = !!data; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [saveLoading, setSaveLoading] = useState(false); |
|
|
|
|
|
const [form] = Form.useForm(); |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
if (visible) { |
|
|
|
|
|
if (data) { |
|
|
|
|
|
form.setFieldsValue(data); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
form.resetFields(); |
|
|
|
|
|
} |
|
|
|
|
|
}, [visible]); |
|
|
|
|
|
|
|
|
|
|
|
const save = async () => { |
|
|
|
|
|
setSaveLoading(true); |
|
|
|
|
|
const fieldValues = form.getFieldsValue(); |
|
|
|
|
|
const newValue = isEdit ? { ...data, ...fieldValues } : fieldValues; |
|
|
|
|
|
const [error, { msg, code }] = isEdit ? await updateApi(newValue) : await createApi(newValue); |
|
|
|
|
|
if (!error && code === 0) { |
|
|
|
|
|
onSave(newValue); |
|
|
|
|
|
} else { |
|
|
|
|
|
antdUtils.message?.open({ |
|
|
|
|
|
type: 'error', |
|
|
|
|
|
content: msg ?? '操作失败', |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
setSaveLoading(false); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
<> |
|
|
|
|
|
<Modal |
|
|
|
|
|
open={visible} |
|
|
|
|
|
title={isEdit ? "编辑" : "新建"} |
|
|
|
|
|
width={800} |
|
|
|
|
|
onOk={save} |
|
|
|
|
|
onCancel={() => onCancel()} |
|
|
|
|
|
confirmLoading={saveLoading} |
|
|
|
|
|
destroyOnClose |
|
|
|
|
|
> |
|
|
|
|
|
<Form |
|
|
|
|
|
form={form} |
|
|
|
|
|
{...layout} |
|
|
|
|
|
onFinish={save} |
|
|
|
|
|
labelCol={{ flex: '0 0 100px' }} |
|
|
|
|
|
wrapperCol={{ span: 16}} |
|
|
|
|
|
> |
|
|
|
|
|
<Form.Item name="title" label="公告标题" |
|
|
|
|
|
rules={[ |
|
|
|
|
|
{ |
|
|
|
|
|
required: true, |
|
|
|
|
|
message: '请输入公告标题', |
|
|
|
|
|
}, |
|
|
|
|
|
]} |
|
|
|
|
|
> |
|
|
|
|
|
<Input /> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
|
|
|
|
|
|
<Form.Item name="type" label="公告类型" |
|
|
|
|
|
rules={[ |
|
|
|
|
|
{ |
|
|
|
|
|
required: true, |
|
|
|
|
|
message: '请选择公告类型', |
|
|
|
|
|
}, |
|
|
|
|
|
]}> |
|
|
|
|
|
<Radio.Group options={[ |
|
|
|
|
|
{ value: 1, label: "通知" }, |
|
|
|
|
|
{ value: 2, label: "公告" }, |
|
|
|
|
|
]} optionType="button"> |
|
|
|
|
|
</Radio.Group> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
|
|
|
|
|
|
<Form.Item name="status" label="状态"> |
|
|
|
|
|
<Radio.Group options={[ |
|
|
|
|
|
{ value: 0, label: "开启" }, |
|
|
|
|
|
{ value: 1, label: "关闭" } |
|
|
|
|
|
]} optionType="default"> |
|
|
|
|
|
</Radio.Group> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
|
|
|
|
|
|
<Form.Item name="content" label="公告内容"> |
|
|
|
|
|
<RichEditor /> |
|
|
|
|
|
</Form.Item> |
|
|
|
|
|
</Form> |
|
|
|
|
|
</Modal> |
|
|
|
|
|
</> |
|
|
|
|
|
) |
|
|
|
|
|
}; |