shaogen1995 2 년 전
부모
커밋
98ea6c9e30

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1645 - 27
pc/package-lock.json


+ 1 - 0
pc/package.json

@@ -10,6 +10,7 @@
     "@types/node": "^16.18.3",
     "@types/react": "^18.0.24",
     "@types/react-dom": "^18.0.8",
+    "antd": "^5.4.2",
     "axios": "^1.1.3",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",

BIN
pc/public/favicon.ico


+ 1 - 1
pc/public/index.html

@@ -24,7 +24,7 @@
       work correctly both with client-side routing and a non-root public URL.
       Learn how to configure a non-root public URL by running `npm run build`.
     -->
-    <title>React App</title>
+    <title>鸦片战争博物馆</title>
   </head>
   <body>
     <noscript>You need to enable JavaScript to run this app.</noscript>

+ 10 - 72
pc/src/App.tsx

@@ -1,94 +1,32 @@
-// 导入初始化样式
 import "@/assets/styles/base.css";
 
-// 导入 修改仓库的 dispatch,和获取仓库数据的 useSelector
-import { useDispatch, useSelector } from "react-redux";
-
-// 导入自己定义的 RootState 声明类型
-import { RootState } from "./store";
-
-// 导入自己定义的异步addNunAction
-import { addNunAction } from "./store/action/login";
-
-// 关于路由
 import React from "react";
-import { Router, Route, Switch, Redirect } from "react-router-dom";
+import SpinLoding from "./components/SpinLoding";
+import AsyncSpinLoding from "./components/AsyncSpinLoding";
+import { Router, Route, Switch } from "react-router-dom";
 
-// 导入自己封装的 history
 import history from "./utils/history";
 
-// 导入自己封装的 鉴权路由
-import AuthRoute from "./components/AuthRoute";
-
 // 使用 React.lazy 懒加载页面
-const Layout = React.lazy(() => import("./pages/Layout"));
-const Login = React.lazy(() => import("./pages/Login"));
-const Home = React.lazy(() => import("./pages/Home"));
+const A1Home = React.lazy(() => import("./pages/A1Home"));
 
 function App() {
-  const dispatch = useDispatch(); 
   return (
-    <div>
-      <h1>App总组件</h1>
-      {/* 点击这个按钮 控制  dispatch 来异步 修改仓库的 num 变量*/}
-      <button onClick={() => dispatch(addNunAction())}>点击+1</button>
-      <br />
-      <div onClick={() => history.push("/Login")}>去登录页</div>
-      <br />
-      <div onClick={() => history.push("/Layout")}>去Layout页面</div>
-      <br />
-      <div onClick={() => history.push("/Home")}>去Home页面</div>
-      <hr />
-      <Son1 />
-      <hr />
-      <Son2 />
-
+    <>
       {/* 关于路由 */}
-      {/* 这里需要把自己封装的 history 给第一级总路由器,不然项目中的路由信息会链接不上*/}
       <Router history={history}>
-        {/* 使用了 React.lazy 需要定义一个加载中组件,这里我简单写一个。后面根据需求自己修改更好看的 加载中 组件*/}
-        <React.Suspense fallback={<div>加载中...</div>}>
-          {/* 使用 Switch 包裹路由,匹配到一个之后就不会往下匹配 */}
+        <React.Suspense fallback={<SpinLoding />}>
           <Switch>
-            {/* 使用路由重定向,回到登录页 */}
-            <Redirect exact path="/" to="Login" />
-            {/* 普通路由,没有鉴权功能 */}
-            <Route path="/Login" component={Login} />
-            {/* 普通路由,没有鉴权功能 */}
-            <Route path="/Layout" component={Layout} />
-            {/* 鉴权路由,没有token,访问改路由,会重定向到 登录页面 */}
-            <AuthRoute path="/Home" component={Home} />
-            {/* 当所有路由匹配不到的时候显示 自己定义的 404 页面,这里我暂时没有定义 */}
-            {/* <Route path='*' component={NotFound} /> */}
+            <Route path="/" component={A1Home} />
           </Switch>
         </React.Suspense>
       </Router>
-    </div>
-  );
-}
 
-const Son1 = function Son1() {
-  // 从仓库中获取响应式数据 num
-  const { num } = useSelector((state: RootState) => state.loginStore);
-  return (
-    <>
-      <h2>子组件1</h2>
-      <p>存在仓库的数字:{num}</p>
-    </>
-  );
-};
-
-const Son2 = function Son2() {
-  // 从仓库中获取响应式数据 num
-  const { num } = useSelector((state: RootState) => state.loginStore);
-
-  return (
-    <>
-      <h2>子组件2</h2>
-      <p>存在仓库的数字:{num}</p>
+      {/* 发送请求的加载组件 */}
+      <AsyncSpinLoding />
     </>
   );
-};
+}
 
 const MemoApp = React.memo(App);
 

+ 1 - 1
pc/src/assets/styles/base.css

@@ -39,7 +39,7 @@ textarea {
 }
 /* 主题色 */
 :root {
-  --themeColor: #9F1927;
+  --themeColor: #c8b992;
 }
 a {
   color: var(--themeColor);

+ 1 - 1
pc/src/assets/styles/base.less

@@ -48,7 +48,7 @@ textarea {
 
 /* 主题色 */
 :root {
-  --themeColor: #9F1927;
+  --themeColor: #c8b992;
 }
 
 a {

+ 21 - 0
pc/src/components/AsyncSpinLoding/index.module.scss

@@ -0,0 +1,21 @@
+.AsyncSpinLoding {
+  opacity: 0;
+  pointer-events: none;
+  transition: all .5s;
+  position: fixed;
+  z-index: 9998;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  // background-color: rgba(0, 0, 0, .6);
+  background-color: transparent;
+  :global{
+    .ant-spin-spinning{
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%,-50%);
+    }
+  }
+}

+ 15 - 0
pc/src/components/AsyncSpinLoding/index.tsx

@@ -0,0 +1,15 @@
+import styles from "./index.module.scss";
+import { Spin } from "antd";
+import React from "react";
+
+function AsyncSpinLoding() {
+  return (
+    <div id="AsyncSpinLoding" className={styles.AsyncSpinLoding}>
+      <Spin size="large" />
+    </div>
+  );
+}
+
+const MemoAsyncSpinLoding = React.memo(AsyncSpinLoding);
+
+export default MemoAsyncSpinLoding;

+ 0 - 48
pc/src/components/AuthRoute/index.tsx

@@ -1,48 +0,0 @@
-//自己封装的 history 路由跳转,在tsx和ts中都能使用。使用 react-router-dom 里面的 useHistory Hooks 只能在tsx函数组件中使用,不能在ts文件中使用,不太方便,所以这里自己封装。
-import history from "@/utils/history";
-
-// 自己封装的获取token的函数
-import { hasToken } from "@//utils/storage";
-
-import React from "react";
-
-import { Redirect, Route } from "react-router-dom";
-
-type AtahType = {
-  path: string; //传入的路由路径,必传
-  component: React.FC; //引入react中以及封装好的 组件 的类型声明,必传
-};
-
-function AuthRoute({ path, component: Com }: AtahType) {
-  return (
-    //引入 react-router-dom 中的 Route 组件
-    <Route
-      // 路由路径
-      path={path}
-      render={() => {
-        // 需要token的页面使用本组件,检查到有token,就正常访问
-        if (hasToken()) return <Com />;
-        else {
-          // 没有token,提示一下。这里随便写的alret,可自行修改其他方式提示(比如antd的轻提示)
-          alert("登录失效");
-          return (
-            // 路由重定向到 登录页面
-            <Redirect
-              to={{
-                pathname: "/Login",
-                // 附带 回跳 信息,有些业务需求 登录之后回到 上一个页面的时候可以使用(比如:在个人详情页,由于某些原因token失效,或者本地删除了token,那就会回到登录页,登录成功之后会回跳到 个人详情 页)
-                state: { from: history.location.pathname },
-              }}
-            />
-          );
-        }
-      }}
-    />
-  );
-}
-
-// 使用 React.memo 来优化组件,避免组件的无效更新,类似 类组件里面的PureComponent
-const MemoAuthRoute = React.memo(AuthRoute);
-
-// 默认导出
-export default MemoAuthRoute;

+ 10 - 0
pc/src/components/SpinLoding/index.module.scss

@@ -0,0 +1,10 @@
+.SpinLoding {
+  position: relative;
+  z-index: 9999;
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}

+ 13 - 0
pc/src/components/SpinLoding/index.tsx

@@ -0,0 +1,13 @@
+import styles from "./index.module.scss";
+import { Spin } from "antd";
+import React from "react";
+function SpinLoding() {
+  return (
+    <div className={styles.SpinLoding}>
+      <Spin size='large'/>
+    </div>
+  );
+}
+const MemoSpinLoding = React.memo(SpinLoding);
+
+export default MemoSpinLoding;

+ 5 - 0
pc/src/pages/A1Home/index.module.scss

@@ -0,0 +1,5 @@
+.A1Home{
+  :global{
+    
+  }
+}

+ 14 - 0
pc/src/pages/A1Home/index.tsx

@@ -0,0 +1,14 @@
+import React from "react";
+import styles from "./index.module.scss";
+ function A1Home() {
+  
+  return (
+    <div className={styles.A1Home}>
+      <h1>A1Home</h1>
+    </div>
+  )
+}
+
+const MemoA1Home = React.memo(A1Home);
+
+export default MemoA1Home;

+ 0 - 11
pc/src/pages/Home/index.tsx

@@ -1,11 +0,0 @@
-import React from "react";
-
-function Home() {
-  return <div>Home</div>;
-}
-
-// 使用 React.memo 来优化组件,避免组件的无效更新,类似 类组件里面的PureComponent
-const MemoHome = React.memo(Home);
-
-// 默认导出
-export default MemoHome;

+ 0 - 15
pc/src/pages/Layout/index.tsx

@@ -1,15 +0,0 @@
-import React from "react";
-
-function Layout() {
-  return (
-    <div>
-      <h1>Layout页面</h1>
-    </div>
-  );
-}
-
-// 使用 React.memo 来优化组件,避免组件的无效更新,类似 类组件里面的PureComponent
-const MemoLayout = React.memo(Layout);
-
-// 默认导出
-export default MemoLayout;

+ 0 - 13
pc/src/pages/Login/index.module.scss

@@ -1,13 +0,0 @@
-.Login {
-  width: 500px;
-  height: 500px;
-  background-color: red;
-
-  // 使用 global 来声明 除了第一个盒子 会模块化自动随机生成 calss类名,global里面的类名和元素不会变更。这样在控制台调试样式的时候不会混乱
-  :global {
-    h1 {
-      background-color: aquamarine;
-      font-size: 40px;
-    }
-  }
-}

+ 0 - 23
pc/src/pages/Login/index.tsx

@@ -1,23 +0,0 @@
-import React from "react";
-
-// 自己封装的 axios 初始基地址,会根据开发环境或者打包环境来自动改变
-import { baseURL } from "@/utils/http";
-
-// 导入模块化的css
-import styles from "./index.module.scss";
-
-function Login() {
-  return (
-    // 定义模块化css类名
-    <div className={styles.Login}>
-      <h1>登录页</h1>
-      <h2>全局变量:{baseURL}</h2>
-    </div>
-  );
-}
-
-// 使用 React.memo 来优化组件,避免组件的无效更新,类似 类组件里面的PureComponent
-const MemoLogin = React.memo(Login);
-
-// 默认导出
-export default MemoLogin;

+ 5 - 0
pc/src/pages/初始化组件/index.module.scss

@@ -0,0 +1,5 @@
+.AAAAA{
+  :global{
+    
+  }
+}

+ 14 - 0
pc/src/pages/初始化组件/index.tsx

@@ -0,0 +1,14 @@
+import React from "react";
+import styles from "./index.module.scss";
+ function AAAAA() {
+  
+  return (
+    <div className={styles.AAAAA}>
+      <h1>AAAAA</h1>
+    </div>
+  )
+}
+
+const MemoAAAAA = React.memo(AAAAA);
+
+export default MemoAAAAA;

+ 0 - 21
pc/src/store/action/login.ts

@@ -1,21 +0,0 @@
-// 导入总仓库和自己声明的 AppDispatch
-import store, { AppDispatch } from ".."
-// import http from "@/utils/http"
-
-export const addNunAction = () => {
-
-  // 返回一个函数,用来处理异步操作
-  return async (dispatch: AppDispatch) => {
-    // 可以异步发送请求,这里我简单模拟一个异步操作
-    // const res = await http.get(``)
-    // console.log('----', res);
-    window.setTimeout(() => {
-      // 从仓库中获取之前的 num 值
-      const { num } = store.getState().loginStore
-      // 设置新的 num +1
-      dispatch({ type: 'login/addNum', payload: num + 1 })
-    }, 100);
-  }
-}
-
-

+ 5 - 5
pc/src/store/reducer/index.ts

@@ -1,13 +1,13 @@
 // 导入合并reducer的依赖
-import { combineReducers } from 'redux'
+import { combineReducers } from "redux";
 
 // 导入 登录 模块的 reducer
-import loginReducer from './login'
+import A0layout from "./layout";
 
 // 合并 reducer
 const rootReducer = combineReducers({
-  loginStore: loginReducer,
-})
+  A0layout,
+});
 
 // 默认导出
-export default rootReducer
+export default rootReducer;

+ 24 - 0
pc/src/store/reducer/layout.ts

@@ -0,0 +1,24 @@
+import { MessageType } from "@/utils/message";
+
+// 初始化状态
+const initState = {
+  // antd轻提示(兼容360浏览器)
+  message: {
+    txt: "",
+    type: "info",
+    duration: 3,
+  } as MessageType,
+};
+
+// 定义 action 类型
+type Props = { type: "layout/message"; payload: MessageType };
+
+// 频道 reducer
+export default function loginReducer(state = initState, action: Props) {
+  switch (action.type) {
+    case "layout/message":
+      return { ...state, message: action.payload };
+    default:
+      return state;
+  }
+}

+ 0 - 22
pc/src/store/reducer/login.ts

@@ -1,22 +0,0 @@
-// 导入自己封装的 关于 LoginReducer 的ts声明文件
-import { LoginType } from "@/types"
-
-// 初始化状态
-const initState: LoginType = {
-  num: 0,
-  active: 0,
-}
-
-// 定义 action 类型
-type LoginActionType =
-  { type: 'login/addNum', payload: number }
-
-// 频道 reducer
-export default function loginReducer(state = initState, action: LoginActionType) {
-  switch (action.type) {
-    case 'login/addNum':
-      return { ...state, num: action.payload }
-    default:
-      return state
-  }
-}

+ 5 - 2
pc/src/types/declaration.d.ts

@@ -1,2 +1,5 @@
-declare module 'history'
-declare module '*.scss';
+declare module "history";
+declare module "*.scss";
+declare module "*.png";
+declare module "*.jpg";
+declare module "*.gif";

+ 0 - 1
pc/src/types/index.d.ts

@@ -1,2 +1 @@
-export * from './store/login'
 

+ 0 - 4
pc/src/types/store/login.d.ts

@@ -1,4 +0,0 @@
-export type LoginType = {
-  num: number;
-  active: number;
-}

+ 11 - 0
pc/src/utils/domShow.ts

@@ -0,0 +1,11 @@
+// 加载和上传的盒子的显示隐藏
+export const domShowFu = (ele: string, val: boolean) => {
+  const dom: HTMLDivElement = document.querySelector(ele)!;
+  if (val) {
+    dom.style.opacity = "1";
+    dom.style.pointerEvents = "auto";
+  } else {
+    dom.style.opacity = "0";
+    dom.style.pointerEvents = "none";
+  }
+};

+ 15 - 1
pc/src/utils/history.ts

@@ -3,4 +3,18 @@
 // 根据公司要求自己选择,createBrowserHistory在项目上线的时候需要服务器映射等处理。
 import { createHashHistory  } from 'history'
 const history = createHashHistory()
-export default history
+export default history
+
+export const urlParameter = (data: string) => {
+  if (data) {
+    const query = data.substring(data.indexOf("?") + 1);
+    const arr = query.split("&");
+    const params = {} as any;
+    arr.forEach((v) => {
+      const key = v.substring(0, v.indexOf("="));
+      const val = v.substring(v.indexOf("=") + 1);
+      params[key] = val;
+    });
+    return params;
+  } else return {};
+};

+ 39 - 51
pc/src/utils/http.ts

@@ -1,32 +1,41 @@
-// 导入 axios
 import axios from "axios";
-// 导入自己封装的 history 用来跳转。useHistory 在单纯的ts文件里面无法使用
-import history from "./history";
-// 导入自己封装的获取token信息的函数,和删除本地存储token信息的函数
-import { getTokenInfo, removeTokenInfo } from "./storage";
-// 请求基地址,根据开发环境和打包环境来自己设置。一般打包环境都为空
-export const baseURL = process.env.NODE_ENV === "development" ? "开发环境" : "";
+import { MessageFu } from "./message";
+import { domShowFu } from "./domShow";
+// 请求基地址
+export const baseURL =
+  // 线下的图片地址需要加上/api/
+  process.env.NODE_ENV === "development"
+    ? "http://192.168.20.55:8041/api/"
+    : "";
+// process.env.NODE_ENV === "development" ? "https://xuzhouwall.4dage.com" : "";
+
+// 处理  类型“AxiosResponse<any, any>”上不存在属性“code”
+declare module "axios" {
+  interface AxiosResponse {
+    code: number;
+    // 这里追加你的参数
+  }
+}
 
 // 创建 axios 实例
 const http = axios.create({
-  baseURL,
-  // 请求超过5m没有回来即停止请求,并且抛出异常
+  // --------线下的地址不用加/api/
+  baseURL: baseURL,
+
+  // --------打包或线上环境接口需要加上api/
+  // baseURL: baseURL + "/api/",
   timeout: 5000,
 });
 
-// 设置一个请求状态开关,判断 请求正在发送 和 所有请求都发送完毕
 let axajInd = 0;
 
 // 请求拦截器
 http.interceptors.request.use(
   function (config: any) {
-    // 开关数量+1,表示现在有一个请求在发送。
-    axajInd++;
-    //可以在这里添加业务代码,比如:显示 loding状态
+    // 发请求前打开加载提示
+    domShowFu("#AsyncSpinLoding", true);
 
-    // 检查到有token,为所有请求添加请求体。Bearer字段为 我这边后端的需求,各位看自己 后端需求来修改
-    const { token } = getTokenInfo();
-    if (token) config.headers.Authorization = `Bearer ${token}`;
+    axajInd++;
     return config;
   },
   function (err) {
@@ -34,53 +43,32 @@ http.interceptors.request.use(
   }
 );
 
-// 设置一个定时器id,防止多个请求同时发送,并且token失效的情况,多次执行 业务 代码
 let timeId = -1;
 
 // 响应拦截器
 http.interceptors.response.use(
   function (response) {
-    // 一个请求发送完毕
+    // 请求回来的关闭加载提示
     axajInd--;
     if (axajInd === 0) {
-      // 所有请求发送完毕,可以在这里添加业务代码,比如:隐藏 loding状态
+      domShowFu("#AsyncSpinLoding", false);
     }
-
-    // token过期,这里看后台的返回值设置的为多少
-    if (response.data.code === 401) {
-      // 先清理定时器,在执行。防止多次执行。即页面防抖原理
-      clearTimeout(timeId);
-
-      timeId = window.setTimeout(() => {
-        // 删除本地token信息
-        removeTokenInfo();
-        // 这里的提示统一简单用的alert,自己根据需求更改。比如:antd的message
-        alert("登录失效!");
-        // 回到登录页面
-        history.push("/Login");
-      }, 200);
-    } else if (response.data.code === 0) {
-      // 请求成功,状态也成功(根据后端定义的状态值自己修改)
-      // 这里暂时不做处理,我一般会根据具体需求在组件中自己定义 message
-    } else {
-      //这里一般是请求成功,但是状态码有问题,直接返回后端的提示信息。这里的msg是我这边后端的字段,自己根据后端字段来修改
-      alert(response.data.msg);
-     }
+    if (response.data.code === 0) {
+      // MessageFu.success(response.data.msg);
+    } else MessageFu.warning(response.data.msg);
 
     return response.data;
   },
   async function (err) {
-    // 请求错误的时候,直接把 axajInd 归零,防止页面一直处于 loding 状态
-    axajInd = 0;
-    // 如果在上面定义了发送请求前显示 loding状态,这里需要隐藏 loding
-
-    // 如果因为网络原因,response没有,给提示消息
-    if (!err.response) {
-      alert("网络繁忙,请稍后重试");
-    } else {
-      // 网络没问题,后台返回了有数据
-      alert("错误");
-    }
+    clearTimeout(timeId);
+    timeId = window.setTimeout(() => {
+      axajInd = 0;
+      domShowFu("#AsyncSpinLoding", false);
+      // 如果因为网络原因,response没有,给提示消息
+      if (!err.response) {
+        MessageFu.error("网络繁忙,请稍后重试!");
+      } else MessageFu.error("响应错误,请联系管理员!");
+    }, 100);
 
     return Promise.reject(err);
   }

+ 50 - 0
pc/src/utils/message.ts

@@ -0,0 +1,50 @@
+import store from "@/store";
+
+export type MessageType = {
+  txt: string;
+  type: "info" | "success" | "error" | "warning";
+  duration: number;
+};
+
+export const MessageFu = {
+  info: (txt: string, duration?: number) => {
+    store.dispatch({
+      type: "layout/message",
+      payload: {
+        txt,
+        type: "info",
+        duration: duration === undefined ? 3 : duration,
+      },
+    });
+  },
+  success: (txt: string, duration?: number) => {
+    store.dispatch({
+      type: "layout/message",
+      payload: {
+        txt,
+        type: "success",
+        duration: duration === undefined ? 3 : duration,
+      },
+    });
+  },
+  error: (txt: string, duration?: number) => {
+    store.dispatch({
+      type: "layout/message",
+      payload: {
+        txt,
+        type: "error",
+        duration: duration === undefined ? 3 : duration,
+      },
+    });
+  },
+  warning: (txt: string, duration?: number) => {
+    store.dispatch({
+      type: "layout/message",
+      payload: {
+        txt,
+        type: "warning",
+        duration: duration === undefined ? 3 : duration,
+      },
+    });
+  },
+};

+ 0 - 34
pc/src/utils/storage.ts

@@ -1,34 +0,0 @@
-// ------------------------------------token的本地存储------------------------------------
-
-// 用户 Token 的本地缓存键名,自己定义
-const TOKEN_KEY = 'XXXXX'
-
-/**
- * 从本地缓存中获取 Token 信息
- */
-export const getTokenInfo = (): any => {
-  return JSON.parse(localStorage.getItem(TOKEN_KEY) || '{}')
-}
-
-/**
- * 将 Token 信息存入缓存
- * @param {Object} tokenInfo 从后端获取到的 Token 信息
- */
-export const setTokenInfo = (tokenInfo: any): void => {
-  localStorage.setItem(TOKEN_KEY, JSON.stringify(tokenInfo))
-}
-
-/**
- * 删除本地缓存中的 Token 信息
- */
-export const removeTokenInfo = (): void => {
-  localStorage.removeItem(TOKEN_KEY)
-}
-
-/**
- * 判断本地缓存中是否存在 Token 信息
- */
-export const hasToken = (): boolean => {
-  return Boolean(getTokenInfo().token)
-}
-