index.tsx 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. import React, { useCallback, useMemo, useRef, useState } from 'react'
  2. import styles from './index.module.scss'
  3. import ImageLazy from '@/components/ImageLazy'
  4. import {
  5. PlusOutlined,
  6. EyeOutlined,
  7. CloseOutlined,
  8. DownloadOutlined,
  9. UploadOutlined
  10. } from '@ant-design/icons'
  11. import store from '@/store'
  12. import { baseURL } from '@/utils/http'
  13. import classNames from 'classnames'
  14. import { Button } from 'antd'
  15. import { MessageFu } from '@/utils/message'
  16. import { fileDomInitialFu } from '@/utils/domShow'
  17. import { API_upFile } from '@/store/action/layout'
  18. import { forwardRef, useImperativeHandle } from 'react'
  19. import MyPopconfirm from '../MyPopconfirm'
  20. type MyTypeType = 'thumb' | 'video' | 'audio' | 'model' | 'pdf' | 'epub'
  21. // 这个组件 只处理 上传 一张图片或者 视频 音频 模型 pdf 的情况
  22. type Props = {
  23. fileCheck: boolean //有没有点击过确定
  24. size: number //上传附件大小(M)
  25. dirCode: string //文件的code码
  26. myUrl: string //请求地址
  27. format: string[] //上传格式 ["image/jpeg", "image/png"] ["video/mp4"] ,application/pdf
  28. formatTxt: string //上传图片提示
  29. checkTxt: string
  30. upTxt: string
  31. myType: MyTypeType
  32. isLook?: boolean //是不是查看
  33. ref: any //当前自己的ref,给父组件调用
  34. // 其他后端需要的配置项
  35. otherArr?: { key: string; value: string }[]
  36. }
  37. function ZupOne(
  38. {
  39. fileCheck,
  40. size,
  41. dirCode,
  42. myUrl,
  43. format,
  44. formatTxt,
  45. checkTxt,
  46. upTxt,
  47. myType,
  48. isLook = false,
  49. otherArr
  50. }: Props,
  51. ref: any
  52. ) {
  53. const [fileUrl, setFileUrl] = useState({
  54. fileName: '',
  55. filePath: '',
  56. thumb: '' //压缩图
  57. })
  58. const myInput = useRef<HTMLInputElement>(null)
  59. // 上传封面图
  60. const handeUpPhoto = useCallback(
  61. async (e: React.ChangeEvent<HTMLInputElement>) => {
  62. if (e.target.files) {
  63. // 拿到files信息
  64. const filesInfo = e.target.files[0]
  65. // console.log("-----", filesInfo.type);
  66. // 校验格式
  67. const type = format
  68. if (myType === 'pdf') {
  69. if (!filesInfo.type.includes('pdf')) {
  70. e.target.value = ''
  71. return MessageFu.warning(`只支持${formatTxt}格式!`)
  72. }
  73. } else if (myType === 'epub') {
  74. if (!filesInfo.name.endsWith('.epub')) {
  75. e.target.value = ''
  76. return MessageFu.warning(`只支持${formatTxt}格式!`)
  77. }
  78. } else {
  79. if (!type.includes(filesInfo.type)) {
  80. e.target.value = ''
  81. return MessageFu.warning(`只支持${formatTxt}格式!`)
  82. }
  83. }
  84. // 校验大小
  85. if (filesInfo.size > size * 1024 * 1024) {
  86. e.target.value = ''
  87. return MessageFu.warning(`最大支持${size}M!`)
  88. }
  89. // 创建FormData对象
  90. const fd = new FormData()
  91. // 把files添加进FormData对象(‘photo’为后端需要的字段)
  92. let myTypeRes: string = myType
  93. if (['pdf', 'epub'].includes(myTypeRes)) myTypeRes = 'doc'
  94. fd.append('type', myTypeRes)
  95. fd.append('dirCode', dirCode)
  96. fd.append('file', filesInfo)
  97. if (otherArr) {
  98. otherArr.forEach((v: any) => {
  99. fd.append(v.key, v.value)
  100. })
  101. }
  102. if (filesInfo.size > 1 * 1024 * 1024) {
  103. // 开启压缩图片
  104. fd.append('isCompress', 'true')
  105. }
  106. e.target.value = ''
  107. try {
  108. const res = await API_upFile(fd, myUrl)
  109. if (res.code === 0) {
  110. MessageFu.success('上传成功!')
  111. setFileUrl(res.data)
  112. }
  113. fileDomInitialFu()
  114. } catch (error) {
  115. fileDomInitialFu()
  116. }
  117. }
  118. },
  119. [dirCode, format, formatTxt, myType, myUrl, otherArr, size]
  120. )
  121. // 让父组件调用的 回显 附件 地址
  122. const setFileComFileFu = useCallback(
  123. (valObj: { fileName: string; filePath: string; thumb: string }) => {
  124. setFileUrl(valObj)
  125. },
  126. []
  127. )
  128. // 让父组件调用的返回 附件 名字和路径
  129. const fileComFileResFu = useCallback(() => {
  130. return fileUrl
  131. }, [fileUrl])
  132. // 可以让父组件调用子组件的方法
  133. useImperativeHandle(ref, () => ({
  134. setFileComFileFu,
  135. fileComFileResFu
  136. }))
  137. const acceptRes = useMemo(() => {
  138. let accept = '.png,.jpg,.jpeg'
  139. if (myType === 'video') accept = '.mp4'
  140. else if (myType === 'audio') accept = '.mp3'
  141. else if (myType === 'model') accept = '.4dage'
  142. else if (myType === 'pdf') accept = '.pdf'
  143. else if (myType === 'epub') accept = '.epub'
  144. return accept
  145. }, [myType])
  146. // 点击 预览(除了图片)
  147. const lookFileNoImgFu = useCallback(
  148. (type: MyTypeType) => {
  149. if (type === 'pdf' || type === 'thumb') {
  150. // 新窗口打开
  151. window.open(baseURL + fileUrl.filePath)
  152. } else if (type !== 'epub') {
  153. store.dispatch({
  154. type: 'layout/lookDom',
  155. payload: { src: fileUrl.filePath, type }
  156. })
  157. }
  158. // if (type === "pdf") {
  159. // } else {
  160. // }
  161. },
  162. [fileUrl.filePath]
  163. )
  164. return (
  165. <div className={styles.ZupOne}>
  166. <input
  167. id='upInput'
  168. type='file'
  169. accept={acceptRes}
  170. ref={myInput}
  171. onChange={e => handeUpPhoto(e)}
  172. />
  173. {myType === 'thumb' ? (
  174. <div
  175. hidden={fileUrl.filePath !== ''}
  176. className='file_upIcon'
  177. onClick={() => myInput.current?.click()}
  178. >
  179. <PlusOutlined rev={undefined} />
  180. </div>
  181. ) : (
  182. <Button
  183. hidden={fileUrl.filePath !== ''}
  184. onClick={() => myInput.current?.click()}
  185. icon={<UploadOutlined rev={undefined} />}
  186. >
  187. 上传
  188. </Button>
  189. )}
  190. {/* 为图片的情况-------------- */}
  191. {myType === 'thumb' ? (
  192. <div className='file_img' hidden={fileUrl.filePath === ''}>
  193. {fileUrl ? (
  194. <ImageLazy
  195. width={100}
  196. height={100}
  197. srcBig={fileUrl.filePath}
  198. src={fileUrl.thumb}
  199. noLook
  200. />
  201. ) : null}
  202. {/* 删除 */}
  203. <div className='file_closeBox' hidden={isLook}>
  204. <MyPopconfirm
  205. txtK='删除'
  206. onConfirm={() => setFileUrl({ fileName: '', filePath: '', thumb: '' })}
  207. Dom={<CloseOutlined rev={undefined} />}
  208. />
  209. </div>
  210. {/* 预览 下载 */}
  211. <div className='file_lookBox'>
  212. <EyeOutlined
  213. onClick={() =>
  214. store.dispatch({
  215. type: 'layout/lookBigImg',
  216. payload: { url: baseURL + fileUrl.filePath, show: true }
  217. })
  218. }
  219. rev={undefined}
  220. />
  221. <a href={baseURL + fileUrl.filePath} download target='_blank' rel='noreferrer'>
  222. <DownloadOutlined rev={undefined} />
  223. </a>
  224. </div>
  225. </div>
  226. ) : fileUrl.filePath ? (
  227. <div className='fileInfo'>
  228. <div className='upSuccTxt'>{fileUrl.fileName}</div>
  229. {/* 视频预览 */}
  230. <div
  231. className='clearCover'
  232. hidden={!fileUrl.filePath || myType === 'epub'}
  233. onClick={() => lookFileNoImgFu(myType)}
  234. >
  235. <EyeOutlined rev={undefined} />
  236. </div>
  237. {/* 视频下载 */}
  238. <a
  239. href={baseURL + fileUrl.filePath}
  240. download
  241. target='_blank'
  242. className='clearCover'
  243. rel='noreferrer'
  244. >
  245. <DownloadOutlined rev={undefined} />
  246. </a>
  247. {/* 视频删除 */}
  248. {isLook ? null : (
  249. <MyPopconfirm
  250. txtK='删除'
  251. onConfirm={() => setFileUrl({ fileName: '', filePath: '', thumb: '' })}
  252. Dom={<CloseOutlined className='clearCover' rev={undefined} />}
  253. />
  254. )}
  255. </div>
  256. ) : null}
  257. <div className='fileBoxRow_r_tit' hidden={isLook}>
  258. 格式要求:支持{formatTxt}格式;最大支持{size}M。{upTxt}
  259. <br />
  260. <div
  261. className={classNames('noUpThumb', !fileUrl.filePath && fileCheck ? 'noUpThumbAc' : '')}
  262. >
  263. {checkTxt}
  264. </div>
  265. </div>
  266. </div>
  267. )
  268. }
  269. export default forwardRef(ZupOne)