index.tsx 6.8 KB

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