modal.tsx 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. import React, { useState, useEffect, useLayoutEffect } from 'react';
  2. import { Modal, Row, Col, Space, Form, Input, Select, message, Upload, Button } from 'antd';
  3. import { ScissorOutlined } from '@ant-design/icons';
  4. import { getAgent } from '@/services/agent';
  5. import { postOrPutNotice } from '@/services/notice';
  6. import { uploadFile } from '@/services/user';
  7. // import ReactWEditor from 'wangeditor-for-react';
  8. // 引入编辑器组件
  9. import BraftEditor, { ControlType, ExtendControlType, ImageControlType } from 'braft-editor';
  10. // 引入编辑器样式
  11. import 'braft-editor/dist/index.css';
  12. import { ContentUtils } from 'braft-utils';
  13. import { baseUrl } from '@/utils/request';
  14. import type { noticeModalProps } from './data';
  15. import type { Dispatch } from 'umi';
  16. import { useIntl } from 'react-intl';
  17. import { Role } from '@/models/user';
  18. const layout = {
  19. labelCol: { span: 5 },
  20. wrapperCol: { span: 16 },
  21. };
  22. // 定义rem基准值
  23. const sizeBase = 23.4375;
  24. interface IProps {
  25. dispatch: Dispatch;
  26. roleList: Role[];
  27. }
  28. interface EditorDemoProps {
  29. editorContent: string;
  30. changeContent: (content: string) => void;
  31. }
  32. class EditorDemo extends React.Component<EditorDemoProps> {
  33. state = {
  34. // 创建一个空的editorState作为初始值
  35. editorState: BraftEditor.createEditorState(null),
  36. editorInstance: null,
  37. };
  38. async componentDidMount() {
  39. // 假设此处从服务端获取html格式的编辑器内容
  40. const htmlContent = this.props.editorContent;
  41. console.log(htmlContent, 'htmlContenthtmlContenthtmlContent');
  42. // 使用BraftEditor.createEditorState将html字符串转换为编辑器需要的editorStat
  43. this.setState({
  44. editorState: BraftEditor.createEditorState(htmlContent),
  45. });
  46. console.log(this.state.editorInstance.getValue(), '222');
  47. }
  48. submitContent = async () => {
  49. // 在编辑器获得焦点时按下ctrl+s会执行此方法
  50. // 编辑器内容提交到服务端之前,可直接调用editorState.toHTML()来获取HTML格式的内容
  51. // const htmlContent = this.state.editorState.toHTML()
  52. // const result = await saveEditorContent(htmlContent)
  53. };
  54. handleEditorChange = (editorState) => {
  55. console.log(editorState.toHTML(), 'editorState');
  56. this.setState({ editorState });
  57. this.props.changeContent(editorState.toHTML());
  58. };
  59. handleChange = ({ fileList }: { fileList: Record<string, any> }): void => {
  60. console.log(fileList, 'fileList');
  61. const len = fileList.length - 1;
  62. if (fileList[len]?.status === 'done') {
  63. if (fileList[len].response.code === 0) {
  64. console.log(fileList[len].response.data, ' fileList[len].response.data');
  65. this.setState({
  66. editorState: ContentUtils.insertMedias(this.state.editorState, [
  67. {
  68. type: 'IMAGE',
  69. url: fileList[len].response.data + `?imageView2/1/w/343/h/192`,
  70. width: '343px',
  71. height: '192px',
  72. },
  73. ]),
  74. });
  75. }
  76. }
  77. };
  78. circleImg = (mediaData) => {
  79. console.log(mediaData, 'mediaDatamediaData');
  80. const { url }: { url: string } = mediaData;
  81. if (url.includes('?imageView2')) {
  82. mediaData.url = mediaData.url.split('?imageView2')[0];
  83. } else {
  84. mediaData.url =
  85. mediaData.url +
  86. `?imageView2/1/w/${parseInt(mediaData.width)}/h/${parseInt(mediaData.height)}`;
  87. }
  88. };
  89. render() {
  90. const controls = [
  91. 'bold',
  92. 'italic',
  93. 'underline',
  94. 'text-color',
  95. 'separator',
  96. 'list-ul',
  97. 'list-ol',
  98. 'emoji',
  99. 'text-indent',
  100. 'headings',
  101. 'clear',
  102. 'hr',
  103. 'blockquote',
  104. 'font-size',
  105. 'line-height',
  106. ];
  107. const extendControls: ExtendControlType[] = [
  108. {
  109. key: 'antd-uploader',
  110. type: 'component',
  111. component: (
  112. <Upload
  113. accept="image/*"
  114. action={`${baseUrl}/forum/file/uploadImage`}
  115. showUploadList={false}
  116. // customRequest={this.uploadHandler}
  117. onChange={this.handleChange}
  118. >
  119. <button
  120. type="button"
  121. className="control-item button upload-button"
  122. data-title="插入图片"
  123. >
  124. 插入图片
  125. </button>
  126. </Upload>
  127. ),
  128. },
  129. ];
  130. const hooks = {
  131. 'set-image-size': ({ width, height }) => {
  132. console.log(width, 'widthwidth');
  133. let _width = width;
  134. if (_width === undefined) {
  135. _width = '343rpx';
  136. }
  137. if (parseInt(_width) !== 343) {
  138. message.warning('图片宽度默认为343');
  139. return false;
  140. }
  141. return {
  142. width: _width,
  143. height: height,
  144. };
  145. },
  146. };
  147. const imageControls: ImageControlType[] = [
  148. // 'float-left',
  149. // 'float-right',
  150. // {
  151. // text: '裁剪图片',
  152. // render: (mediaData) => (
  153. // <a>
  154. // <ScissorOutlined color="#fff" onClick={() => this.circleImg(mediaData)} />
  155. // </a>
  156. // ),
  157. // },
  158. 'size',
  159. 'remove',
  160. ];
  161. const { editorState } = this.state;
  162. return (
  163. <div className="my-component">
  164. <BraftEditor
  165. hooks={hooks}
  166. imageResizable={false}
  167. style={{ border: '1px solid #d9d9d9', width: '375px' }}
  168. controls={controls}
  169. imageControls={imageControls}
  170. ref={(instance) => (this.state.editorInstance = instance)}
  171. extendControls={extendControls}
  172. value={editorState}
  173. onChange={this.handleEditorChange}
  174. />
  175. </div>
  176. );
  177. }
  178. }
  179. type NoticeModalProps = noticeModalProps | IProps;
  180. const NoticeModal: React.FC<noticeModalProps & IProps> = ({
  181. GetNotice,
  182. type,
  183. closeModal,
  184. visible,
  185. curNoticeData,
  186. dispatch,
  187. roleList,
  188. }) => {
  189. console.log(roleList, 'roleListroleList');
  190. const [form] = Form.useForm();
  191. const [label, setLabel] = useState('');
  192. const [content, setContent] = useState('');
  193. // editContent 反填
  194. const [editContent, setEditContent] = useState<string>('');
  195. // 反填表单时的值
  196. const [editForm, setEditForm] = useState({});
  197. useEffect(() => {
  198. onFill();
  199. dispatch({
  200. type: 'user/getRoleList',
  201. payload: {
  202. curPage: 1,
  203. passSize: 100,
  204. },
  205. });
  206. }, []);
  207. // 新增或者编辑公告
  208. const PostOrPutNotice = async (record: any): Promise<void> => {
  209. const { code, data } = await postOrPutNotice({ ...record });
  210. if (code === 0 && data) {
  211. message.success(type === 1 ? '编辑成功' : '新增成功');
  212. } else {
  213. message.success(type === 1 ? '编辑失败' : '新增失败');
  214. }
  215. closeModal();
  216. GetNotice();
  217. };
  218. // 反填表单
  219. const onFill = (): void => {
  220. console.log(curNoticeData, '反填表单');
  221. const $par = { ...curNoticeData };
  222. form.setFieldsValue($par);
  223. setEditForm($par);
  224. setEditContent(curNoticeData.content);
  225. };
  226. const onFinish = (values: any) => {
  227. console.log(values, 'values');
  228. console.log(content, 'contentcontent');
  229. if (content === '<p></p>') {
  230. message.error('请填写公告内容');
  231. return;
  232. }
  233. let $par;
  234. if (type === 1) {
  235. $par = {
  236. ...editForm,
  237. ...values,
  238. userIds: ['ALL'],
  239. roles: values.roles,
  240. type: 'ANN',
  241. methodType: type,
  242. content,
  243. };
  244. } else {
  245. $par = {
  246. ...values,
  247. userIds: ['ALL'],
  248. roles: values.roles,
  249. type: 'ANN',
  250. methodType: type,
  251. content,
  252. };
  253. }
  254. console.log($par);
  255. PostOrPutNotice($par);
  256. };
  257. // 提交表单
  258. const onsubmit = () => form.submit();
  259. // 设置标题
  260. const changeLabel = (e: React.ChangeEvent<HTMLInputElement>): void => setLabel(e.target.value);
  261. // 内容
  262. const changeContent = (content: string): void => setContent(content);
  263. return (
  264. <Modal
  265. width="700px"
  266. visible={visible}
  267. title="发布公告"
  268. onOk={() => onsubmit()}
  269. onCancel={closeModal}
  270. >
  271. <Form {...layout} form={form} onFinish={onFinish}>
  272. <Form.Item
  273. name="roles"
  274. label="可看人员:"
  275. rules={[{ required: true, message: '请选择可看人员' }]}
  276. >
  277. <Select style={{ width: '375px' }} mode="multiple">
  278. {roleList.length &&
  279. roleList.map((item: Record<string, any>) => (
  280. <Select.Option key={item.id} value={item.id}>
  281. {item.label}
  282. </Select.Option>
  283. ))}
  284. </Select>
  285. </Form.Item>
  286. <Form.Item
  287. name="label"
  288. label="公告标题:"
  289. rules={[{ required: true, message: '请填写公告标题' }]}
  290. >
  291. <Input style={{ width: '375px' }} onChange={changeLabel} maxLength={80}></Input>
  292. </Form.Item>
  293. <Form.Item name="content" label="公告内容:">
  294. <EditorDemo key={editContent} changeContent={changeContent} editorContent={editContent} />
  295. </Form.Item>
  296. </Form>
  297. </Modal>
  298. );
  299. };
  300. export default NoticeModal;