Browse Source

✨附件上传增加进度条提示/上传文件类型判断

shaogen1995 2 years ago
parent
commit
c52113ae7a

+ 4 - 0
src/App.tsx

@@ -9,6 +9,7 @@ import AsyncSpinLoding from "./components/AsyncSpinLoding";
 import { Image } from "antd";
 import { useDispatch, useSelector } from "react-redux";
 import { RootState } from "./store";
+import UpAsyncLoding from "./components/UpAsyncLoding";
 const Layout = React.lazy(() => import("./pages/Layout"));
 const Login = React.lazy(() => import("./pages/Login"));
 
@@ -49,6 +50,9 @@ export default function App() {
           },
         }}
       />
+
+      {/* 上传附件的进度条元素 */}
+      <UpAsyncLoding />
     </>
   );
 }

+ 5 - 0
src/components/AsyncSpinLoding/index.module.scss

@@ -18,4 +18,9 @@
       transform: translate(-50%,-50%);
     }
   }
+}
+
+.AsyncSpinLodingShow {
+  opacity: 1;
+  pointer-events: auto;
 }

+ 16 - 1
src/components/AsyncSpinLoding/index.tsx

@@ -1,9 +1,24 @@
 import styles from "./index.module.scss";
 import { Spin } from "antd";
 import React from "react";
+import classNames from "classnames";
+import { useSelector } from "react-redux";
+import { RootState } from "@/store";
+
 function AsyncSpinLoding() {
+  // 从仓库中获取查看图片的信息
+  const asyncLoding = useSelector(
+    (state: RootState) => state.loginStore.asyncLoding
+  );
+
   return (
-    <div id="AsyncSpinLoding" className={styles.AsyncSpinLoding}>
+    <div
+      id="AsyncSpinLoding"
+      className={classNames(
+        styles.AsyncSpinLoding,
+        asyncLoding ? styles.AsyncSpinLodingShow : ""
+      )}
+    >
       <Spin size="large" />
     </div>
   );

+ 1 - 1
src/components/AuthButton/index.tsx

@@ -8,7 +8,7 @@ type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
 
 // 过滤接口 ButtonProps 里面的字段id,使用自己定义的 id
 interface Props extends Omit<ButtonProps, "id"> {
-  children?: ReactNode;
+  children: ReactNode;
   id: number;
   [x: string]: any;
 }

+ 6 - 0
src/components/ObjectAdd/index.css

@@ -101,6 +101,12 @@
 .ObjectAdd .fileBox .fileBoxRow .fileBoxRow_tit2 {
   line-height: 30px;
 }
+.ObjectAdd .fileBox .fileBoxRow .fileBoxRowUpTit {
+  height: 32px;
+  line-height: 32px;
+  font-size: 14px;
+  color: #7e7c7c;
+}
 .ObjectAdd .fileBox .fileBoxRow .fileBoxRow_r {
   padding-left: 20px;
   position: relative;

+ 9 - 1
src/components/ObjectAdd/index.less

@@ -136,10 +136,18 @@
         width: 119px;
         text-align: right;
       }
-      .fileBoxRow_tit2{
+
+      .fileBoxRow_tit2 {
         line-height: 30px;
       }
 
+      .fileBoxRowUpTit {
+        height: 32px;
+        line-height: 32px;
+        font-size: 14px;
+        color: #7e7c7c;
+      }
+
       .fileBoxRow_r {
         padding-left: 20px;
         position: relative;

+ 58 - 2
src/components/ObjectAdd/index.tsx

@@ -375,6 +375,10 @@ function ObjectAdd({ id, colsePage, editId, dirCode, upInfoAPIFu }: Props) {
     ];
   }, []);
 
+  // 上传附件的进度条
+  const UpAsyncLodingDom: any = document.querySelector("#UpAsyncLoding");
+  const progressDom: any = document.querySelector("#progress");
+
   // 上传封面
   const myInput = useRef<HTMLInputElement>(null);
   const handeUpPhoto = async (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -398,11 +402,16 @@ function ObjectAdd({ id, colsePage, editId, dirCode, upInfoAPIFu }: Props) {
       fd.append("type", "thumb");
       fd.append("dirCode", dirCode);
       fd.append("file", filesInfo);
+
+      e.target.value = "";
+
       const res: any = await object1AddUpFileAPI(fd);
       if (res.code === 0) {
         message.success("上传成功!");
         setCover(res.data.filePath);
       }
+      UpAsyncLodingDom.style.opacity = 0;
+      progressDom.style.width = "0%";
     }
   };
 
@@ -423,15 +432,41 @@ function ObjectAdd({ id, colsePage, editId, dirCode, upInfoAPIFu }: Props) {
         // 拿到files信息
         const filesInfo = e.target.files[0];
 
+        let type = [] as string[];
+
+        let tit = "";
+
+        if (
+          fileSelect === "img" ||
+          fileSelect === "video" ||
+          fileSelect === "audio"
+        ) {
+          if (fileSelect === "img") {
+            type = ["image/jpeg", "image/png", "image/gif"];
+            tit = "只支持jpg、png、gif格式!";
+          } else if (fileSelect === "video") {
+            type = ["video/mp4"];
+            tit = "只支持mp4格式!";
+          } else if (fileSelect === "audio") {
+            type = ["audio/mpeg"];
+            tit = "只支持mp3格式!";
+          }
+          // 校验格式
+          if (!type.includes(filesInfo.type)) {
+            e.target.value = "";
+            return message.warning(tit);
+          }
+        }
+
         // 创建FormData对象
         const fd = new FormData();
         // 把files添加进FormData对象(‘photo’为后端需要的字段)
         fd.append("type", fileSelect);
         fd.append("dirCode", dirCode);
         fd.append("file", filesInfo);
+        e.target.value = "";
 
         const res: any = await object1AddUpFileAPI(fd);
-        e.target.value = "";
         if (res.code === 0) {
           message.success("上传成功!");
           if (upFileFlagRef.current) {
@@ -466,9 +501,18 @@ function ObjectAdd({ id, colsePage, editId, dirCode, upInfoAPIFu }: Props) {
             dispatch({ type: "login/setFileData", payload: data });
           }
         }
+        UpAsyncLodingDom.style.opacity = 0;
+        progressDom.style.width = "0%";
       }
     },
-    [dirCode, dispatch, fileSelect, results]
+    [
+      UpAsyncLodingDom.style,
+      dirCode,
+      dispatch,
+      fileSelect,
+      progressDom.style,
+      results,
+    ]
   );
 
   return (
@@ -815,6 +859,18 @@ function ObjectAdd({ id, colsePage, editId, dirCode, upInfoAPIFu }: Props) {
                   &emsp;
                   <Button onClick={() => upFileFu()}>上传附件</Button>
                 </div>
+                &emsp;
+                <div className="fileBoxRowUpTit">
+                  {fileSelect === "img" ? (
+                    <>支持上传jpg,png,gif格式</>
+                  ) : fileSelect === "video" ? (
+                    <>支持上传mp4格式</>
+                  ) : fileSelect === "audio" ? (
+                    <>支持上传mp3格式</>
+                  ) : (
+                    ""
+                  )}
+                </div>
               </div>
               {/* 表格主体 */}
               <div className="addTableBox_table">

+ 36 - 0
src/components/UpAsyncLoding/index.module.scss

@@ -0,0 +1,36 @@
+.UpAsyncLoding {
+  opacity: 0;
+  pointer-events: none;
+  position: fixed;
+  z-index: 9997;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0, 0, 0, .4);
+
+  :global {
+    .progressBox {
+      position: absolute;
+      top: 60%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      width: 500px;
+      height: 6px;
+      border-radius: 3px;
+      border: 1px solid var(--themeColor);
+      overflow: hidden;
+
+      #progress {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 0%;
+        height: 100%;
+        background-color: var(--themeColor);
+      }
+
+    }
+
+  }
+}

+ 15 - 0
src/components/UpAsyncLoding/index.tsx

@@ -0,0 +1,15 @@
+import React from "react";
+import styles from "./index.module.scss";
+function UpAsyncLoding() {
+  return (
+    <div id="UpAsyncLoding" className={styles.UpAsyncLoding}>
+      <div className="progressBox">
+        <div id="progress"></div>
+      </div>
+    </div>
+  );
+}
+
+const MemoUpAsyncLoding = React.memo(UpAsyncLoding);
+
+export default MemoUpAsyncLoding;

+ 1 - 1
src/pages/SystemSon/System1/index.tsx

@@ -137,7 +137,7 @@ function System1() {
         render: (item: any) => (
           <>
             {item.isAdmin === 1 ? (
-              "-"
+              <span>&emsp;-</span>
             ) : (
               <>
                 <Button type="text" danger onClick={() => addSystem(item.id)}>

+ 14 - 2
src/store/action/object1.ts

@@ -13,8 +13,21 @@ export const object1AddAPI = (data?: any) => {
 /**
  * 藏品登记页面上传封面图和附件
  */
+
+// 上传附件的进度条
+const UpAsyncLodingDom: any = document.querySelector("#UpAsyncLoding");
+const progressDom: any = document.querySelector("#progress");
+
 export const object1AddUpFileAPI = (data: any) => {
-  return http.post("cms/register/goods/file/upload", data);
+  UpAsyncLodingDom.style.opacity = 1;
+
+  return http.post("cms/register/goods/file/upload", data, {
+    // 显示进度条
+    onUploadProgress: (e: any) => {
+      const complete = ((e.loaded / e.total) * 100) | 0;
+      progressDom.style.width = complete + "%";
+    },
+  });
 };
 
 /**
@@ -40,7 +53,6 @@ export const goodsSonAddAPI = (data: any, id: any) => {
   };
 };
 
-
 /**
  * 获取藏品登记列表信息
  */

+ 9 - 3
src/store/reducer/login.ts

@@ -29,9 +29,11 @@ const initState = {
   authPageArr: [],
   // 所有图片点击预览查看大图
   lookBigImg: {
-    url:'',
-    show:false
+    url: "",
+    show: false,
   },
+  // 加载请求的loding
+  asyncLoding: false,
 };
 
 type LoginActionType =
@@ -40,7 +42,8 @@ type LoginActionType =
   | { type: "login/setGoodsSonList"; payload: any }
   | { type: "login/setAuthButtonArr"; payload: any }
   | { type: "login/setAuthPageArr"; payload: any }
-  | { type: "login/lookBigImg"; payload: any };
+  | { type: "login/lookBigImg"; payload: any }
+  | { type: "login/asyncLoding"; payload: any };
 // 频道 reducer
 export default function loginReducer(
   state = initState,
@@ -65,6 +68,9 @@ export default function loginReducer(
     // 所有图片点击预览查看大图
     case "login/lookBigImg":
       return { ...state, lookBigImg: action.payload };
+    // 加载请求的loding
+    case "login/asyncLoding":
+      return { ...state, asyncLoding: action.payload };
     default:
       return state;
   }

+ 15 - 12
src/utils/http.ts

@@ -2,6 +2,7 @@ import axios from "axios";
 import history from "./history";
 import { getTokenInfo, removeTokenInfo } from "./storage";
 import { message } from "antd";
+import store from "@/store";
 // 请求基地址
 export const baseURL =
   // 线下的图片地址需要加上/api/
@@ -17,18 +18,17 @@ const http = axios.create({
 
   // --------打包或线上环境接口需要加上api/
   baseURL: baseURL + "/api/",
-  timeout: 5000,
+  timeout: 20000,
 });
 
 let axajInd = 0;
-const lodingDom: any = document.querySelector("#AsyncSpinLoding");
 
 // 请求拦截器
 http.interceptors.request.use(
   function (config: any) {
     // 发请求前打开加载提示
-    lodingDom.style.opacity = 1;
-    lodingDom.style.pointerEvents = "auto";
+    store.dispatch({ type: "login/asyncLoding", payload: true });
+
     axajInd++;
 
     const { token } = getTokenInfo();
@@ -42,16 +42,17 @@ http.interceptors.request.use(
 
 let timeId = -1;
 
+// 上传附件的进度条
+const UpAsyncLodingDom: any = document.querySelector("#UpAsyncLoding");
+const progressDom: any = document.querySelector("#progress");
+
 // 响应拦截器
 http.interceptors.response.use(
   function (response) {
     // 请求回来的关闭加载提示
     axajInd--;
     if (axajInd === 0) {
-      // setTimeout(() => {
-      lodingDom.style.opacity = 0;
-      lodingDom.style.pointerEvents = "none";
-      // }, 100);
+      store.dispatch({ type: "login/asyncLoding", payload: false });
     }
     if (response.data.code === 5001 || response.data.code === 5002) {
       clearTimeout(timeId);
@@ -67,10 +68,12 @@ http.interceptors.response.use(
   },
   async function (err) {
     axajInd = 0;
-    // setTimeout(() => {
-    lodingDom.style.opacity = 0;
-    lodingDom.style.pointerEvents = "none";
-    // }, 300);
+    store.dispatch({ type: "login/asyncLoding", payload: false });
+
+    // 响应错误也要取消 上传文件的进度条
+    UpAsyncLodingDom.style.opacity = 0;
+    progressDom.style.width = "0%";
+
     // 如果因为网络原因,response没有,给提示消息
     if (!err.response) {
       message.warning("网络繁忙,请稍后重试!");