index.tsx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import { Button, Input, message, Modal, Popconfirm, Select } from "antd";
  2. import React, { useCallback, useEffect, useRef, useState } from "react";
  3. import {
  4. PlusOutlined,
  5. CloseCircleOutlined,
  6. UploadOutlined,
  7. PlayCircleOutlined,
  8. } from "@ant-design/icons";
  9. import "./index.css";
  10. import ImageLazy from "@/components/ImageLazy";
  11. import {
  12. getWallDetailByIdAPI,
  13. wallUploadAPI,
  14. wallUpSaveAPI,
  15. } from "@/store/action/wall";
  16. import { WallUpSaveAPI } from "@/types";
  17. import { useDispatch } from "react-redux";
  18. type Props = {
  19. id: number;
  20. closeFu: () => void;
  21. upList: () => void;
  22. };
  23. // 上传附件的进度条
  24. const UpAsyncLodingDom: any = document.querySelector("#UpAsyncLoding");
  25. const progressDom: any = document.querySelector("#progress");
  26. function WallAdd({ id, closeFu, upList }: Props) {
  27. const dispatch = useDispatch();
  28. // 上传的inputRef
  29. const myInput = useRef<HTMLInputElement>(null);
  30. // 类型
  31. const [type, setType] = useState<"img" | "video">("img");
  32. // 名称
  33. const [name, setName] = useState("");
  34. // 图片
  35. const [cover, setCover] = useState({ fileName: "", filePath: "" });
  36. // 视频
  37. const [video, setVideo] = useState({ fileName: "", filePath: "" });
  38. // 通过id获取详情
  39. const getInfoById = useCallback(async () => {
  40. const res = await getWallDetailByIdAPI(id);
  41. setType(res.data.type);
  42. setName(res.data.name);
  43. if (res.data.type === "img")
  44. setCover({ fileName: res.data.fileName, filePath: res.data.filePath });
  45. else setVideo({ fileName: res.data.fileName, filePath: res.data.filePath });
  46. }, [id]);
  47. // 进来看看是不是编辑
  48. useEffect(() => {
  49. if (id) getInfoById();
  50. }, [getInfoById, id]);
  51. // 上传图片或者视频
  52. const handeUpPhoto = useCallback(
  53. async (e: React.ChangeEvent<HTMLInputElement>) => {
  54. if (e.target.files) {
  55. // 拿到files信息
  56. const filesInfo = e.target.files[0];
  57. let typeArr = [] as string[];
  58. let tit1 = "";
  59. let fileSize = 20 * 1024 * 1024;
  60. let tit2 = "最大支持20M!";
  61. if (type === "img") {
  62. typeArr = ["image/jpeg", "image/png", "image/gif"];
  63. tit1 = "只支持jpg、png、gif格式!";
  64. } else {
  65. tit2 = "最大支持500M!";
  66. fileSize = 500 * 1024 * 1024;
  67. typeArr = ["video/mp4"];
  68. tit1 = "只支持mp4格式!";
  69. }
  70. // 校验格式
  71. if (!typeArr.includes(filesInfo.type)) {
  72. e.target.value = "";
  73. return message.warning(tit1);
  74. }
  75. // 校验大小
  76. if (filesInfo.size > fileSize) {
  77. e.target.value = "";
  78. return message.warning(tit2);
  79. }
  80. // 创建FormData对象
  81. const fd = new FormData();
  82. // 把files添加进FormData对象(‘photo’为后端需要的字段)
  83. fd.append("type", type);
  84. fd.append("file", filesInfo);
  85. e.target.value = "";
  86. const res: any = await wallUploadAPI(fd);
  87. if (res.code === 0) {
  88. message.success("上传成功!");
  89. // 上传的是图片
  90. if (type === "img") setCover(res.data);
  91. else setVideo(res.data);
  92. }
  93. UpAsyncLodingDom.style.opacity = 0;
  94. progressDom.style.width = "0%";
  95. }
  96. },
  97. [type]
  98. );
  99. // 点击确定
  100. const btnOkFu = useCallback(async () => {
  101. if (name === "") return message.warning("名称不能为空!");
  102. if (
  103. (type === "img" && cover.fileName === "") ||
  104. (type === "video" && video.fileName === "")
  105. )
  106. return message.warning("附件不能为空!");
  107. const obj: WallUpSaveAPI = {
  108. fileName: type === "img" ? cover.fileName : video.fileName,
  109. filePath: type === "img" ? cover.filePath : video.filePath,
  110. id: id ? id : null,
  111. name: name,
  112. type: type,
  113. };
  114. const res: any = await wallUpSaveAPI(obj);
  115. if (res.code === 0) {
  116. message.success(`${id ? "编辑" : "新增"}成功!`);
  117. upList();
  118. closeFu();
  119. }
  120. }, [
  121. closeFu,
  122. cover.fileName,
  123. cover.filePath,
  124. id,
  125. name,
  126. type,
  127. upList,
  128. video.fileName,
  129. video.filePath,
  130. ]);
  131. return (
  132. <Modal
  133. wrapClassName="wallAdd"
  134. destroyOnClose
  135. open={true}
  136. title={id ? "编辑" : "新增"}
  137. footer={
  138. [] // 设置footer为空,去掉 取消 确定默认按钮
  139. }
  140. >
  141. {/* 主要内容 */}
  142. <div className="wallAddMain">
  143. <div className="row">
  144. <div className="bs">*</div>
  145. <div className="lable">类型:</div>
  146. <Select
  147. value={type}
  148. onChange={(val) => setType(val)}
  149. style={{ width: 100 }}
  150. options={[
  151. { value: "img", label: "图片" },
  152. { value: "video", label: "视频" },
  153. ]}
  154. />
  155. </div>
  156. <div className="row">
  157. <div className="bs">*</div>
  158. <div className="lable">名称:</div>
  159. <Input
  160. maxLength={15}
  161. showCount
  162. style={{ width: 300 }}
  163. placeholder="请输入"
  164. value={name}
  165. onChange={(e) => setName(e.target.value.trim())}
  166. />
  167. </div>
  168. <div className="row">
  169. <div className="bs">*</div>
  170. <div className="lable">附件:</div>
  171. <div className="upBox">
  172. <input
  173. id="upInput"
  174. type="file"
  175. accept={type === "img" ? ".png,.jpg,.gif,.jpeg" : ".mp4"}
  176. ref={myInput}
  177. onChange={(e) => handeUpPhoto(e)}
  178. />
  179. {type === "img" ? (
  180. // 图片上传
  181. <>
  182. <div
  183. hidden={cover.fileName !== ""}
  184. className="fileBoxRow_up"
  185. onClick={() => myInput.current?.click()}
  186. >
  187. <PlusOutlined />
  188. </div>
  189. <div
  190. className="fileBoxRow_r_img"
  191. hidden={cover.fileName === ""}
  192. >
  193. {cover.filePath ? (
  194. <ImageLazy width={120} height={120} src={cover.filePath} />
  195. ) : null}
  196. <Popconfirm
  197. title="删除后无法恢复,是否删除?"
  198. okText="删除"
  199. cancelText="取消"
  200. onConfirm={() => setCover({ fileName: "", filePath: "" })}
  201. >
  202. <div className="clearCover">
  203. <CloseCircleOutlined />
  204. </div>
  205. </Popconfirm>
  206. </div>
  207. </>
  208. ) : (
  209. // 视频上传
  210. <>
  211. <div className="upVideo">
  212. <Button
  213. onClick={() => myInput.current?.click()}
  214. icon={<UploadOutlined />}
  215. >
  216. 上传
  217. </Button>
  218. </div>
  219. {/* 视频上传成功之后的信息 */}
  220. <div className="upVideoSucc">
  221. <div className="upVideoSuccTxt">{video.fileName}</div>
  222. <div
  223. className="lookVideoIncoBox"
  224. hidden={!video.fileName}
  225. onClick={() =>
  226. dispatch({
  227. type: "login/lookVideo",
  228. payload: video.filePath,
  229. })
  230. }
  231. >
  232. <PlayCircleOutlined />
  233. </div>
  234. <Popconfirm
  235. title="删除后无法恢复,是否删除?"
  236. okText="删除"
  237. cancelText="取消"
  238. onConfirm={() => setVideo({ fileName: "", filePath: "" })}
  239. >
  240. <div className="clearCover" hidden={!video.fileName}>
  241. <CloseCircleOutlined />
  242. </div>
  243. </Popconfirm>
  244. </div>
  245. </>
  246. )}
  247. {/* 图片上传提示 */}
  248. <div className="fileBoxRow_r_tit" hidden={type !== "img"}>
  249. 图片格式:支持png、jpg、gif和jpeg的图片格式;最大支持20M。
  250. </div>
  251. {/* 视频上传提示 */}
  252. <div className="fileBoxRow_r_tit" hidden={type !== "video"}>
  253. 视频格式:仅支持MP4格式的视频文件,大小不得超过500MB。
  254. </div>
  255. </div>
  256. </div>
  257. </div>
  258. {/* 确定按钮 */}
  259. <div className="wallAddBtn">
  260. <Button type="primary" onClick={btnOkFu}>
  261. 提交
  262. </Button>
  263. &emsp;
  264. <Popconfirm
  265. title="放弃编辑后,信息将不会保存!"
  266. okText="放弃"
  267. cancelText="取消"
  268. onConfirm={closeFu}
  269. >
  270. <Button>取消</Button>
  271. </Popconfirm>
  272. </div>
  273. </Modal>
  274. );
  275. }
  276. const MemoWallAdd = React.memo(WallAdd);
  277. export default MemoWallAdd;