shaogen1995 10 місяців тому
батько
коміт
9fa02a08af
43 змінених файлів з 42088 додано та 0 видалено
  1. 12 0
      web/.editorconfig
  2. 23 0
      web/.gitignore
  3. 2 0
      web/.npmrc
  4. 11 0
      web/.prettierrc.js
  5. 39 0
      web/.vscode/settings.json
  6. 27 0
      web/README.md
  7. 10 0
      web/config-overrides.js
  8. 30270 0
      web/package-lock.json
  9. 64 0
      web/package.json
  10. 8 0
      web/path.tsconfig.json
  11. BIN
      web/public/favicon.ico
  12. 44 0
      web/public/index.html
  13. 12 0
      web/public/myData/myData.js
  14. 14 0
      web/src/App.tsx
  15. 44 0
      web/src/AppM.tsx
  16. BIN
      web/src/assets/img/IMGerror.png
  17. BIN
      web/src/assets/img/landtip.png
  18. BIN
      web/src/assets/img/loading.gif
  19. 143 0
      web/src/assets/styles/base.css
  20. 175 0
      web/src/assets/styles/base.less
  21. 27 0
      web/src/components/Message/index.tsx
  22. 30 0
      web/src/components/NotFound/index.tsx
  23. 92 0
      web/src/components/RouterOrder.tsx
  24. 10 0
      web/src/components/SpinLoding/index.module.scss
  25. 13 0
      web/src/components/SpinLoding/index.tsx
  26. 37 0
      web/src/index.tsx
  27. 5 0
      web/src/pages/A1home/index.module.scss
  28. 14 0
      web/src/pages/A1home/index.tsx
  29. 5 0
      web/src/pages/A1homeM/index.module.scss
  30. 14 0
      web/src/pages/A1homeM/index.tsx
  31. 5 0
      web/src/pages/初始化组件/index.module.scss
  32. 14 0
      web/src/pages/初始化组件/index.tsx
  33. 20 0
      web/src/store/index.ts
  34. 14 0
      web/src/store/reducer/index.ts
  35. 25 0
      web/src/store/reducer/layout.ts
  36. 1 0
      web/src/types/api/layot.d.ts
  37. 13 0
      web/src/types/declaration.d.ts
  38. 2 0
      web/src/types/index.d.ts
  39. 22 0
      web/src/utils/history.ts
  40. 50 0
      web/src/utils/message.ts
  41. 16 0
      web/src/utils/storage.ts
  42. 27 0
      web/tsconfig.json
  43. 10734 0
      web/yarn.lock

+ 12 - 0
web/.editorconfig

@@ -0,0 +1,12 @@
+root = true # 控制配置文件 .editorconfig 是否生效的字段
+ 
+[**] # 匹配全部文件
+indent_style = space # 缩进风格,可选space|tab
+indent_size = 2 # 缩进的空格数
+charset = utf-8 # 设置字符集
+trim_trailing_whitespace = true # 删除一行中的前后空格
+insert_final_newline = true # 设为true表示使文件以一个空白行结尾
+end_of_line = lf
+ 
+[**.md] # 匹配md文件
+trim_trailing_whitespace = false

+ 23 - 0
web/.gitignore

@@ -0,0 +1,23 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*

+ 2 - 0
web/.npmrc

@@ -0,0 +1,2 @@
+registry=https://registry.npmmirror.com/
+@dage:registry=http://192.168.20.245:4873/

+ 11 - 0
web/.prettierrc.js

@@ -0,0 +1,11 @@
+module.exports = {
+  printWidth: 100, // 一行的字符数,如果超过会进行换行
+  tabWidth: 2, // 一个tab代表几个空格数,默认就是2
+  useTabs: false, // 是否启用tab取代空格符缩进,.editorconfig设置空格缩进,所以设置为false
+  semi: false, // 行尾是否使用分号,默认为true
+  singleQuote: true, // 字符串是否使用单引号
+  trailingComma: "none", // 对象或数组末尾是否添加逗号 none| es5| all
+  jsxSingleQuote: true, // 在jsx里是否使用单引号,你看着办
+  bracketSpacing: true, // 对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
+  arrowParens: "avoid", // 箭头函数如果只有一个参数则省略括号
+};

+ 39 - 0
web/.vscode/settings.json

@@ -0,0 +1,39 @@
+{
+  "search.exclude": {
+    "/node_modules": true,
+    "dist": true,
+    "pnpm-lock.sh": true
+  },
+  "editor.formatOnSave": true,
+  "[javascript]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[javascriptreact]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[typescript]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[typescriptreact]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[json]": {
+    "editor.defaultFormatter": "vscode.json-language-features"
+  },
+  "[html]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[markdown]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[css]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[less]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[scss]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "liveServer.settings.port": 5502
+}

+ 27 - 0
web/README.md

@@ -0,0 +1,27 @@
+本地运行:静态资源里面先运行一个服务 
+使用 http-server
+确保服务地址是:http://127.0.0.1:8080
+
+
+-------------------
+
+------ts版本类型问题-------
+
+找到 import { useDispatch } from "react-redux";
+
+按住 Ctrl 点击 useDispatch 出来 useDispatch.d.ts类型声明文件
+(路径node_modules>react-redux>es>hooks>useDispatch.d.ts)
+
+找到最后面的 AnyAction,按住 Ctrl 点击 进入
+(路径node_modules>redux>index.d.ts)
+
+找到
+export interface Action<T = any> {
+  type: T
+}
+
+在type后面加一个 ?   即=>
+
+export interface Action<T = any> {
+  type?: T
+}

+ 10 - 0
web/config-overrides.js

@@ -0,0 +1,10 @@
+const path = require('path')
+const { override, addWebpackAlias } = require('customize-cra')
+
+// 添加 @ 别名
+const webpackAlias = addWebpackAlias({
+  '@': path.resolve(__dirname, 'src'),
+})
+
+// 导出要进行覆盖的 webpack 配置
+module.exports = override(webpackAlias)

Різницю між файлами не показано, бо вона завелика
+ 30270 - 0
web/package-lock.json


+ 64 - 0
web/package.json

@@ -0,0 +1,64 @@
+{
+  "name": "demo",
+  "version": "0.1.0",
+  "private": true,
+  "dependencies": {
+    "@ant-design/cssinjs": "^1.5.6",
+    "@dage/krpano": "^2.2.0",
+    "@testing-library/jest-dom": "^5.16.5",
+    "@testing-library/react": "^13.4.0",
+    "@testing-library/user-event": "^13.5.0",
+    "@types/jest": "^27.5.2",
+    "@types/node": "^16.18.3",
+    "@types/react": "^18.0.24",
+    "@types/react-dom": "^18.0.8",
+    "antd": "^5.8.3",
+    "antd-mobile": "^5.30.0",
+    "axios": "^1.1.3",
+    "classnames": "^2.3.2",
+    "react": "^18.2.0",
+    "react-dom": "^18.2.0",
+    "react-redux": "^8.0.4",
+    "react-router-dom": "5.3",
+    "react-scripts": "5.0.1",
+    "react-sortablejs": "^6.1.4",
+    "redux": "^4.2.0",
+    "redux-devtools-extension": "^2.13.9",
+    "redux-thunk": "^2.4.1",
+    "sass": "^1.55.0",
+    "typescript": "^4.8.4",
+    "web-vitals": "^2.1.4"
+  },
+  "scripts": {
+    "dev": "react-app-rewired start",
+    "build": "react-app-rewired build",
+    "test": "react-app-rewired test",
+    "eject": "react-scripts eject"
+  },
+  "eslintConfig": {
+    "extends": [
+      "react-app",
+      "react-app/jest"
+    ]
+  },
+  "browserslist": {
+    "production": [
+      ">0.2%",
+      "not dead",
+      "not op_mini all"
+    ],
+    "development": [
+      "last 1 chrome version",
+      "last 1 firefox version",
+      "last 1 safari version"
+    ]
+  },
+  "devDependencies": {
+    "@types/history": "^5.0.0",
+    "@types/lodash": "^4.14.198",
+    "@types/react-router-dom": "^5.3.3",
+    "customize-cra": "^1.0.0",
+    "react-app-rewired": "^2.2.1"
+  },
+  "homepage": "."
+}

+ 8 - 0
web/path.tsconfig.json

@@ -0,0 +1,8 @@
+{
+    "compilerOptions": {
+      "baseUrl": "./",
+      "paths": {
+        "@/*": ["src/*"]
+      }
+    }
+  }

BIN
web/public/favicon.ico


+ 44 - 0
web/public/index.html

@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html lang="zh">
+  <head>
+    <meta charset="utf-8" />
+    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+    <meta name="viewport" content="width=device-width, initial-scale=1" />
+    <meta name="theme-color" content="#000000" />
+    <meta name="description" content="Web site created using create-react-app" />
+    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
+
+    <script src="./myData/myData.js"></script>
+
+    <!--
+      manifest.json provides metadata used when your web app is installed on a
+      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
+    -->
+
+    <!--
+      Notice the use of %PUBLIC_URL% in the tags above.
+      It will be replaced with the URL of the `public` folder during the build.
+      Only files inside the `public` folder can be referenced from the HTML.
+
+      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
+      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>中山大学附属肿瘤医院线上院史馆</title>
+  </head>
+
+  <body>
+    <noscript>You need to enable JavaScript to run this app.</noscript>
+    <div id="root"></div>
+    <!--
+      This HTML file is a template.
+      If you open it directly in the browser, you will see an empty page.
+
+      You can add webfonts, meta tags, or analytics to this file.
+      The build step will place the bundled scripts into the <body> tag.
+
+      To begin the development, run `npm start` or `yarn start`.
+      To create a production bundle, use `npm run build` or `yarn build`.
+    -->
+  </body>
+</html>

+ 12 - 0
web/public/myData/myData.js

@@ -0,0 +1,12 @@
+// 本地开发静态资源目录
+const baseUrlLoc = 'http://192.168.20.55:8080/staticData/'
+
+const myBaseUrl = 'https://houseoss.4dkankan.com/project/zsWeb/'
+
+// Build开发资源目录
+const baseUrlAtl = myBaseUrl + 'staticData/'
+
+// 所有数据
+const myDataTemp = {
+  home: {}
+}

+ 14 - 0
web/src/App.tsx

@@ -0,0 +1,14 @@
+import '@/assets/styles/base.css'
+import MessageCom from './components/Message'
+import RouterOrder from './components/RouterOrder'
+
+export default function App() {
+  return (
+    <div id='App'>
+      {/* 关于路由 */}
+      <RouterOrder />
+      {/* antd 轻提示 ---兼容360浏览器 */}
+      <MessageCom />
+    </div>
+  )
+}

+ 44 - 0
web/src/AppM.tsx

@@ -0,0 +1,44 @@
+import '@/assets/styles/base.css'
+// 关于路由
+import { useCallback, useEffect, useRef } from 'react'
+import MessageCom from './components/Message'
+import RouterOrder from './components/RouterOrder'
+
+export default function AppM() {
+  const setFullFu = useCallback(() => {
+    clearTimeout(time.current)
+    time.current = window.setTimeout(() => {
+      const dom: HTMLDivElement | null = document.querySelector('#root')
+      if (dom) {
+        dom.style.height = document.documentElement.clientHeight + 'px'
+      }
+    }, 100)
+  }, [])
+
+  const time = useRef(-1)
+
+  useEffect(() => {
+    const dom: HTMLDivElement | null = document.querySelector('#root')
+    if (dom) {
+      dom.style.width = '100vw'
+      dom.style.minHeight = 'auto'
+      dom.style.height = document.documentElement.clientHeight + 'px'
+      dom.style.minWidth = 'auto'
+    }
+    window.addEventListener('resize', setFullFu, true)
+
+    return () => {
+      window.removeEventListener('resize', setFullFu)
+    }
+  }, [setFullFu])
+
+  return (
+    <div id='AppM'>
+      {/* 关于路由 */}
+      <RouterOrder />
+
+      {/* antd 轻提示 ---兼容360浏览器 */}
+      <MessageCom />
+    </div>
+  )
+}

BIN
web/src/assets/img/IMGerror.png


BIN
web/src/assets/img/landtip.png


BIN
web/src/assets/img/loading.gif


+ 143 - 0
web/src/assets/styles/base.css

@@ -0,0 +1,143 @@
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+html {
+  height: 100%;
+  font-size: 14px;
+  user-select: none;
+}
+body {
+  font: 1em/1.4 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI', 'Hiragino Sans GB', 'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei', sans-serif;
+  height: 100%;
+  color: black;
+}
+a {
+  text-decoration: none;
+  color: black;
+  outline: none;
+}
+i {
+  font-style: normal;
+}
+img {
+  max-width: 100%;
+  max-height: 100%;
+  vertical-align: middle;
+  object-fit: cover;
+}
+ul {
+  list-style: none;
+}
+body {
+  overflow: auto;
+  overflow-y: overlay;
+}
+/* 文本域取消下拉 */
+textarea {
+  resize: none !important;
+  min-height: 100px !important;
+}
+/* 主题色 */
+:root {
+  --themeColor: #caab7a;
+  --themeColor2: #f4945a;
+}
+/* 找不到页面 */
+.noFindPage {
+  padding-top: 100px;
+  opacity: 0;
+  transition: opacity 0.5s;
+}
+#root {
+  width: 100vw;
+  height: 100vh;
+  min-width: 1600px;
+  min-height: 900px;
+  overflow: auto;
+  overflow-y: overlay;
+  /* antd图片预览组件 */
+}
+#root #App {
+  width: 100%;
+  height: 100%;
+  position: relative;
+}
+#root #AppM {
+  overflow: hidden;
+  max-width: 500px;
+  margin: 0 auto;
+}
+#root #AppM .noFindPage {
+  padding-top: 0;
+}
+#root .ant-image {
+  display: none;
+}
+[hidden] {
+  display: none !important;
+}
+.mySorrl::-webkit-scrollbar {
+  /*滚动条整体样式*/
+  width: 3px;
+  /*高宽分别对应横竖滚动条的尺寸*/
+  height: 1px;
+}
+.mySorrl::-webkit-scrollbar-thumb {
+  /*滚动条里面小方块*/
+  border-radius: 10px;
+  -webkit-box-shadow: inset 0 0 5px transparent;
+  background: var(--themeColor2);
+}
+.mySorrl::-webkit-scrollbar-track {
+  /*滚动条里面轨道*/
+  -webkit-box-shadow: inset 0 0 5px transparent;
+  border-radius: 10px;
+  background: transparent;
+}
+#root {
+  /*横屏*/
+}
+#root #ScreenChange {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 10000;
+  background-color: rgba(0, 0, 0, 0.8);
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  opacity: 0;
+  pointer-events: none;
+  transition: all 0.5s;
+}
+#root #ScreenChange > img {
+  width: 200px;
+}
+#root #ScreenChange > p {
+  margin-top: 20px;
+  color: #fff;
+  font-size: 18px;
+  height: 40px;
+}
+@media screen and (orientation: landscape) {
+  #root #ScreenChange {
+    opacity: 1;
+    pointer-events: auto;
+  }
+}
+.A1locBoxLoc {
+  animation: moveDian 1s linear infinite alternate;
+}
+@keyframes moveDian {
+  0% {
+    transform: translateY(-6px);
+  }
+  100% {
+    transform: translateY(6px);
+  }
+}

+ 175 - 0
web/src/assets/styles/base.less

@@ -0,0 +1,175 @@
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+html {
+  height: 100%;
+  font-size: 14px;
+  user-select: none;
+}
+
+body {
+  font: 1em/1.4 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI', 'Hiragino Sans GB',
+    'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei', sans-serif;
+  height: 100%;
+  color: black;
+}
+
+a {
+  text-decoration: none;
+  color: black;
+  outline: none;
+}
+
+i {
+  font-style: normal;
+}
+
+img {
+  max-width: 100%;
+  max-height: 100%;
+  vertical-align: middle;
+  object-fit: cover;
+}
+
+ul {
+  list-style: none;
+}
+
+body {
+  overflow: auto;
+  overflow-y: overlay;
+}
+
+/* 文本域取消下拉 */
+textarea {
+  resize: none !important;
+  min-height: 100px !important;
+}
+
+/* 主题色 */
+:root {
+  --themeColor: #caab7a;
+  --themeColor2: #f4945a;
+}
+
+/* 找不到页面 */
+.noFindPage {
+  padding-top: 100px;
+  opacity: 0;
+  transition: opacity 0.5s;
+}
+
+// 重置antd样式
+#root {
+  width: 100vw;
+  height: 100vh;
+  min-width: 1600px;
+  min-height: 900px;
+  overflow: auto;
+  overflow-y: overlay;
+
+  // pc端App组件的样式
+  #App {
+    width: 100%;
+    height: 100%;
+    position: relative;
+  }
+
+  // 移动端AppM组件的样式
+  #AppM {
+    overflow: hidden;
+    max-width: 500px;
+    margin: 0 auto;
+    .noFindPage {
+      padding-top: 0;
+    }
+  }
+
+  /* antd图片预览组件 */
+  .ant-image {
+    display: none;
+  }
+}
+
+[hidden] {
+  display: none !important;
+}
+
+// 滚动条
+.mySorrl::-webkit-scrollbar {
+  /*滚动条整体样式*/
+  width: 3px;
+  /*高宽分别对应横竖滚动条的尺寸*/
+  height: 1px;
+}
+
+.mySorrl::-webkit-scrollbar-thumb {
+  /*滚动条里面小方块*/
+  border-radius: 10px;
+  -webkit-box-shadow: inset 0 0 5px transparent;
+  background: var(--themeColor2);
+}
+
+.mySorrl::-webkit-scrollbar-track {
+  /*滚动条里面轨道*/
+  -webkit-box-shadow: inset 0 0 5px transparent;
+  border-radius: 10px;
+  background: transparent;
+}
+
+#root {
+  // 横屏 竖屏的切换
+  #ScreenChange {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    z-index: 10000;
+    background-color: rgba(0, 0, 0, 0.8);
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    opacity: 0;
+    pointer-events: none;
+    transition: all 0.5s;
+
+    & > img {
+      width: 200px;
+    }
+
+    & > p {
+      margin-top: 20px;
+      color: #fff;
+      font-size: 18px;
+      height: 40px;
+    }
+  }
+
+  /*横屏*/
+  @media screen and (orientation: landscape) {
+    #ScreenChange {
+      opacity: 1;
+      pointer-events: auto;
+    }
+  }
+}
+
+// pc首页箭头动画帧
+.A1locBoxLoc {
+  animation: moveDian 1s linear infinite alternate;
+}
+
+@keyframes moveDian {
+  0% {
+    transform: translateY(-6px);
+  }
+
+  100% {
+    transform: translateY(6px);
+  }
+}

+ 27 - 0
web/src/components/Message/index.tsx

@@ -0,0 +1,27 @@
+import React, { useEffect } from 'react'
+import { message } from 'antd'
+import { useSelector } from 'react-redux'
+import { RootState } from '@/store'
+
+function MessageCom() {
+  // 从仓库中获取 antd 轻提示信息
+  const messageReducerInfo = useSelector((state: RootState) => state.A0Layout.message)
+
+  const [messageApi, contextHolder] = message.useMessage()
+
+  useEffect(() => {
+    if (messageReducerInfo.txt) {
+      messageApi.open({
+        type: messageReducerInfo.type,
+        content: messageReducerInfo.txt,
+        duration: messageReducerInfo.duration
+      })
+    }
+  }, [messageApi, messageReducerInfo])
+
+  return <>{contextHolder}</>
+}
+
+const MemoMessage = React.memo(MessageCom)
+
+export default MemoMessage

+ 30 - 0
web/src/components/NotFound/index.tsx

@@ -0,0 +1,30 @@
+import history from '@/utils/history'
+import { Button, Result } from 'antd'
+import { useEffect, useRef } from 'react'
+
+export default function NotFound() {
+  const timeRef = useRef(-1)
+
+  useEffect(() => {
+    timeRef.current = window.setTimeout(() => {
+      const dom: HTMLDivElement = document.querySelector('.noFindPage')!
+      dom.style.opacity = '1'
+    }, 300)
+    return () => {
+      clearTimeout(timeRef.current)
+    }
+  }, [])
+
+  return (
+    <div className='noFindPage'>
+      <Result status='404' title='404' subTitle='找不到页面' />
+      <div style={{ display: 'flex', justifyContent: 'center' }}>
+        <Button type='primary' onClick={() => history.replace('/')}>
+          首页
+        </Button>
+        &emsp;
+        <Button onClick={() => history.go(-1)}>返回</Button>
+      </div>
+    </div>
+  )
+}

+ 92 - 0
web/src/components/RouterOrder.tsx

@@ -0,0 +1,92 @@
+import history, { isMobileFu } from '@/utils/history'
+import React from 'react'
+import { Route, Router, Switch } from 'react-router-dom'
+import SpinLoding from './SpinLoding'
+import NotFound from '@/components/NotFound'
+
+const A1home = React.lazy(() => import('@/pages/A1home'))
+const A1homeM = React.lazy(() => import('@/pages/A1homeM'))
+
+const routerArr = [
+  {
+    id: 1,
+    name: '首页',
+    path: '/',
+    exact: true,
+    Com: isMobileFu() ? A1homeM : A1home
+  },
+  // {
+  //   id: 2,
+  //   name: "村落",
+  //   path: "/village",
+  //   exact: false,
+  //   Com: isMobileFu() ? B1VillageM : B1Village,
+  // },
+  // {
+  //   id: 3,
+  //   name: "建筑",
+  //   path: "/architec",
+  //   exact: false,
+  //   Com: isMobileFu() ? C1ArchitecM : C1Architec,
+  // },
+  // {
+  //   id: 4,
+  //   name: "建筑详情",
+  //   path: "/architecInfo",
+  //   exact: false,
+  //   Com: C2ArchitecInfo,
+  // },
+  // {
+  //   id: 5,
+  //   name: "构件",
+  //   path: "/build",
+  //   exact: false,
+  //   Com: isMobileFu() ? D1BuildM : D1Build,
+  // },
+  // {
+  //   id: 6,
+  //   name: "构件详情",
+  //   path: "/buildInfo",
+  //   exact: false,
+  //   Com: D2BuildInfo,
+  // },
+  // {
+  //   id: 7,
+  //   name: "场景",
+  //   path: "/scene",
+  //   exact: false,
+  //   Com: Z2Scene,
+  // },
+  // {
+  //   id: 8,
+  //   name: "搜索",
+  //   path: "/search",
+  //   exact: false,
+  //   Com: Z1Search,
+  // },
+  {
+    id: 9,
+    name: '找不到页面',
+    path: '*',
+    exact: false,
+    Com: NotFound
+  }
+]
+
+function RouterOrder() {
+  return (
+    <Router history={history}>
+      <React.Suspense fallback={<SpinLoding />}>
+        <Switch>
+          {routerArr.map(v => (
+            <Route key={v.id} path={v.path} exact={v.exact} component={v.Com} />
+          ))}
+        </Switch>
+      </React.Suspense>
+    </Router>
+  )
+}
+
+const MemoRouterOrder = React.memo(RouterOrder)
+
+export default MemoRouterOrder

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

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

+ 13 - 0
web/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;

+ 37 - 0
web/src/index.tsx

@@ -0,0 +1,37 @@
+// import 'default-passive-events';
+import App from './App'
+import AppM from './AppM'
+
+import store from './store/index'
+import { Provider } from 'react-redux'
+import { createRoot } from 'react-dom/client'
+
+import { ConfigProvider } from 'antd'
+// 兼容360浏览器
+import { StyleProvider, legacyLogicalPropertiesTransformer } from '@ant-design/cssinjs'
+
+import 'dayjs/locale/zh-cn'
+import locale from 'antd/locale/zh_CN'
+
+import { isMobileFu } from './utils/history'
+
+const container = document.getElementById('root') as HTMLElement
+const root = createRoot(container)
+
+root.render(
+  <ConfigProvider
+    locale={locale}
+    theme={{
+      token: {
+        colorPrimary: '#caab7a'
+      }
+    }}
+  >
+    <Provider store={store}>
+      <StyleProvider hashPriority='high' transformers={[legacyLogicalPropertiesTransformer]}>
+        {/* 渲染 移动端 或 pc端 */}
+        {isMobileFu() ? <AppM /> : <App />}
+      </StyleProvider>
+    </Provider>
+  </ConfigProvider>
+)

+ 5 - 0
web/src/pages/A1home/index.module.scss

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

+ 14 - 0
web/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;

+ 5 - 0
web/src/pages/A1homeM/index.module.scss

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

+ 14 - 0
web/src/pages/A1homeM/index.tsx

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

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

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

+ 14 - 0
web/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;

+ 20 - 0
web/src/store/index.ts

@@ -0,0 +1,20 @@
+// 导入 redux
+import { applyMiddleware, legacy_createStore as createStore } from 'redux'
+// 导入自己封装的  rootReducer 
+import rootReducer from './reducer'
+// 导入调试工具和 异步的 redux(用来发送异步请求)
+// 调试工具需要下载谷歌 扩展程序 我用的是 Redux DevTools 3.0.17
+import { composeWithDevTools } from 'redux-devtools-extension'
+import thunk from 'redux-thunk'
+
+// 创建仓库实例
+const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)))
+
+// 声明 RootState,在使用仓库的时候用来使用
+export type RootState = ReturnType<typeof store.getState>
+
+// 声明 AppDispatch,在异步请求的时候来使用
+export type AppDispatch = typeof store.dispatch
+
+// 导出仓库实例
+export default store

+ 14 - 0
web/src/store/reducer/index.ts

@@ -0,0 +1,14 @@
+// 导入合并reducer的依赖
+import { combineReducers } from "redux";
+
+// 导入 登录 模块的 reducer
+import A0Layout from "./layout";
+
+
+// 合并 reducer
+const rootReducer = combineReducers({
+  A0Layout,
+});
+
+// 默认导出
+export default rootReducer;

+ 25 - 0
web/src/store/reducer/layout.ts

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

+ 1 - 0
web/src/types/api/layot.d.ts

@@ -0,0 +1 @@
+export type MyDataType = { id: number }

+ 13 - 0
web/src/types/declaration.d.ts

@@ -0,0 +1,13 @@
+declare module 'history'
+declare module '*.scss'
+declare module '*.png'
+declare module '*.jpg'
+declare module '*.gif'
+declare module '*.svg'
+declare module 'js-export-excel'
+declare module 'braft-utils'
+
+// 一些在pubilc/index里面直接定义的数据类型声明
+declare const baseUrlLoc: string
+declare const baseUrlAtl: string
+declare const myDataTemp: MyDataType

+ 2 - 0
web/src/types/index.d.ts

@@ -0,0 +1,2 @@
+export * from './api/layot'
+

+ 22 - 0
web/src/utils/history.ts

@@ -0,0 +1,22 @@
+import { createHashHistory } from 'history'
+const history = createHashHistory()
+export default history
+
+// 判断是手机端还是pc端
+export const isMobileFu = () => {
+  if (
+    window.navigator.userAgent.match(
+      /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
+    )
+  ) {
+    return true
+  } else return false
+}
+
+// 当前环境是 本地环境 还是 服务器环境
+export const isLoc = process.env.NODE_ENV === 'development'
+
+export const baseURL = isLoc ? baseUrlLoc : baseUrlAtl
+
+// 所有数据
+export const myData = myDataTemp

+ 50 - 0
web/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,
+      },
+    });
+  },
+};

+ 16 - 0
web/src/utils/storage.ts

@@ -0,0 +1,16 @@
+// 本地存储-临时会话
+const TOKEN_KEY = "KP_WEB_TIT";
+
+/**
+ * 获取临时存储信息
+ */
+export const getTitFu = (): string[] => {
+  return JSON.parse(sessionStorage.getItem(TOKEN_KEY) || "[]");
+};
+
+/**
+ *  信息存入缓存
+ */
+export const setTitFu = (val: string[]): void => {
+  sessionStorage.setItem(TOKEN_KEY, JSON.stringify(val));
+};

+ 27 - 0
web/tsconfig.json

@@ -0,0 +1,27 @@
+{
+  "extends": "./path.tsconfig.json",
+  "compilerOptions": {
+    "target": "es5",
+    "lib": [
+      "dom",
+      "dom.iterable",
+      "esnext"
+    ],
+    "allowJs": true,
+    "skipLibCheck": true,
+    "esModuleInterop": true,
+    "allowSyntheticDefaultImports": true,
+    "strict": true,
+    "forceConsistentCasingInFileNames": true,
+    "noFallthroughCasesInSwitch": true,
+    "module": "esnext",
+    "moduleResolution": "node",
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true,
+    "jsx": "react-jsx"
+  },
+  "include": [
+    "src"
+  ]
+}

Різницю між файлами не показано, бо вона завелика
+ 10734 - 0
web/yarn.lock