index.tsx 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. import { MessageFu } from "@/utils/message";
  2. import { Button, Form, Input, Popconfirm, Radio } from "antd";
  3. import React, { useCallback, useEffect, useRef, useState } from "react";
  4. import { PlusOutlined, CloseOutlined } from "@ant-design/icons";
  5. import classNames from "classnames";
  6. import styles from "./index.module.scss";
  7. import ImageLazy from "@/components/ImageLazy";
  8. import { ImgListType } from "@/types";
  9. import WallLook from "../WallLook";
  10. type Props = {
  11. id: number;
  12. closeMoalFu: () => void;
  13. };
  14. // 上传附件的进度条
  15. const UpAsyncLodingDom: any = document.querySelector("#UpAsyncLoding");
  16. const progressDom: any = document.querySelector("#progress");
  17. function WallAdd({ id, closeMoalFu }: Props) {
  18. const getInfoFu = useCallback((id: number) => {
  19. console.log("是编辑", id);
  20. }, []);
  21. useEffect(() => {
  22. if (id > 0) getInfoFu(id);
  23. }, [getInfoFu, id]);
  24. // 表单的ref
  25. const FormBoxRef = useRef<any>({});
  26. // 上传封面图的ref
  27. const myInput = useRef<HTMLInputElement>(null);
  28. // 版式的选择
  29. const [imgNum, setImgNum] = useState(1);
  30. // 上传图片的校验
  31. const [imgCheck, setImgCheck] = useState(false);
  32. // 上传图片的全部数据(最多8张来进行切割)
  33. const imgListRef = useRef<ImgListType[]>([
  34. { id: 1, fileName: "xxx", filePath: "/wall/img/20230202_12193909316.jpg" },
  35. { id: 2, fileName: "xxx", filePath: "/wall/img/20230209_1519270201.gif" },
  36. { id: 3, fileName: "xxx", filePath: "/wall/img/20230202_12193909316.jpg" },
  37. { id: 4, fileName: "xxx", filePath: "/wall/img/20230209_1519270201.gif" },
  38. { id: 5, fileName: "xxx", filePath: "/wall/img/20230202_12193909316.jpg" },
  39. { id: 6, fileName: "xxx", filePath: "/wall/img/20230209_1519270201.gif" },
  40. { id: 7, fileName: "xxx", filePath: "/wall/img/20230202_12193909316.jpg" },
  41. { id: 8, fileName: "xxx", filePath: "/wall/img/20230209_1519270201.gif" },
  42. ]);
  43. // 在页面展示的图片
  44. const [imgList, setImgList] = useState<ImgListType[]>([]);
  45. // 版式的选择改变,切割数组
  46. useEffect(() => {
  47. if (imgListRef.current.length) {
  48. const newData = imgListRef.current.slice(0, imgNum);
  49. setImgList(newData);
  50. }
  51. }, [imgNum]);
  52. // ---------附件图片的拖动
  53. const [dragImg, setDragImg] = useState<any>(null);
  54. const handleDragOver = useCallback(
  55. (e: React.DragEvent<HTMLDivElement>, item: ImgListType) => {
  56. e.dataTransfer.dropEffect = "move";
  57. },
  58. []
  59. );
  60. const handleDragEnter = useCallback(
  61. (e: React.DragEvent<HTMLDivElement>, item: ImgListType) => {
  62. e.dataTransfer.effectAllowed = "move";
  63. if (item === dragImg) return;
  64. const newItems = [...imgList]; //拷贝一份数据进行交换操作。
  65. const src = newItems.indexOf(dragImg); //获取数组下标
  66. const dst = newItems.indexOf(item);
  67. newItems.splice(dst, 0, ...newItems.splice(src, 1)); //交换位置
  68. setImgList(newItems);
  69. },
  70. [dragImg, imgList]
  71. );
  72. // 删除某一张图片
  73. const delImgListFu = useCallback(
  74. (id: number) => {
  75. const newItems = imgList.filter((v) => v.id !== id);
  76. setImgList(newItems);
  77. imgListRef.current = imgListRef.current.filter((v) => v.id !== id);
  78. },
  79. [imgList]
  80. );
  81. // 没有通过校验
  82. const onFinishFailed = useCallback(() => {
  83. setImgCheck(true);
  84. }, []);
  85. // 上传封面图
  86. const handeUpPhoto = useCallback(
  87. async (e: React.ChangeEvent<HTMLInputElement>) => {
  88. if (e.target.files) {
  89. // 拿到files信息
  90. const filesInfo = e.target.files[0];
  91. // 校验格式
  92. const type = ["image/jpeg", "image/png"];
  93. if (!type.includes(filesInfo.type)) {
  94. e.target.value = "";
  95. return MessageFu.warning("只支持jpg、png格式!");
  96. }
  97. // 校验大小
  98. if (filesInfo.size > 30 * 1024 * 1024) {
  99. e.target.value = "";
  100. return MessageFu.warning("最大支持30M!");
  101. }
  102. // 创建FormData对象
  103. const fd = new FormData();
  104. // 把files添加进FormData对象(‘photo’为后端需要的字段)
  105. fd.append("type", "thumb");
  106. fd.append("file", filesInfo);
  107. e.target.value = "";
  108. // const res: any = await goodsUploadAPI(fd);
  109. // if (res.code === 0) {
  110. // MessageFu.success("上传成功!");
  111. // setCover(res.data.filePath);
  112. // }
  113. UpAsyncLodingDom.style.opacity = 0;
  114. progressDom.style.width = "0%";
  115. }
  116. },
  117. []
  118. );
  119. // 通过校验点击确定
  120. const onFinish = useCallback(() => {
  121. console.log("通过校验,点击确定");
  122. setImgCheck(true);
  123. if (imgList.length < imgNum) return;
  124. }, [imgList.length, imgNum]);
  125. // 点击预览效果
  126. const [lookImg, setLookImg] = useState(false);
  127. return (
  128. <div className={styles.WallAdd}>
  129. <div className="main">
  130. <Form
  131. ref={FormBoxRef}
  132. name="basic"
  133. labelCol={{ span: 3 }}
  134. onFinish={onFinish}
  135. onFinishFailed={onFinishFailed}
  136. autoComplete="off"
  137. >
  138. <Form.Item
  139. label="名称"
  140. name="name"
  141. rules={[{ required: true, message: "请输名称!" }]}
  142. getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
  143. >
  144. <Input maxLength={25} showCount placeholder="请输入内容" />
  145. </Form.Item>
  146. <div className="myformBox">
  147. <div className="label">
  148. <span>*</span> 版式:
  149. </div>
  150. <div className="myformBoxR">
  151. <Radio.Group
  152. onChange={(e) => setImgNum(e.target.value)}
  153. value={imgNum}
  154. >
  155. <Radio value={1}>1</Radio>
  156. <Radio value={2}>2</Radio>
  157. <Radio value={4}>4</Radio>
  158. <Radio value={6}>6</Radio>
  159. <Radio value={8}>8</Radio>
  160. </Radio.Group>
  161. </div>
  162. </div>
  163. {/* 图片上传 */}
  164. <div className="myformBox myformBox0">
  165. <input
  166. id="upInput"
  167. type="file"
  168. accept=".png,.jpg,.jpeg"
  169. ref={myInput}
  170. onChange={(e) => handeUpPhoto(e)}
  171. />
  172. <div className="label"></div>
  173. <div className="myformBoxR">
  174. <div className="fileBoxRow_r">
  175. <div className="upImgBox">
  176. <div
  177. hidden={imgList.length >= imgNum}
  178. className="fileBoxRow_up"
  179. onClick={() => myInput.current?.click()}
  180. >
  181. <PlusOutlined />
  182. </div>
  183. {imgList.map((v) => (
  184. <div
  185. className="fileBoxRow_r_img"
  186. key={v.id}
  187. draggable="true"
  188. onDragStart={() => setDragImg(v)}
  189. onDragOver={(e) => handleDragOver(e, v)}
  190. onDragEnter={(e) => handleDragEnter(e, v)}
  191. onDragEnd={() => setDragImg(null)}
  192. >
  193. {v.filePath ? (
  194. <ImageLazy
  195. noLook={dragImg ? true : false}
  196. width={100}
  197. height={100}
  198. src={v.filePath}
  199. />
  200. ) : null}
  201. <Popconfirm
  202. title="删除后无法恢复,是否删除?"
  203. okText="删除"
  204. cancelText="取消"
  205. onConfirm={() => delImgListFu(v.id!)}
  206. >
  207. <div className="clearCover">
  208. <CloseOutlined />
  209. </div>
  210. </Popconfirm>
  211. </div>
  212. ))}
  213. </div>
  214. <div className="fileTit">
  215. {imgList.length && imgList.length >= 2 ? (
  216. <>
  217. 按住鼠标可拖动图片调整顺序。
  218. <br />
  219. </>
  220. ) : null}
  221. 建议尺寸:{12960 / imgNum}*1920
  222. <br />
  223. 支持png、jpg和jpeg的图片格式;最大支持30M。
  224. </div>
  225. </div>
  226. </div>
  227. </div>
  228. {/* 校验提示 */}
  229. <div
  230. className={classNames(
  231. "noUpThumb",
  232. imgList.length < imgNum && imgCheck ? "noUpThumbAc" : ""
  233. )}
  234. >
  235. 请上传 {imgNum} 张图片!
  236. </div>
  237. {/* 确定和取消按钮 */}
  238. <br />
  239. <Form.Item wrapperCol={{ offset: 9, span: 16 }}>
  240. <Button type="primary" htmlType="submit">
  241. 提交
  242. </Button>
  243. &emsp;
  244. <Button disabled={!imgList.length} onClick={() => setLookImg(true)}>
  245. 预览效果
  246. </Button>
  247. &emsp;
  248. <Popconfirm
  249. title="放弃编辑后,信息将不会保存!"
  250. okText="放弃"
  251. cancelText="取消"
  252. onConfirm={closeMoalFu}
  253. >
  254. <Button>取消</Button>
  255. </Popconfirm>
  256. </Form.Item>
  257. </Form>
  258. </div>
  259. {/* 点击预览效果出来的页面 */}
  260. {lookImg ? (
  261. <WallLook imgList={imgList} closeMoalFu={() => setLookImg(false)} />
  262. ) : null}
  263. </div>
  264. );
  265. }
  266. const MemoWallAdd = React.memo(WallAdd);
  267. export default MemoWallAdd;