diff --git a/.eslintrc.js b/.eslintrc.js index 051199c..53cc55c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -35,6 +35,7 @@ module.exports = { 'import/no-unresolved': 'off', 'import/order': 'off', 'import/prefer-default-export': 'off', + 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], // 关闭variable必须全部大写规则 '@typescript-eslint/naming-convention': [ 'error', diff --git a/package.json b/package.json index 5f1c427..d411db4 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@types/lodash": "^4.14.178", "@types/mockjs": "^1.0.6", "@types/node": "^16.11.18", + "@types/qrcode.react": "^1.0.2", "@types/react": "^17.0.38", "@types/react-dom": "^17.0.11", "@types/react-router-dom": "^5.3.2", @@ -49,6 +50,7 @@ "echarts-for-react": "^3.0.2", "lodash": "^4.17.21", "mockjs": "^1.1.0", + "qrcode.react": "^2.0.0", "query-string": "^6.12.0", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/src/assets/image/assets-login-bg-black.png b/src/assets/image/assets-login-bg-black.png new file mode 100644 index 0000000..b4dde4b Binary files /dev/null and b/src/assets/image/assets-login-bg-black.png differ diff --git a/src/assets/image/assets-login-bg-white.png b/src/assets/image/assets-login-bg-white.png new file mode 100644 index 0000000..4275549 Binary files /dev/null and b/src/assets/image/assets-login-bg-white.png differ diff --git a/src/assets/svg/assets-logo-full.svg b/src/assets/svg/assets-logo-full.svg new file mode 100644 index 0000000..94f0049 --- /dev/null +++ b/src/assets/svg/assets-logo-full.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/configs/menu.ts b/src/configs/menu.ts index 4753d92..6286365 100644 --- a/src/configs/menu.ts +++ b/src/configs/menu.ts @@ -6,6 +6,8 @@ import { LayersIcon, CheckCircleIcon, UserCircleIcon, + LogoutIcon, + RootListIcon, } from 'tdesign-icons-react'; export interface IMenuItem { @@ -154,10 +156,22 @@ export const menu: IMenuItem[] = [ }, ], }, + { + key: 'login', + label: '登录页', + Icon: LogoutIcon, + children: [ + { + key: '/login/index', + label: '登录中心', + path: '/login', + }, + ], + }, { key: 'level1', label: '一级菜单', - Icon: UserCircleIcon, + Icon: RootListIcon, children: [ { key: '/level1/level2', diff --git a/src/configs/routes.ts b/src/configs/routes.ts index 1c26bd9..ed8b1fd 100644 --- a/src/configs/routes.ts +++ b/src/configs/routes.ts @@ -19,6 +19,7 @@ import Result403 from 'pages/Result/403'; import Result404 from 'pages/Result/404'; import Result500 from 'pages/Result/500'; import ResultBrowserIncompatible from 'pages/Result/BrowserIncompatible'; +import Login from 'pages/Login'; interface IRouteItem { key?: string; @@ -26,6 +27,7 @@ interface IRouteItem { exact?: boolean; isHome?: boolean; Component: React.FC; + isFullPage?: boolean; } export const routes: IRouteItem[] = [ @@ -106,4 +108,9 @@ export const routes: IRouteItem[] = [ path: '/result/browser-incompatible', Component: ResultBrowserIncompatible, }, + { + path: '/login', + Component: Login, + isFullPage: true, + }, ]; diff --git a/src/layouts/components/Container.tsx b/src/layouts/components/Container.tsx index a84a782..85c1016 100644 --- a/src/layouts/components/Container.tsx +++ b/src/layouts/components/Container.tsx @@ -2,38 +2,37 @@ import React from 'react'; import { Layout } from 'tdesign-react'; import { ELayout } from 'modules/global'; import Header from './Header'; -import Content from './Content'; import Footer from './Footer'; import Menu from './Menu'; import Style from './Content.module.less'; -const SideLayout = React.memo(() => ( +const SideLayout = React.memo(({ children }: { children: React.ReactNode }) => ( - + {children} )); -const TopLayout = React.memo(() => ( +const TopLayout = React.memo(({ children }: { children: React.ReactNode }) => ( - + {children} )); -const MixLayout = React.memo(() => ( +const MixLayout = React.memo(({ children }: { children: React.ReactNode }) => ( - + {children} diff --git a/src/layouts/components/Content.tsx b/src/layouts/components/Content.tsx index 92bd716..70208bb 100644 --- a/src/layouts/components/Content.tsx +++ b/src/layouts/components/Content.tsx @@ -2,21 +2,40 @@ import React from 'react'; import { Switch, Route, Redirect } from 'react-router-dom'; import { Layout } from 'tdesign-react'; import { routes } from 'configs/routes'; +import { useAppSelector } from 'modules/store'; +import { selectGlobal } from 'modules/global'; import UnAuthorized from 'pages/Result/403'; import NotFound from 'pages/Result/404'; import ServerError from 'pages/Result/500'; +import LayoutMap from './Container'; const { Content } = Layout; export default React.memo(() => { const home = routes.find((item) => item.isHome); + const globalState = useAppSelector(selectGlobal); + const Container = LayoutMap[globalState.layout]; return ( {home && } - {routes.map((route, index) => ( - - ))} + {routes.map((route, index) => { + const { Component } = route; + return route.isFullPage ? ( + + ) : ( + ( + + + + )} + /> + ); + })} diff --git a/src/layouts/components/HeaderIcon.module.less b/src/layouts/components/HeaderIcon.module.less index 9c25be1..407d79a 100644 --- a/src/layouts/components/HeaderIcon.module.less +++ b/src/layouts/components/HeaderIcon.module.less @@ -1,8 +1,15 @@ .dropdown { :global { .t-dropdown__item { - max-width: none!important; + max-width: none !important; width: 117px; + &-text { + display: flex; + align-items: center; + } + .t-icon { + margin-right: 8px; + } } } } diff --git a/src/layouts/components/HeaderIcon.tsx b/src/layouts/components/HeaderIcon.tsx index 34c585f..412fe6b 100644 --- a/src/layouts/components/HeaderIcon.tsx +++ b/src/layouts/components/HeaderIcon.tsx @@ -1,11 +1,22 @@ import React, { memo } from 'react'; import { useHistory } from 'react-router-dom'; import { Button, Popup, Badge, Dropdown, Row, Col } from 'tdesign-react'; -import { Icon, LogoGithubIcon, MailIcon, HelpCircleIcon, SettingIcon } from 'tdesign-icons-react'; +import { + Icon, + LogoGithubIcon, + MailIcon, + HelpCircleIcon, + SettingIcon, + PoweroffIcon, + UserCircleIcon, +} from 'tdesign-icons-react'; import { useAppDispatch } from 'modules/store'; import { toggleSetting } from 'modules/global'; +import { logout } from 'modules/user'; import Style from './HeaderIcon.module.less'; +const { DropdownMenu, DropdownItem } = Dropdown; + export default memo(() => { const dispatch = useAppDispatch(); const history = useHistory(); @@ -18,22 +29,15 @@ export default memo(() => { window.open('https://github.com/Tencent/tdesign-react-starter'); }; - const options = [ - { - content: '个人中心', - value: 1, - }, - { - content: '退出登录', - value: 2, - }, - ]; - const clickHandler = (data: any) => { if (data.value === 1) { history.push('/user/index'); } }; + const handleLogout = async () => { + await dispatch(logout()); + history.push('/login/index'); + }; return ( @@ -59,7 +63,7 @@ export default memo(() => { - + @@ -67,6 +71,20 @@ export default memo(() => { + + + <> + + 个人中心 + > + + + <> + + 退出登录 + > + + diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx index baee407..8220c39 100644 --- a/src/layouts/index.tsx +++ b/src/layouts/index.tsx @@ -4,7 +4,7 @@ import throttle from 'lodash/throttle'; import { useAppSelector, useAppDispatch } from 'modules/store'; import { selectGlobal, toggleSetting, toggleMenu } from 'modules/global'; import Setting from './components/Setting'; -import LayoutMap from './components/Container'; +import Content from './components/Content'; import Style from './index.module.less'; export default memo(() => { @@ -25,11 +25,9 @@ export default memo(() => { }; }, []); - const Container = LayoutMap[globalState.layout]; - return ( - + ) => { + const mockLogin = async (userInfo: Record) => { + // 登录请求流程 + console.log(userInfo); + // const { account, password } = userInfo; + // if (account !== 'td') { + // return { + // code: 401, + // message: '账号不存在', + // }; + // } + // if (['main_', 'dev_'].indexOf(password) === -1) { + // return { + // code: 401, + // message: '密码错误', + // }; + // } + // const token = { + // main_: 'main_token', + // dev_: 'dev_token', + // }[password]; + return { + code: 200, + message: '登陆成功', + data: 'main_token', + }; + }; + + const res = await mockLogin(userInfo); + if (res.code === 200) { + return res.data; + } + throw res; +}); + +// getUserInfo +export const getUserInfo = createAsyncThunk(`${namespace}/getUserInfo`, async (_, { getState }: any) => { + const { token } = getState(); + const mockRemoteUserInfo = async (token: string) => { + if (token === 'main_token') { + return { + name: 'td_main', + roles: ['all'], + }; + } + return { + name: 'td_dev', + roles: ['userIndex', 'dashboardBase', 'login'], + }; + }; + + const res = await mockRemoteUserInfo(token); + + return res; +}); + +const userSlice = createSlice({ + name: namespace, + initialState, + reducers: { + logout: (state) => { + localStorage.removeItem(TOKEN_NAME); + state.token = ''; + state.userInfo = {}; + }, + remove: (state) => { + state.token = ''; + }, + }, + extraReducers: (builder) => { + builder + .addCase(login.fulfilled, (state, action) => { + localStorage.setItem(TOKEN_NAME, action.payload); + + state.token = action.payload; + }) + .addCase(getUserInfo.fulfilled, (state, action) => { + state.userInfo = action.payload; + }); + }, +}); + +export const selectListBase = (state: RootState) => state.listBase; + +export const { logout, remove } = userSlice.actions; + +export default userSlice.reducer; diff --git a/src/pages/Login/components/Header/index.module.less b/src/pages/Login/components/Header/index.module.less new file mode 100644 index 0000000..be10d78 --- /dev/null +++ b/src/pages/Login/components/Header/index.module.less @@ -0,0 +1,37 @@ +.loginHeader { + height: 64px; + padding: 0 24px; + display: flex; + justify-content: space-between; + align-items: center; + backdrop-filter: blur(5px); + color: var(--td-text-color-primary); +} + +.logo { + width: 188px; + height: 64px; +} + +.operationsContainer { + display: flex; + align-items: center; + .t-button { + margin-left: 16px; + } +} + +.operationsButton { + margin-left: 16px; +} + +.icon { + height: 20px; + width: 20px; + padding: 6px; + box-sizing: content-box; + + &:hover { + cursor: pointer; + } +} diff --git a/src/pages/Login/components/Header/index.tsx b/src/pages/Login/components/Header/index.tsx new file mode 100644 index 0000000..1a17f9d --- /dev/null +++ b/src/pages/Login/components/Header/index.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { Button } from 'tdesign-react'; +import { LogoGithubIcon, HelpCircleIcon, SettingIcon } from 'tdesign-icons-react'; +import { useAppDispatch } from 'modules/store'; +import { toggleSetting } from 'modules/global'; + +import LogoFullIcon from 'assets/svg/assets-logo-full.svg?component'; +import Style from './index.module.less'; + +export default function Header() { + const dispatch = useAppDispatch(); + + const navToGitHub = () => { + window.open('https://github.com/tencent/tdesign-react-starter'); + }; + + const navToHelper = () => { + window.open('http://tdesign.tencent.com/starter/docs/react/get-started'); + }; + + const toggleSettingPanel = () => { + dispatch(toggleSetting()); + }; + + return ( + + + + + + + + + + + + + + + + + ); +} diff --git a/src/pages/Login/components/Login/index.module.less b/src/pages/Login/components/Login/index.module.less new file mode 100644 index 0000000..5a69af9 --- /dev/null +++ b/src/pages/Login/components/Login/index.module.less @@ -0,0 +1,102 @@ +.itemContainer { + width: 400px; + margin-top: 48px; +} + +.checkContainer { + display: flex; + align-items: center; + font-size: 14px; + color: var(--td-text-color-secondary); + + &.rememberPwd { + margin-bottom: 16px; + justify-content: space-between; + } + + :global { + .t-checkbox__label { + color: var(--td-text-color-secondary); + } + + span { + color: var(--td-brand-color); + + &:hover { + cursor: pointer; + } + } + } +} + +.tipContainer { + width: 192px; + margin-bottom: 16px; + font-size: 14px; + display: flex; + justify-content: space-between; + + :global { + .tip { + color: var(--td-text-color-primary); + } + + .refresh { + display: flex; + align-items: center; + color: var(--td-brand-color); + + .t-icon { + font-size: 14px; + margin-left: 4px; + } + + &:hover { + cursor: pointer; + } + } + } +} + +.checkContainerTip { + float: right; + font-size: 14px; + color: var(--td-brand-color); +} + +.verificationBtn { + flex-shrink: 0; + width: 102px; + height: 40px; + margin-left: 11px; +} + +.btnContainer { + margin-top: 48px; +} + +.switchContainer { + margin-top: 24px; + + :global { + .tip { + font-size: 14px; + color: var(--td-brand-color); + cursor: pointer; + display: inline-flex; + align-items: center; + margin-right: 14px; + + &:not(:last-child) { + &::after { + content: ''; + display: block; + width: 1px; + height: 12px; + background: var(--td-gray-color-3); + margin-left: 14px; + } + } + } + } +} diff --git a/src/pages/Login/components/Login/index.tsx b/src/pages/Login/components/Login/index.tsx new file mode 100644 index 0000000..87943f0 --- /dev/null +++ b/src/pages/Login/components/Login/index.tsx @@ -0,0 +1,141 @@ +import React, { useState, useRef } from 'react'; +import classnames from 'classnames'; +import { Form, MessagePlugin, Input, Checkbox, Button, FormInstanceFunctions, SubmitContext } from 'tdesign-react'; +import { LockOnIcon, UserIcon, BrowseOffIcon, BrowseIcon, RefreshIcon } from 'tdesign-icons-react'; +import { useAppDispatch } from 'modules/store'; +import QRCode from 'qrcode.react'; + +import useCountdown from '../../hooks/useCountDown'; +import { useHistory } from 'react-router-dom'; +import { login } from 'modules/user'; + +import Style from './index.module.less'; + +const { FormItem } = Form; + +export type ELoginType = 'password' | 'phone' | 'qrcode'; + +export default function Login() { + const [loginType, changeLoginType] = useState('password'); + const [showPsw, toggleShowPsw] = useState(false); + const { countdown, setupCountdown } = useCountdown(60); + const formRef = useRef(); + const history = useHistory(); + const dispatch = useAppDispatch(); + + const onSubmit = async (e: SubmitContext) => { + if (e.validateResult === true) { + try { + const formValue = formRef.current?.getFieldsValue?.(true) || {}; + await dispatch(login(formValue)); + + MessagePlugin.success('登录成功'); + + history.push('/dashboard/base'); + } catch (e) { + console.log(e); + MessagePlugin.error('登录失败'); + } + } + }; + + const switchType = (val: ELoginType) => { + formRef.current?.reset?.(); + changeLoginType(val); + }; + + return ( + + + {loginType === 'password' && ( + <> + + }> + + + } + suffixIcon={ + showPsw ? ( + toggleShowPsw((current) => !current)} /> + ) : ( + toggleShowPsw((current) => !current)} /> + ) + } + /> + + + 记住账号 + 忘记账号? + + > + )} + + {/* 扫码登陆 */} + {loginType === 'qrcode' && ( + <> + + 请使用微信扫一扫登录 + + 刷新 + + + + > + )} + {/* // 手机号登陆 */} + {loginType === 'phone' && ( + <> + + } /> + + + + 0} + onClick={setupCountdown} + > + {countdown === 0 ? '发送验证码' : `${countdown}秒后可重发`} + + + > + )} + {loginType !== 'qrcode' && ( + + + 登录 + + + )} + + {loginType !== 'password' && ( + switchType('password')}> + 使用账号密码登录 + + )} + {loginType !== 'qrcode' && ( + switchType('qrcode')}> + 使用微信扫码登录 + + )} + {loginType !== 'phone' && ( + switchType('phone')}> + 使用手机号登录 + + )} + + + + ); +} diff --git a/src/pages/Login/components/Register/index.module.less b/src/pages/Login/components/Register/index.module.less new file mode 100644 index 0000000..f3e5380 --- /dev/null +++ b/src/pages/Login/components/Register/index.module.less @@ -0,0 +1,36 @@ +.itemContainer { + width: 400px; + margin-top: 48px; +} + +.verificationBtn { + flex-shrink: 0; + width: 102px; + height: 40px; + margin-left: 11px; +} + +.switchContainer { + margin-top: 24px; +} + +.switchTip { + font-size: 14px; + color: var(--td-brand-color); + cursor: pointer; + display: inline-flex; + align-items: center; + margin-right: 14px; +} + +.checkContainer { + font-size: 14px; + color: var(--td-text-color-secondary); + :global { + .tip { + float: right; + font-size: 14px; + color: var(--td-brand-color); + } + } +} diff --git a/src/pages/Login/components/Register/index.tsx b/src/pages/Login/components/Register/index.tsx new file mode 100644 index 0000000..c656bea --- /dev/null +++ b/src/pages/Login/components/Register/index.tsx @@ -0,0 +1,107 @@ +import React, { useState, useRef } from 'react'; +import classnames from 'classnames'; +import { Form, MessagePlugin, Input, Checkbox, Button, FormInstanceFunctions, SubmitContext } from 'tdesign-react'; +import { LockOnIcon, UserIcon, MailIcon, BrowseOffIcon, BrowseIcon } from 'tdesign-icons-react'; +import useCountdown from '../../hooks/useCountDown'; + +import Style from './index.module.less'; + +const { FormItem } = Form; + +export type ERegisterType = 'phone' | 'email'; + +export default function Register() { + const [registerType, changeRegisterType] = useState('phone'); + const [showPsw, toggleShowPsw] = useState(false); + const { countdown, setupCountdown } = useCountdown(60); + const formRef = useRef(); + + const onSubmit = (e: SubmitContext) => { + if (e.validateResult === true) { + const { checked } = formRef.current?.getFieldsValue?.(['checked']) as { checked: boolean }; + if (!checked) { + MessagePlugin.error('请同意 TDesign 服务协议和 TDesign 隐私声明'); + return; + } + MessagePlugin.success('注册成功'); + } + }; + + const switchType = (val: ERegisterType) => { + formRef.current?.reset?.(); + changeRegisterType(val); + }; + + return ( + + + {registerType === 'phone' && ( + + } /> + + )} + + {registerType === 'email' && ( + + } /> + + )} + + + } + suffixIcon={ + showPsw ? ( + toggleShowPsw((current) => !current)} /> + ) : ( + toggleShowPsw((current) => !current)} /> + ) + } + /> + + {registerType === 'phone' && ( + + + 0} + onClick={setupCountdown} + > + {countdown === 0 ? '发送验证码' : `${countdown}秒后可重发`} + + + )} + + 我已阅读并同意 TDesign服务协议 和 + TDesign 隐私声明 + + + + 注册 + + + + switchType(registerType === 'phone' ? 'email' : 'phone')}> + {registerType === 'phone' ? '使用邮箱注册' : '使用手机号注册'} + + + + + ); +} diff --git a/src/pages/Login/hooks/useCountDown.ts b/src/pages/Login/hooks/useCountDown.ts new file mode 100644 index 0000000..3b806d5 --- /dev/null +++ b/src/pages/Login/hooks/useCountDown.ts @@ -0,0 +1,32 @@ +import { useState, useEffect, useRef } from 'react'; + +const useCountdown = (duration: number) => { + const [countdown, setCountdown] = useState(0); + const [isSetup, toggleSetup] = useState(false); + const timer = useRef(); + + useEffect(() => { + if (isSetup) { + setCountdown(duration); + timer.current = setInterval(() => { + setCountdown((current) => current - 1); + }, 1000); + } else clearInterval(timer.current as NodeJS.Timeout); + }, [isSetup]); + + useEffect(() => { + if (countdown === 0) { + toggleSetup(false); + } + }, [countdown]); + + useEffect(() => () => clearInterval(timer.current as NodeJS.Timeout), []); + + function setupCountdown() { + toggleSetup(true); + } + + return { countdown, setupCountdown }; +}; + +export default useCountdown; diff --git a/src/pages/Login/index.module.less b/src/pages/Login/index.module.less new file mode 100644 index 0000000..c827931 --- /dev/null +++ b/src/pages/Login/index.module.less @@ -0,0 +1,67 @@ +.loginWrapper { + height: 100vh; + display: flex; + flex-direction: column; + background-size: cover; + background-position: 100%; + position: relative; + &.dark { + background-color: var(--td-bg-color-page); + background-image: url('assets/image/assets-login-bg-black.png'); + } + &.light { + background-color: white; + background-image: url('assets/image/assets-login-bg-white.png'); + } +} + +.loginContainer { + position: absolute; + top: 22%; + left: 5%; + min-height: 500px; + line-height: 22px; +} + +.title { + font-size: 36px; + line-height: 44px; + color: var(--td-text-color-primary); + margin-top: 4px; + margin-bottom: 0; +} + +.subTitle { + margin-top: 16px; +} + +.tip { + display: inline-block; + margin-right: 8px; + font-size: 14px; + margin-top: 0; + margin-bottom: 0; + + &.registerTip { + color: var(--td-text-color-secondary); + } + + &.loginTip { + color: var(--td-text-color-primary); + cursor: pointer; + } +} + +.copyright { + font-size: 14px; + position: absolute; + left: 5%; + bottom: 64px; + color: var(--td-text-color-secondary); +} + +@media screen and (max-height: 700px) { + .copyright { + display: none; + } +} diff --git a/src/pages/Login/index.tsx b/src/pages/Login/index.tsx new file mode 100644 index 0000000..8710812 --- /dev/null +++ b/src/pages/Login/index.tsx @@ -0,0 +1,42 @@ +import React, { memo, useState } from 'react'; +import classNames from 'classnames'; +import Login from './components/Login'; +import Register from './components/Register'; +import LoginHeader from './components/Header'; +import { useAppSelector } from 'modules/store'; +import { selectGlobal } from 'modules/global'; + +import Style from './index.module.less'; + +export default memo(() => { + const [type, setType] = useState('login'); + const globalState = useAppSelector(selectGlobal); + const { theme } = globalState; + const handleSwitchLoginType = () => { + setType(type === 'register' ? 'login' : 'register'); + }; + + return ( + + + + + 登录到 + TDesign Starter + + + {type === 'register' ? '已有账号?' : '没有账号吗?'} + + + {type === 'register' ? '登录' : '注册新账号'} + + + + {type === 'login' ? : } + + + + ); +}); diff --git a/src/styles/index.less b/src/styles/index.less index 2e5574f..08df376 100644 --- a/src/styles/index.less +++ b/src/styles/index.less @@ -1,19 +1,17 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', + 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } -html, body, #app { +html, +body, +#app { height: 100%; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } - - diff --git a/vite.config.js b/vite.config.js index acc2535..6dbd45b 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,60 +1,58 @@ -import { viteMockServe } from 'vite-plugin-mock'; import path from 'path'; +import { viteMockServe } from 'vite-plugin-mock'; import react from '@vitejs/plugin-react'; import svgr from '@honkhonk/vite-plugin-svgr'; -export default (params) => { - return { - base: './', - resolve: { - alias: { - assets: path.resolve(__dirname, './src/assets'), - components: path.resolve(__dirname, './src/components'), - configs: path.resolve(__dirname, './src/configs'), - layouts: path.resolve(__dirname, './src/layouts'), - modules: path.resolve(__dirname, './src/modules'), - pages: path.resolve(__dirname, './src/pages'), - styles: path.resolve(__dirname, './src/styles'), - utils: path.resolve(__dirname, './src/utils'), - services: path.resolve(__dirname, './src/services'), - }, +export default (params) => ({ + base: './', + resolve: { + alias: { + assets: path.resolve(__dirname, './src/assets'), + components: path.resolve(__dirname, './src/components'), + configs: path.resolve(__dirname, './src/configs'), + layouts: path.resolve(__dirname, './src/layouts'), + modules: path.resolve(__dirname, './src/modules'), + pages: path.resolve(__dirname, './src/pages'), + styles: path.resolve(__dirname, './src/styles'), + utils: path.resolve(__dirname, './src/utils'), + services: path.resolve(__dirname, './src/services'), }, + }, - css: { - preprocessorOptions: { - less: { - modifyVars: { - // 如需自定义组件其他 token, 在此处配置 - }, + css: { + preprocessorOptions: { + less: { + modifyVars: { + // 如需自定义组件其他 token, 在此处配置 }, }, }, + }, - plugins: [ - svgr(), - react(), - params.mode === 'mock' && - viteMockServe({ - mockPath: './mock', - localEnabled: true, - }), - ], + plugins: [ + svgr(), + react(), + params.mode === 'mock' && + viteMockServe({ + mockPath: './mock', + localEnabled: true, + }), + ], - build: { - cssCodeSplit: false, - }, + build: { + cssCodeSplit: false, + }, - server: { - host: '0.0.0.0', - port: 3003, - proxy: { - '/api': { - // 用于开发环境下的转发请求 - // 更多请参考:https://vitejs.dev/config/#server-proxy - target: 'https://service-exndqyuk-1257786608.gz.apigw.tencentcs.com', - changeOrigin: true, - }, + server: { + host: '0.0.0.0', + port: 3003, + proxy: { + '/api': { + // 用于开发环境下的转发请求 + // 更多请参考:https://vitejs.dev/config/#server-proxy + target: 'https://service-exndqyuk-1257786608.gz.apigw.tencentcs.com', + changeOrigin: true, }, }, - }; -}; + }, +});
+ {type === 'register' ? '已有账号?' : '没有账号吗?'} +
+ {type === 'register' ? '登录' : '注册新账号'} +