Jelajahi Sumber

第三方登录对接

shaogen1995 1 bulan lalu
induk
melakukan
a0d926dc61

+ 3 - 20
后台大场景编辑/README.md

@@ -1,22 +1,5 @@
-1.版本类型问题
-
-找到 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
-}
+1.测试服务器存放位置:--/data/data01/beiren_bigScene_local_data
 
+2.测试域名:https://sit-beirenbigscene.4dage.com
 
+3.部署之后 backUrl 按需求修改域名

+ 7 - 27
后台大场景编辑/public/index.html

@@ -5,39 +5,19 @@
     <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"
-    />
+    <meta name="description" content="Web site created using create-react-app" />
     <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
-    <!--
-      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.
+    <script>
+      // 甲方服务器域名
+      // const backUrl = 'http://192.168.20.55:3000'
+      const backUrl = 'https://sit-beirenbigscene.4dage.com/'
+    </script>
 
-      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>
+    <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>

+ 15 - 14
后台大场景编辑/src/App.tsx

@@ -1,15 +1,15 @@
-import "@/assets/styles/base.css";
+import '@/assets/styles/base.css'
 // 关于路由
-import React from "react";
-import { Router, Route, Switch } from "react-router-dom";
-import history from "./utils/history";
-import AuthRoute from "./components/AuthRoute";
-import SpinLoding from "./components/SpinLoding";
-import AsyncSpinLoding from "./components/AsyncSpinLoding";
-import UpAsyncLoding from "./components/UpAsyncLoding";
-import MessageCom from "./components/Message";
-const Layout = React.lazy(() => import("./pages/Layout"));
-const Login = React.lazy(() => import("./pages/Login"));
+import React from 'react'
+import { Router, Route, Switch } from 'react-router-dom'
+import history from './utils/history'
+import AuthRoute from './components/AuthRoute'
+import SpinLoding from './components/SpinLoding'
+import AsyncSpinLoding from './components/AsyncSpinLoding'
+import UpAsyncLoding from './components/UpAsyncLoding'
+import MessageCom from './components/Message'
+const Layout = React.lazy(() => import('./pages/Layout'))
+const Login = React.lazy(() => import('./pages/Login'))
 
 export default function App() {
   return (
@@ -19,8 +19,9 @@ export default function App() {
         <React.Suspense fallback={<SpinLoding />}>
           <Switch>
             {/* 测试页面 */}
-            <Route path="/login" component={Login} />
-            <AuthRoute path="/" component={Layout} />
+            <Route path='/' component={Login} exact />
+            <Route path='/login' component={Login} />
+            <AuthRoute path='/' component={Layout} />
           </Switch>
         </React.Suspense>
       </Router>
@@ -34,5 +35,5 @@ export default function App() {
       {/* antd 轻提示 ---兼容360浏览器 */}
       <MessageCom />
     </>
-  );
+  )
 }

+ 1 - 2
后台大场景编辑/src/assets/styles/base.css

@@ -6,7 +6,6 @@
 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;
@@ -40,7 +39,7 @@ textarea {
 }
 /* 主题色 */
 :root {
-  --themeColor: #00A0E6;
+  --themeColor: #00a0e6;
 }
 /* 找不到页面 */
 .noFindPage {

+ 7 - 21
后台大场景编辑/src/assets/styles/base.less

@@ -7,11 +7,12 @@
 html {
   height: 100%;
   font-size: 14px;
-  user-select: none;
+  // 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;
+  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;
 }
@@ -49,20 +50,15 @@ textarea {
 
 /* 主题色 */
 :root {
-  --themeColor: #00A0E6;
+  --themeColor: #00a0e6;
 }
 
-
-
-
-
 /* 找不到页面 */
 .noFindPage {
   opacity: 0;
-  transition: opacity .5s;
+  transition: opacity 0.5s;
 }
 
-
 /* 兼容360浏览器的下拉框 */
 .ant-select-selector {
   position: relative;
@@ -71,7 +67,6 @@ textarea {
   transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
 }
 
-
 // 重置antd样式
 #root {
   width: 100vw;
@@ -111,7 +106,6 @@ textarea {
     background-color: var(--themeColor) !important;
   }
 
-
   .ant-pagination .ant-pagination-item-active a {
     color: #fff !important;
   }
@@ -137,14 +131,11 @@ textarea {
     color: #fff;
   }
 
-
-
   .ant-pagination-next {
     border-radius: 50% !important;
     border: 1px solid #999;
   }
 
-
   .ant-pagination-next:hover {
     background-color: var(--themeColor);
   }
@@ -161,7 +152,6 @@ textarea {
     background-color: transparent;
   }
 
-
   /* 表格的图片居中 */
   .tableImgAuto {
     display: flex;
@@ -186,19 +176,15 @@ textarea {
   }
 
   // 时间选择器居中
-  .ant-picker .ant-picker-input>input {
+  .ant-picker .ant-picker-input > input {
     text-align: center;
   }
 }
 
-
-
 [hidden] {
   display: none !important;
 }
 
-
-
 #upInput {
   display: none;
 }
@@ -252,4 +238,4 @@ textarea {
   -webkit-box-shadow: inset 0 0 5px transparent;
   border-radius: 10px;
   background: transparent;
-}
+}

+ 13 - 13
后台大场景编辑/src/components/AuthRoute/index.tsx

@@ -1,13 +1,13 @@
-import { hasToken } from "@//utils/storage";
-import { MessageFu } from "@/utils/message";
-import React from "react";
-import { Redirect, Route } from "react-router-dom";
+import { hasToken } from '@//utils/storage'
+// import { MessageFu } from "@/utils/message";
+import React from 'react'
+import { Redirect, Route } from 'react-router-dom'
 
 type AtahType = {
-  path: string;
-  component: React.FC;
-  [x: string]: any;
-};
+  path: string
+  component: React.FC
+  [x: string]: any
+}
 
 export default function AuthRoute({ path, component: Com, ...rest }: AtahType) {
   return (
@@ -15,18 +15,18 @@ export default function AuthRoute({ path, component: Com, ...rest }: AtahType) {
       path={path}
       {...rest}
       render={() => {
-        if (hasToken()) return <Com />;
+        if (hasToken()) return <Com />
         else {
-          MessageFu.warning("登录失效!");
+          // MessageFu.warning("登录失效!");
           return (
             <Redirect
               to={{
-                pathname: "/login",
+                pathname: '/login'
               }}
             />
-          );
+          )
         }
       }}
     />
-  );
+  )
 }

+ 97 - 105
后台大场景编辑/src/pages/Layout/index.tsx

@@ -1,148 +1,140 @@
-import React, {
-  useCallback,
-  useEffect,
-  useMemo,
-  useRef,
-  useState,
-} from "react";
-import { CaretUpOutlined, CaretDownOutlined } from "@ant-design/icons";
-import styles from "./index.module.scss";
-import SpinLoding from "@/components/SpinLoding";
-import { Route, Switch, useLocation } from "react-router-dom";
-import AuthRoute from "@/components/AuthRoute";
-import classNames from "classnames";
-import history from "@/utils/history";
-import { Button, Form, Input, Modal, Popconfirm } from "antd";
-import { Base64 } from "js-base64";
-import encodeStr from "@/utils/pass";
-import { passWordEditAPI } from "@/store/action/layout";
-import { getTokenInfo, removeTokenInfo } from "@/utils/storage";
-import { MessageFu } from "@/utils/message";
-import logonImg from "@/assets/img/logo.png";
-
-const NotFound = React.lazy(() => import("@/components/NotFound"));
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons'
+import styles from './index.module.scss'
+import SpinLoding from '@/components/SpinLoding'
+import { Route, Switch, useLocation } from 'react-router-dom'
+import AuthRoute from '@/components/AuthRoute'
+import classNames from 'classnames'
+import history from '@/utils/history'
+import { Button, Form, Input, Modal, Popconfirm } from 'antd'
+import { Base64 } from 'js-base64'
+import encodeStr from '@/utils/pass'
+import { passWordEditAPI } from '@/store/action/layout'
+import { getTokenInfo, removeTokenInfo } from '@/utils/storage'
+import { MessageFu } from '@/utils/message'
+import logonImg from '@/assets/img/logo.png'
+
+const NotFound = React.lazy(() => import('@/components/NotFound'))
 
 function Layout() {
   const list = useMemo(() => {
     return [
       {
         id: 100,
-        name: "场景管理",
-        path: "/",
-        Com: React.lazy(() => import("../A1List")),
-      },
-    ];
-  }, []);
+        name: '场景管理',
+        path: '/list',
+        Com: React.lazy(() => import('../A1List'))
+      }
+    ]
+  }, [])
 
   useEffect(() => {
     // 如果是超级管理员
-    const userInfo = getTokenInfo().user;
+    const userInfo = getTokenInfo().user
     if (userInfo.isAdmin === 1) {
       list.push({
         id: 900,
-        name: "用户管理",
-        path: "/user",
-        Com: React.lazy(() => import("../A9User")),
-      });
+        name: '用户管理',
+        path: '/user',
+        Com: React.lazy(() => import('../A9User'))
+      })
     }
-  }, [list]);
+  }, [list])
 
   // 点击跳转
   const pathCutFu = useCallback((path: string) => {
-    history.push(path);
-  }, []);
+    history.push(path)
+  }, [])
 
   // 当前路径选中的左侧菜单
-  const location = useLocation();
-  const [path, setPath] = useState("");
+  const location = useLocation()
+  const [path, setPath] = useState('')
 
   useEffect(() => {
-    const arr = location.pathname.split("/");
-    let pathTemp = "/";
-    if (arr[1]) pathTemp = "/" + arr[1];
+    const arr = location.pathname.split('/')
+    let pathTemp = '/'
+    if (arr[1]) pathTemp = '/' + arr[1]
 
-    setPath(pathTemp);
-  }, [location]);
+    setPath(pathTemp)
+  }, [location])
 
   const userInfo = useMemo(() => {
-    return getTokenInfo().user;
-  }, []);
+    return getTokenInfo().user
+  }, [])
 
   // 修改密码相关
-  const [open, setOpen] = useState(false);
+  const [open, setOpen] = useState(false)
 
   // 拿到新密码的输入框的值
-  const oldPasswordValue = useRef("");
+  const oldPasswordValue = useRef('')
 
-  const checkPassWord = (rule: any, value: any = "") => {
-    if (value !== oldPasswordValue.current)
-      return Promise.reject("新密码不一致!");
-    else return Promise.resolve(value);
-  };
+  const checkPassWord = (rule: any, value: any = '') => {
+    if (value !== oldPasswordValue.current) return Promise.reject('新密码不一致!')
+    else return Promise.resolve(value)
+  }
 
   const onFinish = async (values: any) => {
     // 通过校验之后发送请求
     if (values.oldPassword === values.newPassword)
-      return MessageFu.warning("新旧密码不能相同!");
+      return MessageFu.warning('新旧密码不能相同!')
     const obj = {
       oldPassword: encodeStr(Base64.encode(values.oldPassword)),
-      newPassword: encodeStr(Base64.encode(values.newPassword)),
-    };
-    const res: any = await passWordEditAPI(obj);
+      newPassword: encodeStr(Base64.encode(values.newPassword))
+    }
+    const res: any = await passWordEditAPI(obj)
     if (res.code === 0) {
-      MessageFu.success("修改成功!");
-      loginExit();
+      MessageFu.success('修改成功!')
+      loginExit()
     }
-  };
+  }
 
   // 点击退出登录
   const loginExit = () => {
-    removeTokenInfo();
-    history.push("/login");
-  };
+    removeTokenInfo()
+    history.push('/login')
+  }
 
   return (
     <div className={styles.Layout}>
       {/* 左边 */}
-      <div className="layoutLeft">
-        <div className="layoutLeftTop">
-          {userInfo.isAdmin === 1 ? <img src={logonImg} alt="" /> : null}
+      <div className='layoutLeft'>
+        <div className='layoutLeftTop'>
+          {userInfo.isAdmin === 1 ? <img src={logonImg} alt='' /> : null}
         </div>
         {/* 左边主体 */}
-        <div className="layoutLeftMain">
-          {list.map((v) => (
+        <div className='layoutLeftMain'>
+          {list.map(v => (
             <div
               key={v.id}
               onClick={() => pathCutFu(v.path)}
-              className={classNames(
-                "mainBoxL2Row",
-                v.path === path ? "active" : ""
-              )}
+              className={classNames('mainBoxL2Row', v.path === path ? 'active' : '')}
             >
-              <div className="txt">{v.name}</div>
+              <div className='txt'>{v.name}</div>
             </div>
           ))}
         </div>
       </div>
       {/* 右边 */}
-      <div className="layoutRight">
-        <div className="layoutRightTop">
+      <div className='layoutRight'>
+        <div className='layoutRightTop'>
           {/* 用户相关 */}
-          <div className="user">
+          <div className='user'>
             {userInfo.realName}
-            <div className="userInco userInco1">
+            <div className='userInco userInco1'>
               <CaretUpOutlined />
             </div>
-            <div className="userInco userInco2">
+            <div className='userInco userInco2'>
               <CaretDownOutlined />
             </div>
-            <div className="userSet">
-              <span onClick={() => setOpen(true)}>修改密码</span>
+            <div className='userSet'>
+              <span onClick={() => setOpen(true)} hidden>
+                修改密码
+              </span>
               <Popconfirm
-                placement="bottom"
-                title="确定退出吗?"
-                okText="确定"
-                cancelText="取消"
+                placement='bottom'
+                title='确定退出吗?'
+                okText='确定'
+                cancelText='取消'
                 okButtonProps={{ loading: false }}
                 onConfirm={loginExit}
               >
@@ -152,16 +144,16 @@ function Layout() {
           </div>
         </div>
         {/* 右边主体 */}
-        <div className="layoutRightMain">
+        <div className='layoutRightMain'>
           {/* 二级路由页面 */}
-          <div className="mainBoxR">
+          <div className='mainBoxR'>
             <React.Suspense fallback={<SpinLoding />}>
               <Switch>
-                {list.map((v) => (
+                {list.map(v => (
                   <AuthRoute key={v.id} exact path={v.path} component={v.Com} />
                 ))}
 
-                <Route path="*" component={NotFound} />
+                <Route path='*' component={NotFound} />
               </Switch>
             </React.Suspense>
           </div>
@@ -172,44 +164,44 @@ function Layout() {
       <Modal
         destroyOnClose
         open={open}
-        title="修改密码"
+        title='修改密码'
         onCancel={() => setOpen(false)}
         footer={
           [] // 设置footer为空,去掉 取消 确定默认按钮
         }
       >
         <Form
-          name="basic"
+          name='basic'
           labelCol={{ span: 5 }}
           wrapperCol={{ span: 16 }}
           onFinish={onFinish}
-          autoComplete="off"
+          autoComplete='off'
         >
           <Form.Item
-            label="旧密码"
-            name="oldPassword"
-            rules={[{ required: true, message: "不能为空!" }]}
+            label='旧密码'
+            name='oldPassword'
+            rules={[{ required: true, message: '不能为空!' }]}
           >
             <Input.Password maxLength={15} />
           </Form.Item>
 
           <Form.Item
-            label="新密码"
-            name="newPassword"
+            label='新密码'
+            name='newPassword'
             rules={[
-              { required: true, message: "不能为空!" },
-              { min: 6, max: 15, message: "密码长度为6-15个字符!" },
+              { required: true, message: '不能为空!' },
+              { min: 6, max: 15, message: '密码长度为6-15个字符!' }
             ]}
           >
             <Input.Password
               maxLength={15}
-              onChange={(e) => (oldPasswordValue.current = e.target.value)}
+              onChange={e => (oldPasswordValue.current = e.target.value)}
             />
           </Form.Item>
 
           <Form.Item
-            label="确定新密码"
-            name="checkPass"
+            label='确定新密码'
+            name='checkPass'
             rules={[{ validator: checkPassWord }]}
           >
             <Input.Password maxLength={15} />
@@ -218,16 +210,16 @@ function Layout() {
           <Form.Item wrapperCol={{ offset: 14, span: 16 }}>
             <Button onClick={() => setOpen(false)}>取消</Button>
             &emsp;
-            <Button type="primary" htmlType="submit">
+            <Button type='primary' htmlType='submit'>
               确定
             </Button>
           </Form.Item>
         </Form>
       </Modal>
     </div>
-  );
+  )
 }
 
 // 使用 React.memo 来优化组件,避免组件的无效更新,类似 类组件里面的PureComponent
-const MemoLayout = React.memo(Layout);
-export default MemoLayout;
+const MemoLayout = React.memo(Layout)
+export default MemoLayout

+ 137 - 0
后台大场景编辑/src/pages/Login copy/index.module.scss

@@ -0,0 +1,137 @@
+.Login {
+  width: 100%;
+  height: 100%;
+  background-image: url('../../assets/img/loginBg.jpg');
+  background-size: cover;
+  position: relative;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    z-index: 9;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, .7);
+  }
+
+
+  :global {
+    .main {
+      z-index: 10;
+      position: absolute;
+      top: 48%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      width: 400px;
+      text-align: center;
+
+      &>h3 {
+        font-size: 24px;
+        letter-spacing: 6px;
+        color: #fff;
+      }
+
+      .inputBox {
+        width: 100%;
+
+        input::-webkit-input-placeholder {
+          /* WebKit browsers */
+          color: rgba(255, 255, 255, .5);
+        }
+
+        input:-moz-placeholder {
+          /* Mozilla Firefox 4 to 18 */
+          color: rgba(255, 255, 255, .5);
+        }
+
+        input::-moz-placeholder {
+          /* Mozilla Firefox 19+ */
+          color: rgba(255, 255, 255, .5);
+        }
+
+        input:-ms-input-placeholder {
+          /* Internet Explorer 10+ */
+          color: rgba(255, 255, 255, .5);
+        }
+
+
+        .inputBoxRow {
+          margin-top: 30px;
+
+          .ant-input-suffix .ant-input-password-icon {
+            color: #fff;
+            font-size: 22px;
+          }
+        }
+
+        .ant-input-prefix {
+          margin-right: 10px;
+
+          .anticon {
+            padding-right: 10px;
+            width: 36px;
+            height: 36px;
+
+            svg {
+              width: 100%;
+              height: 100%;
+            }
+          }
+        }
+
+        .ant-input {
+          color: #fff;
+          font-size: 18px;
+          width: 45%;
+          height: 60px;
+          line-height: 60px;
+          background-clip: content-box;
+        }
+
+        input:-webkit-autofill {
+          font-size: 18px !important;
+          -webkit-text-fill-color: #fff !important;
+          background-image: none;
+          -webkit-box-shadow: 0 0 0px 1000px transparent inset !important; //填充阴影,可以用来遮住背景色
+          background-color: transparent;
+          transition: background-color 50000s ease-in-out 0s; //背景色透明  生效时长  过渡效果  启用时延迟的时间
+
+        }
+
+        .ant-input-affix-wrapper {
+          background-color: transparent;
+          padding: 0 11px;
+          width: 100%;
+          height: 60px;
+          border: none;
+          border: 1px solid #fff;
+          color: #fff;
+
+          .ant-input {
+            background-color: transparent;
+            width: 100%;
+            height: 60px;
+          }
+        }
+
+        // .ant-input-affix-wrapper-focused {
+        //   box-shadow: none
+        // }
+      }
+
+      .loginBtn {
+        margin-top: 30px;
+
+        .ant-btn {
+          width: 100%;
+          font-size: 20px;
+          height: 50px;
+        }
+      }
+
+    }
+  }
+}

+ 78 - 0
后台大场景编辑/src/pages/Login copy/index.tsx

@@ -0,0 +1,78 @@
+import styles from "./index.module.scss";
+
+import { Input, Button } from "antd";
+import { UserOutlined, LockOutlined } from "@ant-design/icons";
+import { useState } from "react";
+import { Base64 } from "js-base64";
+import encodeStr from "@/utils/pass";
+import { setTokenInfo } from "@/utils/storage";
+import history from "@/utils/history";
+import { MessageFu } from "@/utils/message";
+import { userLoginAPI } from "@/store/action/layout";
+
+export default function Login() {
+  // 账号密码
+  const [userName, setUserName] = useState("admin");
+  const [passWord, setPassWord] = useState("");
+
+  // 键盘按下回车事件
+  const keyUpEntFu = (e: React.KeyboardEvent<HTMLInputElement>) => {
+    if (e.key === "Enter") loginClickFu();
+  };
+  // 点击登录
+  const loginClickFu = async () => {
+    // 非空判断
+    if (userName === "") return MessageFu.warning("请输入用户名!");
+    else if (passWord === "") return MessageFu.warning("请输入密码!");
+    const obj = {
+      userName,
+      passWord: encodeStr(Base64.encode(passWord)),
+    };
+    const res: any = await userLoginAPI(obj);
+    if (res.code === 0) {
+      MessageFu.success("登录成功");
+      // 用户信息存到本地
+      setTokenInfo(res.data);
+      history.push("/");
+    } else if (res.code === 3014)
+      MessageFu.warning("用户名不存在或密码错误,请联系管理员!");
+  };
+
+  return (
+    <div className={styles.Login}>
+      <div className="main">
+        <h3>本地大场景管理</h3>
+        {/* 账号密码输入框 */}
+        <div className="inputBox">
+          <div className="inputBoxRow">
+            <Input
+              onKeyUp={(e) => keyUpEntFu(e)}
+              value={userName}
+              onChange={(e) => setUserName(e.target.value.trim())}
+              prefix={<UserOutlined />}
+              placeholder="请输入用户名"
+              maxLength={15}
+            />
+          </div>
+          <div className="inputBoxRow">
+            <Input.Password
+              onKeyUp={(e) => keyUpEntFu(e)}
+              value={passWord}
+              onChange={(e) => setPassWord(e.target.value.trim())}
+              prefix={<LockOutlined />}
+              placeholder="请输入用户密码"
+              maxLength={15}
+            />
+          </div>
+        </div>
+
+        {/* 登录按钮 */}
+        <div className="loginBtn">
+          <Button type="primary" size="large" onClick={loginClickFu}>
+            登 录
+          </Button>
+        </div>
+      </div>
+    </div>
+  );
+}

+ 19 - 115
后台大场景编辑/src/pages/Login/index.module.scss

@@ -3,8 +3,6 @@
   height: 100%;
   background-image: url('../../assets/img/loginBg.jpg');
   background-size: cover;
-  position: relative;
-  position: relative;
 
   &::before {
     content: '';
@@ -14,124 +12,30 @@
     left: 0;
     width: 100%;
     height: 100%;
-    background-color: rgba(0, 0, 0, .7);
+    background-color: rgba(0, 0, 0, 0.7);
   }
-
-
   :global {
-    .main {
-      z-index: 10;
+    .LoginBtn {
       position: absolute;
-      top: 48%;
+      top: 55%;
       left: 50%;
       transform: translate(-50%, -50%);
-      width: 400px;
-      text-align: center;
-
-      &>h3 {
-        font-size: 24px;
-        letter-spacing: 6px;
-        color: #fff;
-      }
-
-      .inputBox {
-        width: 100%;
-
-        input::-webkit-input-placeholder {
-          /* WebKit browsers */
-          color: rgba(255, 255, 255, .5);
-        }
-
-        input:-moz-placeholder {
-          /* Mozilla Firefox 4 to 18 */
-          color: rgba(255, 255, 255, .5);
-        }
-
-        input::-moz-placeholder {
-          /* Mozilla Firefox 19+ */
-          color: rgba(255, 255, 255, .5);
-        }
-
-        input:-ms-input-placeholder {
-          /* Internet Explorer 10+ */
-          color: rgba(255, 255, 255, .5);
-        }
-
-
-        .inputBoxRow {
-          margin-top: 30px;
-
-          .ant-input-suffix .ant-input-password-icon {
-            color: #fff;
-            font-size: 22px;
-          }
-        }
-
-        .ant-input-prefix {
-          margin-right: 10px;
-
-          .anticon {
-            padding-right: 10px;
-            width: 36px;
-            height: 36px;
-
-            svg {
-              width: 100%;
-              height: 100%;
-            }
-          }
-        }
-
-        .ant-input {
-          color: #fff;
-          font-size: 18px;
-          width: 45%;
-          height: 60px;
-          line-height: 60px;
-          background-clip: content-box;
-        }
-
-        input:-webkit-autofill {
-          font-size: 18px !important;
-          -webkit-text-fill-color: #fff !important;
-          background-image: none;
-          -webkit-box-shadow: 0 0 0px 1000px transparent inset !important; //填充阴影,可以用来遮住背景色
-          background-color: transparent;
-          transition: background-color 50000s ease-in-out 0s; //背景色透明  生效时长  过渡效果  启用时延迟的时间
-
-        }
-
-        .ant-input-affix-wrapper {
-          background-color: transparent;
-          padding: 0 11px;
-          width: 100%;
-          height: 60px;
-          border: none;
-          border: 1px solid #fff;
-          color: #fff;
-
-          .ant-input {
-            background-color: transparent;
-            width: 100%;
-            height: 60px;
-          }
-        }
-
-        // .ant-input-affix-wrapper-focused {
-        //   box-shadow: none
-        // }
-      }
-
-      .loginBtn {
-        margin-top: 30px;
-
-        .ant-btn {
-          width: 100%;
-          font-size: 20px;
-          height: 50px;
-        }
-      }
+      z-index: 10;
+    }
 
+    .codeLoding {
+      position: absolute;
+      z-index: 100;
+      width: 100%;
+      height: 100%;
+      top: 0;
+      left: 0;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      color: #fff;
+      font-size: 24px;
+      letter-spacing: 4px;
     }
   }
-}
+}

+ 63 - 67
后台大场景编辑/src/pages/Login/index.tsx

@@ -1,78 +1,74 @@
-import styles from "./index.module.scss";
+import React, { useCallback, useEffect, useState } from 'react'
+import styles from './index.module.scss'
+import { Button } from 'antd'
+import { API_login, isTokenFlagAPI } from '@/store/action/A1List'
+import { MessageFu } from '@/utils/message'
+import { setTokenInfo } from '@/utils/storage'
+import history from '@/utils/history'
+function Login() {
+  const loginFu = useCallback(() => {
+    window.location.href = `https://dev.itfinspread.com:8003/#/sso?redirectUrl=${backUrl}`
+  }, [])
 
-import { Input, Button } from "antd";
-import { UserOutlined, LockOutlined } from "@ant-design/icons";
-import { useState } from "react";
-import { Base64 } from "js-base64";
-import encodeStr from "@/utils/pass";
-import { setTokenInfo } from "@/utils/storage";
-import history from "@/utils/history";
-import { MessageFu } from "@/utils/message";
-import { userLoginAPI } from "@/store/action/layout";
+  const [code, setCode] = useState('')
 
-export default function Login() {
-  // 账号密码
-  const [userName, setUserName] = useState("admin");
-  const [passWord, setPassWord] = useState("");
+  const getUserInfo = useCallback(async (code: string) => {
+    setCode(code)
+    try {
+      const res = await API_login({ code, redirectUrl: backUrl })
+      if (res.code === 0) {
+        if (res.data.token) {
+          MessageFu.success('登录成功')
+          // 用户信息存到本地
+          setTokenInfo(res.data)
+          window.location.href = '/#/list'
+        } else {
+          MessageFu.warning('token为空')
+          setCode('')
+        }
+      } else setCode('')
+    } catch (error) {
+      setCode('')
+    }
+  }, [])
 
-  // 键盘按下回车事件
-  const keyUpEntFu = (e: React.KeyboardEvent<HTMLInputElement>) => {
-    if (e.key === "Enter") loginClickFu();
-  };
-  // 点击登录
-  const loginClickFu = async () => {
-    // 非空判断
-    if (userName === "") return MessageFu.warning("请输入用户名!");
-    else if (passWord === "") return MessageFu.warning("请输入密码!");
-    const obj = {
-      userName,
-      passWord: encodeStr(Base64.encode(passWord)),
-    };
-    const res: any = await userLoginAPI(obj);
+  const checkTokenFu = useCallback(async () => {
+    // 检查token有效直接跳list页面
+    const res = await isTokenFlagAPI()
     if (res.code === 0) {
-      MessageFu.success("登录成功");
-      // 用户信息存到本地
-      setTokenInfo(res.data);
-      history.push("/");
-    } else if (res.code === 3014)
-      MessageFu.warning("用户名不存在或密码错误,请联系管理员!");
-  };
+      if (res.data) {
+        history.replace('/list')
+      }
+    }
+  }, [])
+
+  useEffect(() => {
+    // 创建 URLSearchParams 对象解析查询字符串
+    const searchParams = new URLSearchParams(window.location.search)
+    const code = searchParams.get('code') // 获取 code 参数
+    if (code) {
+      getUserInfo(code)
+    } else {
+      checkTokenFu()
+    }
+  }, [checkTokenFu, getUserInfo])
 
   return (
     <div className={styles.Login}>
-      <div className="main">
-        <h3>本地大场景管理</h3>
-        {/* 账号密码输入框 */}
-        <div className="inputBox">
-          <div className="inputBoxRow">
-            <Input
-              onKeyUp={(e) => keyUpEntFu(e)}
-              value={userName}
-              onChange={(e) => setUserName(e.target.value.trim())}
-              prefix={<UserOutlined />}
-              placeholder="请输入用户名"
-              maxLength={15}
-            />
-          </div>
-          <div className="inputBoxRow">
-            <Input.Password
-              onKeyUp={(e) => keyUpEntFu(e)}
-              value={passWord}
-              onChange={(e) => setPassWord(e.target.value.trim())}
-              prefix={<LockOutlined />}
-              placeholder="请输入用户密码"
-              maxLength={15}
-            />
-          </div>
-        </div>
+      <div className='LoginBtn'>
+        <Button type='primary' size='large' onClick={loginFu} hidden={!!code}>
+          孪生数字底座平台授权登录
+        </Button>
+      </div>
 
-        {/* 登录按钮 */}
-        <div className="loginBtn">
-          <Button type="primary" size="large" onClick={loginClickFu}>
-            登 录
-          </Button>
-        </div>
+      {/* 获取用户信息加载中 */}
+      <div className='codeLoding' hidden={!code}>
+        授权中,请稍后...
       </div>
     </div>
-  );
+  )
 }
+
+const MemoLogin = React.memo(Login)
+
+export default MemoLogin

+ 22 - 13
后台大场景编辑/src/store/action/A1List.ts

@@ -1,32 +1,41 @@
-import http from "@/utils/http";
-import { AppDispatch } from "..";
+import http from '@/utils/http'
+import { AppDispatch } from '..'
 /**
  * 获取用户管理表格列表
  */
-export const A1_APIgetList = (data: any) => {
+export const A1_APIgetList = (data: any): any => {
   return async (dispatch: AppDispatch) => {
-    const res = await http.post("cms/scene/list", data);
+    const res = await http.post('cms/scene/list', data)
     if (res.code === 0) {
       const obj = {
         list: res.data.records,
-        total: res.data.total,
-      };
+        total: res.data.total
+      }
 
-      dispatch({ type: "A1/getList", payload: obj });
+      dispatch({ type: 'A1/getList', payload: obj })
     }
-  };
-};
+  }
+}
 
 /**
  * 删除
  */
 export const A1_APIdel = (id: number) => {
-  return http.get(`cms/scene/removes/${id}`);
-};
+  return http.get(`cms/scene/removes/${id}`)
+}
 
 /**
  * 检查登录状态
  */
 export const isTokenFlagAPI = () => {
-  return http.get("/admin/checkLogin");
-};
+  return http.get('admin/checkLogin')
+}
+
+// -------------第三方平台授权登录------------
+
+/**
+ * 通过code获取token和别的用户信息
+ */
+export const API_login = (data: any) => {
+  return http.post('admin/ssoLogin', data)
+}

+ 20 - 20
后台大场景编辑/src/store/action/A9User.ts

@@ -1,54 +1,54 @@
-import { SaveUserType, UserTableAPIType } from "@/types";
-import http from "@/utils/http";
-import { AppDispatch } from "..";
+import { SaveUserType, UserTableAPIType } from '@/types'
+import http from '@/utils/http'
+import { AppDispatch } from '..'
 /**
  * 获取用户管理表格列表
  */
-export const A9API_getUserListAPI = (data: UserTableAPIType) => {
+export const A9API_getUserListAPI = (data: UserTableAPIType): any => {
   return async (dispatch: AppDispatch) => {
-    const res = await http.post("sys/user/list", data);
+    const res = await http.post('sys/user/list', data)
     if (res.code === 0) {
       const obj = {
         list: res.data.records,
-        total: res.data.total,
-      };
+        total: res.data.total
+      }
 
-      dispatch({ type: "user/getList", payload: obj });
+      dispatch({ type: 'user/getList', payload: obj })
     }
-  };
-};
+  }
+}
 
 /**
  * 用户-是否显示
  */
 export const A9API_userDisplayAPI = (id: number, display: number) => {
-  return http.get(`sys/user/editStatus/${id}/${display}`);
-};
+  return http.get(`sys/user/editStatus/${id}/${display}`)
+}
 
 /**
  * 删除用户
  */
 export const A9API_userRemoveAPI = (id: number) => {
-  return http.get(`sys/user/removes/${id}`);
-};
+  return http.get(`sys/user/removes/${id}`)
+}
 
 /**
  * 重置密码
  */
 export const A9API_userPassResetAPI = (id: number) => {
-  return http.get(`sys/user/resetPass/${id}`);
-};
+  return http.get(`sys/user/resetPass/${id}`)
+}
 
 /**
  * 新增/修改用户信息
  */
 export const A9API_userSaveAPI = (data: SaveUserType) => {
-  return http.post("sys/user/save", data);
-};
+  return http.post('sys/user/save', data)
+}
 
 /**
  * 通过id获取角色详情
  */
 export const A9API_getUserInfoByIdAPI = (id: number) => {
-  return http.get(`sys/user/detail/${id}`);
-};
+  return http.get(`sys/user/detail/${id}`)
+}

+ 7 - 6
后台大场景编辑/src/types/declaration.d.ts

@@ -1,6 +1,7 @@
-declare module "history";
-declare module "*.scss";
-declare module "*.png";
-declare module "*.jpg";
-declare module "*.gif";
-declare module "js-export-excel";
+declare module 'history'
+declare module '*.scss'
+declare module '*.png'
+declare module '*.jpg'
+declare module '*.gif'
+declare module 'js-export-excel'
+declare const backUrl: string

+ 41 - 44
后台大场景编辑/src/utils/http.ts

@@ -1,21 +1,19 @@
-import axios from "axios";
-import history from "./history";
-import { getTokenInfo, removeTokenInfo } from "./storage";
-import store from "@/store";
-import { MessageFu } from "./message";
-import { domShowFu } from "./domShow";
+import axios from 'axios'
+import history from './history'
+import { getTokenInfo, removeTokenInfo } from './storage'
+import store from '@/store'
+import { MessageFu } from './message'
+import { domShowFu } from './domShow'
 // 请求基地址
 export const baseURL =
   // 线下的图片地址需要加上/api/
-  // process.env.NODE_ENV === "development"
-  //   ? "http://192.168.20.55:8045/api/"
-  //   : "";
-  process.env.NODE_ENV === "development" ? "https://sit-locbigsecen.4dage.com" : "";
+  // process.env.NODE_ENV === 'development' ? 'http://192.168.20.61:8102/api/' : ''
+  process.env.NODE_ENV === 'development' ? 'https://sit-beirenbigscene.4dage.com' : ''
 
 // 处理  类型“AxiosResponse<any, any>”上不存在属性“code”
-declare module "axios" {
+declare module 'axios' {
   interface AxiosResponse {
-    code: number;
+    code: number
     // 这里追加你的参数
   }
 }
@@ -26,68 +24,67 @@ const http = axios.create({
   // baseURL: baseURL,
 
   // --------打包或线上环境接口需要加上api/
-  baseURL: baseURL + "/api/",
-  timeout: 5000,
-});
+  baseURL: baseURL + '/api/',
+  timeout: 10000
+})
 
-let axajInd = 0;
+let axajInd = 0
 
 // 请求拦截器
 http.interceptors.request.use(
   function (config: any) {
     // 发请求前打开加载提示
-    domShowFu("#AsyncSpinLoding", true);
+    domShowFu('#AsyncSpinLoding', true)
 
-    axajInd++;
+    axajInd++
 
-    const { token } = getTokenInfo();
-    if (token) config.headers.token = token;
-    return config;
+    const { token } = getTokenInfo()
+    if (token) config.headers.token = token
+    return config
   },
   function (err) {
-    return Promise.reject(err);
+    return Promise.reject(err)
   }
-);
+)
 
-let timeId = -1;
+let timeId = -1
 
 // 响应拦截器
 http.interceptors.response.use(
   function (response) {
     // 请求回来的关闭加载提示
-    axajInd--;
+    axajInd--
     if (axajInd === 0) {
-      domShowFu("#AsyncSpinLoding", false);
+      domShowFu('#AsyncSpinLoding', false)
     }
     if (response.data.code === 5001 || response.data.code === 5002) {
-      clearTimeout(timeId);
+      clearTimeout(timeId)
       timeId = window.setTimeout(() => {
-        removeTokenInfo();
-        MessageFu.warning("登录失效!");
-        history.push("/login");
-      }, 200);
+        removeTokenInfo()
+        MessageFu.warning('登录失效!')
+        history.push('/login')
+      }, 200)
     } else if (response.data.code === 0) {
       // MessageFu.success(response.data.msg);
-    } else MessageFu.warning(response.data.msg);
+    } else MessageFu.warning(response.data.msg)
 
-    return response.data;
+    return response.data
   },
   async function (err) {
-    clearTimeout(timeId);
+    clearTimeout(timeId)
     timeId = window.setTimeout(() => {
-      axajInd = 0;
-      domShowFu("#AsyncSpinLoding", false);
+      axajInd = 0
+      domShowFu('#AsyncSpinLoding', false)
       // 如果因为网络原因,response没有,给提示消息
       if (!err.response) {
-        if (store.getState().A0layout.closeUpFile.state)
-          MessageFu.warning("取消上传!");
-        else MessageFu.error("网络繁忙,请稍后重试!");
-      } else MessageFu.error("响应错误,请联系管理员!");
-    }, 100);
+        if (store.getState().A0layout.closeUpFile.state) MessageFu.warning('取消上传!')
+        else MessageFu.error('网络繁忙,请稍后重试!')
+      } else MessageFu.error('响应错误,请联系管理员!')
+    }, 100)
 
-    return Promise.reject(err);
+    return Promise.reject(err)
   }
-);
+)
 
 // 导出 axios 实例
-export default http;
+export default http

+ 1 - 2
后台大场景编辑/src/utils/storage.ts

@@ -1,7 +1,7 @@
 // ------------------------------------token的本地存储------------------------------------
 
 // 用户 Token 的本地缓存键名,自己定义
-const TOKEN_KEY = 'UNITYSCENE_HT_USER_INFO'
+const TOKEN_KEY = 'BEIJING_BEIREN_HT_USER_INFO'
 
 /**
  * 从本地缓存中获取 Token 信息
@@ -31,4 +31,3 @@ export const removeTokenInfo = (): void => {
 export const hasToken = (): boolean => {
   return Boolean(getTokenInfo().token)
 }
-