index.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import React, { useCallback, useMemo, useRef, useState } from 'react'
  2. import styles from './index.module.scss'
  3. // 引入编辑器组件
  4. // 安装---npm install braft-editor --save --force
  5. // npm install braft-utils --save --force
  6. import { ContentUtils } from 'braft-utils'
  7. import BraftEditor from 'braft-editor'
  8. // 引入编辑器样式
  9. import 'braft-editor/dist/index.css'
  10. import classNames from 'classnames'
  11. import { MessageFu } from '@/utils/message'
  12. import { fileDomInitialFu } from '@/utils/domShow'
  13. import { baseURL } from '@/utils/http'
  14. import { forwardRef, useImperativeHandle } from 'react'
  15. import { API_upFile } from '@/store/action/layout'
  16. import { Button } from 'antd'
  17. type Props = {
  18. check: boolean //表单校验,为fasle表示不校验
  19. isLook: boolean //是否是查看进来
  20. ref: any //当前自己的ref,给父组件调用
  21. myUrl: string //上传的api地址
  22. dirCode: string
  23. moduleId: number
  24. titTxt?: string
  25. }
  26. function ZRichTextOne(
  27. { check, isLook, myUrl, titTxt = '请输入内容', dirCode, moduleId }: Props,
  28. ref: any
  29. ) {
  30. const [section, setSection] = useState(BraftEditor.createEditorState(''))
  31. // 判断 富文本是否为空
  32. const isTxtFlag = useMemo(() => {
  33. let flag = false
  34. // 不是按章节发布,检查第一个富文本
  35. const txt = section.toText()
  36. const txtHtml = section.toHTML()
  37. const txtRes = txt.replaceAll('\n', '').replaceAll(' ', '')
  38. if (!txtRes && !txtHtml.includes('class="media-wrap')) flag = true
  39. return flag
  40. }, [section])
  41. const myInput = useRef<HTMLInputElement>(null)
  42. // 上传图片、视频
  43. const handeUpPhoto = useCallback(
  44. async (e: React.ChangeEvent<HTMLInputElement>) => {
  45. if (e.target.files) {
  46. // 拿到files信息
  47. const filesInfo = e.target.files[0]
  48. let type = ['image/jpeg', 'image/png', 'video/mp4']
  49. let size = 5
  50. let txt = '图片只支持png、jpg和jpeg格式!'
  51. let txt2 = '图片最大支持5M!'
  52. // 校验格式
  53. if (!type.includes(filesInfo.type)) {
  54. e.target.value = ''
  55. return MessageFu.warning(txt)
  56. }
  57. // 校验大小
  58. if (filesInfo.size > size * 1024 * 1024) {
  59. e.target.value = ''
  60. return MessageFu.warning(txt2)
  61. }
  62. // 创建FormData对象
  63. const fd = new FormData()
  64. // 把files添加进FormData对象(‘photo’为后端需要的字段)
  65. fd.append('type', 'img')
  66. fd.append('dirCode', dirCode)
  67. fd.append('isCompress', 'true')
  68. fd.append('moduleId', moduleId + '')
  69. fd.append('file', filesInfo)
  70. e.target.value = ''
  71. try {
  72. const res = await API_upFile(fd, myUrl)
  73. if (res.code === 0) {
  74. MessageFu.success('上传成功')
  75. // 在光标位置插入图片
  76. const newTxt = ContentUtils.insertMedias(section, [
  77. {
  78. type: 'IMAGE',
  79. url: baseURL + (res.data.thumb || res.data.thumbPc)
  80. }
  81. ])
  82. setSection(newTxt)
  83. }
  84. fileDomInitialFu()
  85. } catch (error) {
  86. fileDomInitialFu()
  87. }
  88. }
  89. },
  90. [dirCode, moduleId, myUrl, section]
  91. )
  92. // 让父组件调用的 回显 富文本
  93. const ritxtShowFu = useCallback((val: any) => {
  94. if (val) setSection(BraftEditor.createEditorState(val))
  95. }, [])
  96. // 让父组件调用的返回 富文本信息 和 表单校验 isTxtFlag为ture表示未通过校验
  97. const fatherBtnOkFu = useCallback(() => {
  98. return { val: section.toHTML(), flag: isTxtFlag }
  99. }, [isTxtFlag, section])
  100. // 可以让父组件调用子组件的方法
  101. useImperativeHandle(ref, () => ({
  102. ritxtShowFu,
  103. fatherBtnOkFu
  104. }))
  105. return (
  106. <div className={styles.ZRichTextOne} id='ZRichTextOne'>
  107. <input
  108. id='upInput'
  109. type='file'
  110. accept='.png,.jpg,.jpeg,.mp4'
  111. ref={myInput}
  112. onChange={e => handeUpPhoto(e)}
  113. />
  114. <div className={classNames('formRightZW', isLook ? 'formRightZWLook' : '')}>
  115. <div className='formRightZWRR'>
  116. <div hidden={isLook}>
  117. <Button
  118. onClick={() => {
  119. myInput.current?.click()
  120. }}
  121. >
  122. 上传图片
  123. </Button>
  124. </div>
  125. </div>
  126. </div>
  127. <div className={classNames('txtBox', isLook ? 'txtBoxLook' : '')}>
  128. <div className={classNames('zztxtRow')}>
  129. {/* 主体 */}
  130. <BraftEditor
  131. readOnly={isLook}
  132. placeholder={isLook ? '(空)' : '请输入内容'}
  133. value={section}
  134. onChange={e => setSection(e)}
  135. imageControls={['remove']}
  136. />
  137. </div>
  138. </div>
  139. <div className={classNames('noUpThumb', check && isTxtFlag ? 'noUpThumbAc' : '')}>
  140. {titTxt}
  141. </div>
  142. </div>
  143. )
  144. }
  145. export default forwardRef(ZRichTextOne)