Commit 071b98f7 by zhangleyuan

feat:调整路由模块

parent 77caae47
......@@ -61,6 +61,7 @@
"postcss-safe-parser": "4.0.1",
"react": "^16.13.1",
"react-app-polyfill": "^1.0.6",
"react-async-component": "^2.0.0",
"react-dev-utils": "^10.2.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
......
import React from 'react';
import { Route } from 'react-router-dom';
import { Layout,ConfigProvider } from 'antd';
import { RouteConfig } from '@/routes/interface';
import Header from './modules/root/Header'
import Main from './modules/root/Main'
import Menu from './modules/root/Menu'
import zhCN from 'antd/es/locale/zh_CN'
const { Content } = Layout;
class App extends React.Component {
render() {
return (
<div id="home">
<Header/>
<ConfigProvider locale={zhCN}>
<Main/>
</ConfigProvider>
<Menu/>
</div>
)
}
}
export default App;
\ No newline at end of file
......@@ -13,8 +13,7 @@ import { ConfigProvider } from 'antd';
import { createHashHistory } from 'history';
import zh_CN from 'antd/es/locale/zh_CN';
import _ from 'underscore';
import { RootRouter } from './routes/index';
import 'antd/dist/antd.less';
import '@/common/less/index.less';
......@@ -41,13 +40,9 @@ window.RCHistory = _.extend({}, history, {
}
});
export async function mount() {
ReactDOM.render((
<HashRouter {...history} >
<ConfigProvider locale={zh_CN}>
<App/>
</ConfigProvider>
</HashRouter>
), document.getElementById('root'));
ReactDOM.render(
<RootRouter/>,
document.getElementById('root'));
}
mount()
\ No newline at end of file
import React from 'react';
class PrepareLessonPage extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<div className="prepare-lesson-page page">
<div className="content-header">资料云盘</div>
<div className="box content-body">
</div>
</div>
)
}
}
export default PrepareLessonPage;
\ No newline at end of file
import React, { useEffect, useRef, useState } from 'react';
import qs from 'qs';
import {
withRouter
} from 'react-router-dom';
import './Login.less';
import md5 from 'blueimp-md5';
import { message, Row, Col, Tabs, Input, Button, Popover , Select } from 'antd';
import originAxios from 'axios';
import CheckBeforeSendCode from '../../components/CheckBeforeSendCode';
const {Option} = Select;
const {TabPane} = Tabs;
const GH = require('../../images/guohui.png')
function Login(props) {
const initApi = LS.get('DRURL') || '';
const [api, setApi] = useState(initApi);
const [drList, setDrList] = useState([]); // 线路列表
const [loginStyle, setLoginStyle] = useState('passwordLogin');// 登录方式
const [showPassword, setShowPassword] = useState(false);// 显示密码
const [phone, setPhone] = useState(''); // 登录手机号
const [password, setPwd] = useState(''); // 密码
const [phoneverify, setPhoneverify] = useState(''); // 密码登录验证码
const [certificate, setCertificate] = useState(''); // 语音电话参数
const [instName, setInstName] = useState(''); // 免费试用机构名字
const [regPhone, setRegPhone] = useState(''); // 免费试用手机号
const [code, setCode] = useState(''); // 免费试用验证码
const [btnText, setBtnText] = useState('登录'); // 登录按钮文本
const [btnDisabled, setBtnDisabled] = useState(false); // 登录按钮禁用状态
const [modalVisible, setModalVisible] = useState(false); // 注册弹窗可见状态
const [voiceCodeTip, setVoiceCodeTip] = useState(false); // 语音验证码提示状态
const [codeText, setCodeText] = useState('获取验证码'); // 验证码提示语
const [waitStatus, setWaitStatus] = useState(false); // 验证码是否在倒计时
const [regBtnText, setRegBtnText] = useState('提交'); // 注册弹窗按钮文本
const [regBtnDisabled, setRegBtnDisabled] = useState(false) // 注册按钮禁用状态
const [regCodeText, setRegCodeText] = useState('获取验证码'); // 注册弹窗文本
const [userType, setUserType] = useState('B'); // 账号类型 B or CRM_INST
const [regWaitStatus, setRegWaitStatus] = useState(false); // 验证码是否在倒计时
const [regVoiceCodeTip, setRegVoiceCodeTip] = useState(false); // 语音验证码提示状态
const [openCheck1, setOpenCheck1] = useState(false);
const [openCheck2, setOpenCheck2] = useState(false);
const [openCheck3, setOpenCheck3] = useState(false);
const [openCheck4, setOpenCheck4] = useState(false);
const [checking1, setChecking1] = useState(false);
const [checking3, setChecking3] = useState(false);
const [checkObject1, setCheckObject1] = useState({});
const [checkObject2, setCheckObject2] = useState({});
const [checkObject3, setCheckObject3] = useState({});
const [checkObject4, setCheckObject4] = useState({});
useEffect(() => {
getDrList();
window.WEBTRACING('Web_B_LoginPage_View', '曝光事件_首页_WebB_打开登录页');
// 默认
const sear = props.location.search
if(sear){
const urlParams = qs.parse(props.location.search.substr(1))
if(urlParams.tab=== "code"){
setLoginStyle("phoneverifyLogin")
}
if(urlParams.phone){
setPhone(urlParams.phone)
}
}
}, [])
function getDrList() {
originAxios.get('https://res.xiaomai5.com/devops/xmRouteConfig/xmRouteB.conf?spm=5176.8466032.0.dopenurl.218a1450V7oSvA&file=xmRouteB.conf').then((res) => {
setDrList(res.data.routes);
}).catch(() => { })
document.title = "机构管理端登录|小麦助教";
}
async function handleLogin(e) {
const ifVerifyLogin = (loginStyle == 'phoneverifyLogin');
e.preventDefault();
const data = {
account: phone,
pwd: password,
phoneverify
};
if (!data.account) {
setBtnText('请输入手机号');
setBtnDisabled(true);
setTimeout(function () {
setBtnText('登录');
setBtnDisabled(false);
}, 1500);
return;
}
if (data.account.length != 11) {
message.warning('请输入11位长度手机号')
return;
}
if (ifVerifyLogin) {
if (!data.phoneverify) {
setBtnText('无有效验证码,请先获取短信验证码');
setBtnDisabled(true);
setTimeout(function () {
setBtnText('登录');
setBtnDisabled(false);
}, 1500);
return;
}
} else if (!data.pwd) {
setBtnText('请输入密码');
setBtnDisabled(true);
setTimeout(function () {
setBtnText('登录');
setBtnDisabled(false);
}, 1500);
return;
}
data.pwd = md5(data.pwd);
const param = {
accountNo: data.account,
certificate: ifVerifyLogin ? data.phoneverify : data.pwd,
appTerm: 'PC',
loginType: ifVerifyLogin ? 'PHONE_AUTH_CODE' : 'PHONE_PWD'
}
setBtnText('登录中...');
setBtnDisabled(true);
setTimeout(() => {
setBtnText('登录');
setBtnDisabled(false);
}, 3000);
const option = {
sync: true, noCache: true, userType, success: (res) => {
if (typeof res === 'object') {
if (res.code == '200' && !res.result.exists) { // 非机构用户
setRegPhone(data.account)
setModalVisible(true)
return
}
switch (res.code) {
// 成功
case "200":
window.location.reload();
window.WEBTRACING('Web_B_LoginPage_Loginin', '曝光事件_首页_WebB_登陆成功');
localStorage.removeItem('xmsy');
window.LS.set('isCrmInstAdmin', false); // 机构后台账号
var storageDate = window.LS.get('storageDate');
if (storageDate != CONFIG.cacheUpdateTime) {
const apis = localStorage.getItem('server-apis');
// window.LS.clear();
window.LS.set('storageDate', CONFIG.cacheUpdateTime);
if (apis) {
localStorage.setItem('server-apis', apis)
}
}
window.LS.set('token', res.result.xmToken);
window.LS.set('uid', res.result.userId);
window.LS.set('uPhone', /^\d{11}$/.test(data.account) ? data
.account : '');
window.LS.set('crmInstIds', JSON.stringify(res.result.crmInstIds));
if (res.result.userType === 'CRM_INST') {
window.LS.set('isCrmInstAdmin', true); // 机构后台账号
window.RCHistory.push({
pathname: `/campus_panel`,
})
} else if (res.result.isCenterAccount && process.env.DEPLOY_ENV !== 'beta') {
window.LS.set('hasCenter', true);
if (process.env.DEPLOY_ENV === 'dev1') {
location.href = `${location.origin }/dev1/center/index.html${ drLink ? '?type=dr' : ''}`;
} else if (process.env.DEPLOY_ENV === 'gray') {
location.href = `${location.origin }/center/gray/index.html${ drLink ? '?type=dr' : ''}`;
} else {
location.href = `${location.origin }/center/index.html${ drLink ? '?type=dr' : ''}`;
}
} else {
window.RCHistory.push({
pathname: `/`,
})
}
break;
// token非法
case '404':
break;
// 手机号,密码错误
case '500':
setBtnText('手机号或密码错误');
setBtnDisabled(true);
setTimeout(function () {
setBtnText('登录');
setBtnDisabled(false);
}, 1500);
break;
default:
setBtnText(res.message);
setBtnDisabled(true);
setTimeout(function () {
setBtnText('登录');
setBtnDisabled(false);
}, 1500);
break;
}
}
}
}
axios.postJSON('business/anon/b/login', param, option)
}
function handleSendSMSCode(checkData, userType) {
if (waitStatus) return;
const phoneLength = phone.trim().length;
const params = {
phone,
sig: checkData.sig,
sessionId: checkData.csessionid,
token: checkData.token,
scene: 'nc_login',
serverType: 'B_LOGIN',
sideType: 0,
};
if (userType === 'CRM_INST') {
params.serverType = 'CRM_INST';
};
axios.postJSON('business/anon/sms/sendSmsCode', params, { reject: true }).then((res) => {
if (!res.success) {
message.warning(res.message);
} else {
timeSub(60);
setChecking1(true)
setCertificate(res.result);
}
})
let timer;
function timeSub(waitTime, unit) {
clearTimeout(timer);
timer = setTimeout(function () {
if (waitTime == 0) {
setCodeText('发送验证码')
setChecking1(false)
setWaitStatus(false)
clearTimeout(timer);
} else {
if (waitTime < 40) {
setVoiceCodeTip(true)
}
setCodeText(`${waitTime }秒后重发`)
setWaitStatus(true)
timeSub(--waitTime, 1000);
}
}, unit || 0);
}
}
function handleSendVoiceCode(checkData, code) {
let calledVoiceSend = false;
const thePhone = code < 3 ? phone : regPhone;
const phoneLength = thePhone.trim().length;
if (isValidPhone(thePhone) && !calledVoiceSend) {
calledVoiceSend = true;
const params = {
certificate,
sig: checkData.sig,
sessionId: checkData.csessionid,
token: checkData.token,
scene: 'nc_login',
}
axios.postJSON('business/anon/sms/bSendLoginVoiceCode', params, { reject: true }).then((res) => {
if (!res.success) {
message.warning(res.message);
return;
}
message.success('验证码将以电话的形式通知到您,请注意接听');
timeSub(60);
let timer;
function timeSub(waitTime, unit) {
clearTimeout(timer);
timer = setTimeout(function () {
if (waitTime == 0) {
calledVoiceSend = false;
clearTimeout(timer);
} else {
calledVoiceSend = true;
timeSub(--waitTime, 1000);
}
}, unit || 0);
}
})
} else if (calledVoiceSend) {
message.warning('验证码将以电话的形式通知到您,请注意接听');
} else {
setBtnText('请输入正确的手机号');
setBtnDisabled(true);
setTimeout(function () {
setBtnText('登录');
setBtnDisabled(false);
}, 2500);
}
}
function handleSendCode(checkData) {
if (regWaitStatus) { return }
const phoneLength = regPhone.trim().length;
if (phoneLength == 11) {
const params = {
phone: regPhone,
sig: checkData.sig,
sessionId: checkData.csessionid,
token: checkData.token,
scene: 'nc_login',
serverType: 'TRIAL_SAAS',
sideType: 0, // 0 表示web端
}
axios.postJSON('business/anon/sms/sendSmsCode', params, { reject: true }).then((res) => {
if (!res.success) {
message.warning(res.message);
} else {
timeSub(60);
setChecking3(true);
setCertificate(res.result);
}
})
let timer;
function timeSub(waitTime, unit) {
clearTimeout(timer);
timer = setTimeout(function () {
if (waitTime == 0) {
setRegCodeText('发送验证码');
setRegWaitStatus(false)
setChecking3(false);
clearTimeout(timer);
} else {
if (waitTime < 40) {
setRegVoiceCodeTip(true)
}
setRegCodeText(`${waitTime }秒后重发`);
setRegWaitStatus(true)
timeSub(--waitTime, 1000);
}
}, unit || 0);
}
} else {
setRegBtnText('请输入正确的手机号');
setRegBtnDisabled(true)
setTimeout(function () {
setRegBtnText('提交');
setRegBtnDisabled(false)
}, 2500);
}
}
function handleRegiste(e) {
e.preventDefault();
const data = {
instName,
phone: regPhone,
code
};
function verifity(tips) {
setRegBtnText(tips);
setRegBtnDisabled(true)
setTimeout(function () {
setRegBtnText('提交');
setRegBtnDisabled(false)
}, 2500);
}
if (!data.phone) {
verifity('请输入手机号');
return;
}
if (data.phone.length != 11) {
verifity('请输入正确的手机号');
return;
}
if (!data.code) {
verifity('请输入验证码');
return;
}
if (!data.instName) {
verifity('请输入机构名');
return;
}
data.inviteCode = 'web-b'
data.contract = '-';
data.source = 'web-b-免费试用'
data.pwd = '';
data.serverType = 'TRIAL_SAAS';
axios.post('api-b/b/web/register', data).then((res) => {
if (res.resultCode == 1103) {
message.info('请输入正确的验证码');
return;
}
setInstName('');
setRegPhone('');
setCode('');
setModalVisible(false);
message.success("申请成功,我们会在1-2个工作日审核完,请耐心等待!", "提醒");
})
.catch((res) => {
setRegBtnText('提交');
setRegBtnDisabled(false);
});
}
function handleDownloadChrome() {
const url = 'http://www.chromeliulanqi.com/';
window.open(url, '_black');
}
function checkSend(code) {
const value = code < 3 ? phone : regPhone;
if (!value) {
message.warning('请输入手机号');
return;
}
if (value.length != 11) {
message.warning('请输入11位手机号')
return;
}
switch (code) {
case 1:
!_.isEmpty(checkObject1) && checkObject1.reset();
setOpenCheck1(true)
break;
case 2:
!_.isEmpty(checkObject2) && checkObject2.reset();
setOpenCheck2(true)
break;
case 3:
!_.isEmpty(checkObject3) && checkObject3.reset();
setOpenCheck3(true)
break;
case 4:
!_.isEmpty(checkObject4) && checkObject4.reset();
setOpenCheck4(true)
break;
default:
break;
}
}
async function checkAccount(code, callback = () => { }) {
const value = code < 3 ?
phone
: regPhone;
const userType = await axios
.postJSON('business/anon/b/checkUserType', { "mainAccount": value })
.then(({ result: { userType } }) => {
return userType
})
if (userType === 'CRM_INST') {
setUserType('CRM_INST');
callback('CRM_INST');
return;
}
callback();
}
return (
<div className="login-page" style={{ background: `url(${ require('../../images/main_banner.png') })`, backgroundSize: '100%', backgroundRepeat: 'no-repeat', backgroundColor: '#21242E' }}>
<div className="header">
<Row className="header-main" type="flex" justify="space-between" align="middle">
<Col>
<a target="_blank" href="http://www.xiaomai5.com/">
<img src={require("../../images/logo_primary_new.png")} className='logo' alt="" />
</a>
</Col>
<Col>
<Select defaultValue={api} style={{ width: 150 }} onChange={
(val) => {
LS.set('DRURL', val);
setApi(val);
DRURL = val;
LS.set('DRURL', DRURL);
}
}>
<Option value="">线路1-杭州</Option>
{
_.map(drList, (item) => {
return <Option value={`${item.url }/`}>{item.describe}</Option>
})
}
</Select>
</Col>
</Row>
</div>
<div className="login-page" >
<div className="login-main">
<div className="left-banner">
<img src='https://image.xiaomaiketang.com/xm/DXDsNKB3Fn.png' alt="" style={{ width: 448, marginTop: 60 }} />
</div>
<div className="login-box stage">
<div className="login">
<div className="r">
<div className="title">
<Tabs activeKey={loginStyle} tabBarStyle={{ border: 'none', padding: '0 25px' }} onChange={(activeKey) => { setLoginStyle(activeKey) }}>
<TabPane tab="密码登录" key="passwordLogin" />
<TabPane tab="验证码登录" key="phoneverifyLogin" />
</Tabs>
</div>
<form action="" className="login-form" onSubmit={handleLogin}>
<div className="form">
<div className="username" style={{ marginBottom: 16 }}>
<Input
type="phone"
autoComplete="off"
name="account"
maxLength={11}
placeholder="手机号"
value={phone}
onChange={(e) => { setPhone(e.target.value) }}
/>
</div>
{loginStyle == 'passwordLogin' &&
<div className="password" style={{ marginBottom: 16 }}>
<Input type={showPassword ? 'text' : 'password'} id="pwd" name="pwd" placeholder="密码" value={password} onChange={(e) => { setPwd(e.target.value) }} />
<span className="icon iconfont" id="password-icon" onClick={() => { setShowPassword(!showPassword) }} dangerouslySetInnerHTML={{ __html: showPassword ? '&#xe6af;' : '&#xe6ae;' }} />
</div>
}
{
loginStyle == 'phoneverifyLogin' &&
[
<div className="phoneverify">
<Input
type="text"
id="phoneverify"
name="phoneverify"
placeholder="验证码"
autoComplete="off"
value={phoneverify}
onChange={(e) => { setPhoneverify(e.target.value) }}
/>
<Popover
visible={openCheck1}
trigger="click"
title=""
content={<div>
<span style={{ fontSize: '12px', color: '#999', marginBottom: 8, display: 'block' }}>请完成安全验证</span>
<CheckBeforeSendCode
callback={(data, nc) => {
setCheckObject1(nc);
checkAccount(1, (userType) => {
handleSendSMSCode(data, userType);
setTimeout(() => {
setOpenCheck1(false);
}, 500)
})
}}
/>
</div>}
onVisibleChange={(value) => {
if (!value) {
setOpenCheck1(false);
}
}}
placement="bottomRight"
>
<div
className="btn"
id="sendVerifyCode"
onClick={() => {
if (checking1) return;
checkSend(1)
}}
>{codeText}</div>
</Popover>
</div>,
<div className="phoneverify-voice" style={{ display: voiceCodeTip ? 'block' : 'none', marginBottom: 10 }}>
<span style={{ color: '#333' }}>收不到短信? </span>
<Popover
visible={openCheck2}
trigger="click"
title=""
content={<div>
<span style={{ fontSize: '12px', color: '#999', marginBottom: 8, display: 'block' }}>请完成安全验证</span>
<CheckBeforeSendCode
callback={(data, nc) => {
handleSendVoiceCode(data, 2);
setCheckObject2(nc);
setTimeout(() => {
setOpenCheck2(false);
}, 500);
}}
/>
</div>}
onVisibleChange={(value) => {
if (!value) {
setOpenCheck2(false);
}
}}
placement="bottomRight"
>
<span
style={{ color: '#58B7EF', }}
id="sendVoiceVerifyCode"
onClick={() => {
checkSend(2)
}}
>使用语音验证码</span>
</Popover>
</div>
]
}
<div className="submit">
<div className="btn">
<button id='loginIn' type="submit" disabled={btnDisabled}>{btnText}</button>
</div>
<div className="apply" onClick={() => { setModalVisible(true) }}>
<span>免费试用</span>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div className="footer">
<div className="footer-main" style={{marginTop:4}}>
<span><span className="icon iconfont">&#xe627;</span>杭州市西湖区古墩路598号同人广场A座3楼</span>
<span className="tel ml22"><span className="icon iconfont">&#xe628;</span>400-6677-456(小麦助教) </span>
<span className="download-chrome ml22" onClick={handleDownloadChrome}><img src={require("../../images/chrome.png")} />前往下载chrome谷歌浏览器 </span>
</div>
<div className="footer-main mt8">
<span>@2015-2020 杭州杰竞科技有限公司</span>
<a target="_blank"
href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=33010602006090"><img src={GH} alt="" style={{width: '16px', height: '16px', display: 'inline-block', margin: '0 4px 0 0'}}/>浙公网安备33010602006090号</a>
<a target="_blank"
href="http://www.beian.miit.gov.cn/state/outPortal/loginPortal.action;jsessionid=oLD4DenLthr_n8liJdOYupeEe9iZYycUySDz15TmoSGC9ZeRF157!1870117190">浙ICP备15025826号-2</a>
<a target="_blank" href="https://image.xiaomaiketang.com/xm/ffXeG5fXn8.jpg">增值电信业务经营许可证:浙B2-20180802</a>
<img src='https://image.xiaomaiketang.com/xm/DXDsNKB3Fn.png' alt="" style={{ width: 448, marginTop: 60 }} />
</div>
</div>
<div className="layout layout-reg" style={{ display: modalVisible ? 'block' : 'none' }}>
<div className="box">
<div className="reg">
<div className="t clearfix" onClick={() => { setModalVisible(false) }}>
<span style={{ float: 'right' }} className="close icon iconfont">&#xe608;</span>
</div>
<div className="c">
<div className="title">免费试用</div>
<div className="form" style={{ textAlign: 'center' }}>
<form action="" className="register-form" onSubmit={handleRegiste}>
<Input type="text" placeholder="机构名" name="instName" id="instName" autoComplete="off" value={instName} onChange={(e) => { setInstName(e.target.value) }} />
<Input
type="text"
placeholder="手机号"
name="phone"
id="phone"
maxLength={11}
autoComplete="off"
value={regPhone}
onChange={(e) => {
const value = (`${e.target.value }`).replace(/[^0-9]/g, '');
setRegPhone(value);
}}
/>
<div className="vertify-code">
<Input type="text" placeholder="验证码" name="code" id="code" autoComplete="off" value={code} onChange={(e) => { setCode(e.target.value) }} />
<Popover
visible={openCheck3}
trigger="click"
title=""
content={<div>
<span style={{ fontSize: '12px', color: '#999', marginBottom: 8, display: 'block' }}>请完成安全验证</span>
<CheckBeforeSendCode
callback={(data, nc) => {
handleSendCode(data);
setCheckObject3(nc);
setTimeout(() => {
setOpenCheck3(false);
}, 500);
}}
/>
</div>}
onVisibleChange={(value) => {
if (!value) {
setOpenCheck3(false);
}
}}
placement="bottomRight"
>
<div
className="btn"
id="sendCode"
onClick={() => {
if (checking3) return;
checkSend(3)
}}
>{regCodeText}</div>
</Popover>
</div>
<div className="phoneverify-voice" style={{ display: regVoiceCodeTip ? 'block' : 'none' }}>
<span style={{ color: '#686868' }}>收不到短信?</span>
<Popover
visible={openCheck4}
trigger="click"
title=""
content={<div>
<span style={{ fontSize: '12px', color: '#999', marginBottom: 8, display: 'block' }}>请完成安全验证</span>
<CheckBeforeSendCode
callback={(data, nc) => {
handleSendVoiceCode(data, 4);
setCheckObject4(nc);
setTimeout(() => {
setOpenCheck4(false);
}, 500);
}}
/>
</div>}
onVisibleChange={(value) => {
if (!value) {
setOpenCheck4(false);
}
}}
placement="bottomRight"
>
<span
style={{ color: '#FFAB1A', cursor: 'pointer' }}
id="sendRegVoiceVerifyCode"
onClick={() => {
checkSend(4)
}}
>使用语音验证码</span>
</Popover>
</div>
<button type="submit" disabled={regBtnDisabled}>{regBtnText}</button>
</form>
</div>
</div>
</div>
<div className="login-box">
登录
</div>
</div>
</div>
......
......@@ -9,641 +9,10 @@
.login-main {
min-width: 1200px;
}
.header {
height: 60px;
background: #fff;
.header-main {
width: 80%;
margin: auto;
.logo {
height: 64px;
}
}
.ant-select-selection {
&:focus,
&:active,
&:hover {
outline: none;
border: none !important;
box-shadow: none;
}
&:hover {
color: #FC9C6B;
.ant-select-arrow {
color: #FC9C6B;
}
}
&:active {
border-color: #fff;
}
}
}
.left-banner {
// width: 448px;
position: fixed;
top: 50%;
left: 30%;
-webkit-transform: translate(-50%, -60%);
-moz-transform: translate(-50%, -60%);
-ms-transform: translate(-50%, -60%);
-o-transform: translate(-50%, -60%);
transform: translate(-50%, -60%);
.left-qrcorde {
margin: 25px auto 10px;
display: block;
}
.qrcorde-tip {
font-size: 12px;
color: rgba(255, 255, 255, 0.4);
text-align: center;
}
}
.login-box {
min-width: 360px;
height: 340px;
position: fixed;
top: 50%;
left: 70%;
-webkit-transform: translate(-50%, -60%);
-moz-transform: translate(-50%, -60%);
-ms-transform: translate(-50%, -60%);
-o-transform: translate(-50%, -60%);
transform: translate(-50%, -60%);
.go-to-site {
position: absolute;
bottom: -80px;
width: 200px;
margin: 0 auto;
left: 50%;
margin-left: -50px;
a {
color: #FFF;
text-decoration: none;
}
span.icon {
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
font-size: 12px;
display: inline-block;
margin-right: 10px;
}
}
.login {
display: flex;
display: -webkit-flex;
flex-direction: row;
-webkit-flex-direction: row;
height: 100%;
overflow: hidden;
background-color: #ffffff;
border-radius: 4px; //box-shadow: 0 0 17px @sun;
.l {
width: 280px;
height: 100%;
background: @sun;
background: -webkit-gradient(linear, left top, left bottom, from(#ffaa1a), to(#ff8634)) !important;
display: flex;
display: -webkit-flex;
-webkit-flex-direction: column;
flex-direction: column;
align-items: center;
color: #ffffff;
font-size: 12px;
justify-content: center;
-webkit-justify-content: center;
.logo {
height: 125px;
img {
height: 100%;
}
}
.name {
font-size: 16px;
margin-bottom: 20px;
}
.desc {
opacity: .7;
margin-bottom: 20px;
}
.items {
ul {
padding: 0;
li {
.icon {
-webkit-transform: scale(.8);
-moz-transform: scale(.8);
-ms-transform: scale(.8);
-o-transform: scale(.8);
transform: scale(.8);
display: inline-block;
margin-right: 10px;
}
line-height: 30px;
list-style-type: none;
}
}
}
}
.r {
flex: 1;
-webkit-flex: 1;
height: 100%;
padding: 30px;
box-sizing: border-box;
position: relative;
&.show-qrcode {
.qrcode {
display: block;
}
.top-right-tip {
.computer {
display: inline-block;
}
.icon-container {
display: none;
}
}
}
.qrcode {
display: none;
text-align: center;
position: absolute;
background: #FFF;
z-index: 1;
left: 20px;
top: 28px;
padding-top: 20px;
img {
display: inline-block;
width: 180px;
}
}
.top-right-tip {
cursor: pointer;
position: absolute;
top: 4px;
right: 4px;
.computer {
display: none;
}
.icon-container {
position: relative;
height: 32px;
width: 32px;
display: inline-block;
.tips {
width: 69px;
position: absolute;
top: 0;
right: 36px;
img {
width: 100%;
}
}
.shade {
position: absolute;
width: 100%;
height: 150%;
top: 0;
margin-left: -100%;
background: #FFF;
transform-origin: right top;
transform: rotate(-45deg);
}
}
span.icon {
font-size: 32px;
}
}
.title {
color: @sun;
margin-bottom: 30px;
display: flex;
display: -webkit-flex;
justify-content: space-between;
-webkit-justify-content: space-between;
.text1 {
color: black;
}
.icon {
font-size: 11px;
}
#login-method {
width: 100%;
text-align: center;
span {
color: #999;
font-weight: 400;
&:hover {
color: #333;
}
}
span.active {
font-weight: 500;
color: #333;
&::after {
content: '';
display: block;
width: 24px;
height: 4px;
border-radius: 3px;
background: #FF8534;
margin: 10px auto 0;
}
}
#password-login {
margin-right: 32px;
}
}
}
#password-icon {
color: #BFBFBF;
margin-right: 10px;
cursor: pointer;
&:hover {
color: #FC9C6B;
}
-webkit-user-select: none;
-moz-user-select:none;
-o-user-select:none;
-ms-user-select:none;
}
input {
display: block;
width: 100%;
height: 40px;
line-height: 40px;
border: 1px solid #e8e8e8; // border-bottom: 1px solid @xm-color-border;
padding-right: 30px;
padding-left: 10px;
margin-bottom: 16px;
background-color: transparent;
background-image: none;
border-radius: 4px;
box-sizing: border-box;
-webkit-transition: all .3s linear;
-moz-transition: all .3s linear;
-ms-transition: all .3s linear;
-o-transition: all .3s linear;
transition: all .3s linear;
&:focus,
&:active,
&:hover {
outline: none; // border: none!important;
// border-bottom: 1px solid @sun!important;
box-shadow: none;
border-color: #FF8534;
}
}
::-webkit-input-placeholder {
/* WebKit, Blink, Edge */
color: #ccc;
}
:-moz-placeholder {
/* Mozilla Firefox 4 to 18 */
color: #ccc;
}
::-moz-placeholder {
/* Mozilla Firefox 19+ */
color: #ccc;
}
:-ms-input-placeholder {
/* Internet Explorer 10-11 */
color: #ccc
}
input:-webkit-autofill,
textarea:-webkit-autofill,
select:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px white inset;
}
.username,
.password,
.phoneverify {
height: 40px;
position: relative;
color: #666666;
.icon {
position: absolute;
right: 5px;
top: 5px;
font-size: 20px;
}
#sendVerifyCode {
cursor: pointer;
display: flex;
display: -webkit-flex;
justify-content: center;
-webkit-justify-content: center;
align-items: center;
-webkit-align-items: center;
position: absolute;
right: 10px;
top: -53px; // border: 1px solid @sun;
color: #333;
height: 25px;
width: 90px;
border-radius: 3px;
margin-top: 60px;
font-size: 14px; // font-weight: 300;
&:hover {
color: #FF8534;
}
&::before {
content: '';
display: block;
height: 20px;
width: 1px;
background-color: #e8e8e8;
margin-right: 10px;
}
}
}
#sendVoiceVerifyCode {
cursor: pointer;
}
.phoneverify-voice {
// padding-left: 5px;
margin-top: 10px;
&::after {}
}
.submit {
position: absolute;
bottom: 20px;
width: 310px;
button {
// font-weight: 300;
}
}
.apply {
cursor: pointer;
text-align: right;
margin-top: 10px;
color: #999;
float: right; // font-weight: 300;
span.icon {
font-size: 12px;
margin-left: 7px;
}
&:hover {
color: #FC9C6B;
}
}
.btn {
button {
display: block;
width: 100%;
background: linear-gradient(90deg, rgba(255, 133, 52, 1) 0%, rgba(255, 173, 52, 1) 100%);
color: #fff;
font-size: 14px;
font-weight: 400;
line-height: 40px;
border-radius: 4px;
-webkit-transition: all .3s;
-moz-transition: all .3s;
-ms-transition: all .3s;
-o-transition: all .3s;
transition: all .3s;
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
}
}
}
}
.footer {
// height: 60px; // padding: 0 60px;
// width: 80%;
background: #fff;
position: absolute;
bottom: 0;
right: 0;
left: 0;
color: #A2A6B2;
// line-height: 60px;
font-size: 14px;
overflow: hidden;
font-weight: 400;
padding:12px;
a{
display:inline-block;
text-align: center;
margin-left: 22px;
color: #A2A6B2;
// margin-top: 8px;
}
.footer-main {
width: 80%;
margin: auto;
text-align: center;
}
address {
float: left;
font-style: normal;
margin-bottom: unset;
}
.icon {
margin-right: 6px;
} // .tel{
// float: right;
// }
.download-chrome {
&:hover {
color: #Fc9C6B;
}
cursor: pointer;
// line-height: 60px;
display: inline-block; // width: 250px;
// position: absolute;
// left: 50%;
// margin-left: -90px;
img {
display: inline-block;
// height: 40px;
// padding: 10px 0;
width: 16px;
vertical-align: middle;
margin-right: 6px;
}
}
}
.stage {
-webkit-transition: all 0.5s linear;
-moz-transition: all 0.5s linear;
-ms-transition: all 0.5s linear;
-o-transition: all 0.5s linear;
transition: all 0.5s linear;
}
// .stage.blur {
// -ms-filter: blur(3px);
// filter: blur(3px);
// -webkit-filter: blur(3px);
// }
.layout {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, .2);
z-index: 999;
display: none;
&.active {
display: block;
}
.box {
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
input {
display: block;
width: 100%;
border: none;
border-bottom: 1px solid @xm-color-border;
padding-right: 30px;
background-color: transparent;
background-image: none;
border-radius: 0;
box-sizing: border-box;
-webkit-transition: all .3s linear;
-moz-transition: all .3s linear;
-ms-transition: all .3s linear;
-o-transition: all .3s linear;
transition: all .3s linear;
&:focus,
&:active,
&:hover {
outline: none;
border: none !important;
border-bottom: 1px solid @sun !important;
box-shadow: none;
}
}
input:-webkit-autofill,
textarea:-webkit-autofill,
select:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px white inset;
}
}
}
.layout .reg {
width: 400px;
height: 320px;
background: #FFFFFF;
border-radius: 6px;
padding: 10px;
.t {
.close {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
-ms-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
&:hover {
cursor: pointer;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
color: @sun;
}
}
}
.c {
width: 250px;
margin: 0 auto;
font-size: 13px;
.title {
text-align: center;
font-size: 14px;
}
.form {
margin-top: 20px;
input {
display: block;
margin-bottom: 20px;
border-bottom: 1px solid @xm-color-border;
width: 100%;
line-height: 30px;
}
.vertify-code {
position: relative;
.btn {
position: absolute;
background: @sun;
color: #FFFFFF;
line-height: 26px;
top: 0;
right: 0;
padding: 0 8px;
border-radius: 4px;
cursor: pointer;
box-shadow: 0 0px 0px 0px #FFF inset;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
-ms-transition: all 0.5s;
-o-transition: all 0.5s;
transition: all 0.5s;
border: 1px solid @sun;
&:hover {
box-shadow: 0 0px 0px 1px #FFF inset;
}
}
}
button {
display: block;
width: 100%;
background: @sun;
color: #FFFFFF;
text-align: center;
line-height: 39px;
border-radius: 5px;
margin-top: 20px;
box-shadow: 0 0px 0px 0px #FFF inset;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
-ms-transition: all 0.5s;
-o-transition: all 0.5s;
transition: all 0.5s;
&:hover {
box-shadow: 0 0px 0px 3px #FFF inset;
}
border: 1px solid @sun;
}
}
}
} // .api{
// position: absolute;
// right: 50px;
// top: 50px;
// }
.ant-select-selection--single {
height: 28px;
position: relative;
cursor: pointer;
background: transparent;
border: none;
color: #999; // width: 100px;
font-size: 28px; // font-weight: 300;
}
.ant-select-arrow {
color: #999;
}
}
\ No newline at end of file
}
\ No newline at end of file
import React from 'react'
import './Main.less';
import Bus from "@/core/bus";
import { MainRoutes } from '@/routes';
class Main extends React.Component {
constructor(props) {
super(props);
......@@ -10,6 +10,7 @@ class Main extends React.Component {
}
}
componentDidMount() {
console.log("MainRoutes",MainRoutes);
Bus.bind("menuTypeChange", (menuType) => {
this.setState({ menuType })
});
......@@ -21,7 +22,7 @@ class Main extends React.Component {
className={this.state.menuType ? `right-container has-nav ${hasBanner ? 'has_banner' : ''}` : `right-container has-nav right-container-vertical ${hasBanner ? 'has_banner' : ''}`}
id="rightContainer"
>
我是内容区
<MainRoutes/>
</div>
)
}
......
......@@ -70,7 +70,7 @@ class Menus extends React.Component {
)}
</Menu.Item>
<SubMenu
key="2"
key="3"
title={
<span>
<Icon type="mail" />
......
......@@ -9,7 +9,6 @@ class testPage extends React.Component {
render() {
return (
<div className="prepare-lesson-page page">
<div className="content-header">测试</div>
......
......@@ -5,24 +5,13 @@
* @LastEditTime: 2020-08-27 10:07:47
* @Description: 内容线路由配置
*/
import { MenuConfig } from '@/routes/interface';
import VideoCourse from '@/modules/video-course';
import ClassBook from '@/modules/class-book';
import TestPage from '@/modules/test';
const mainRoutes = [
{
path: '/home',
component: TestPage,
name: '首页'
},
]
const CloudClassConfig: MenuConfig = {
key: 'cloudClass',
name: '云课堂',
routes: [
{
key: 'test',
name: '页面测试',
path: '/cloudclass/test',
component: TestPage
},
]
};
export default CloudClassConfig;
\ No newline at end of file
export default mainRoutes;
\ No newline at end of file
......@@ -5,12 +5,14 @@
* @LastEditTime: 2020-08-13 11:23:36
* @Description:
*/
import CloudClass from './config/cloudClass';
import {Redirect,Router, Route ,Switch} from 'react-router-dom';
import mainRoutes from './config/mainRoutes';
import React from 'react'
import { Redirect,HashRouter as Router,Route ,Switch} from 'react-router-dom';
import { createHashHistory } from 'history';
import App from '../modules/root/App';
import Login from '../modules/root/Login';
import _ from 'underscore';
import { asyncComponent } from 'react-async-component'
const history = createHashHistory();
window.RCHistory = _.extend({}, history, {
push: (obj: any) => {
......@@ -28,61 +30,51 @@ window.RCHistory = _.extend({}, history, {
history.replace(obj)
}
});
const cache:any = {
path: '',
component: null
}
function dynamic (component:any) {
const resolveComponent = component
return asyncComponent({
resolve: () => {
const ts = resolveComponent()
return ts
},
})
}
export const RootRouter = () => {
return (
// <Router {...history}>
// <Switch>
// {/* <Route key="1" exact path="/login" render={() => <Login />} />
// <Route key="6" path="/" render={() => <App dispatch={dispatch} state={state} />} /> */}
// </Switch>
// </Router>
<Router {...history}>
<Switch>
<Route key="1" exact path="/login" render={() => <Login />} />
<Route key="2" path="/" render={() => <App />} />
</Switch>
</Router>
)
}
// export const MainRoutes = () => {
// return (
// <Switch>
// {
// _.map(renderRoutes, ({
// path,
// version,
// component,
// container,
// isMicroApp,
// }, key) => {
// if (isMicroApp) {
// return <Route
// key={key}
// path={path}
// render={() => {
// return <div id={container} />
// }}
// />
// }
// if (!version) {
// return <Route
// key={key}
// path={path}
// render={() => {
// const Component = dynamic({ path, component })
// cache[path] = Component
// return <Component />
// }}
// />
// } else if ((version === '5.0' && window.NewVersion) || (version !== '5.0' && !window.NewVersion)) {
// return <Route
// key={key}
// path={path}
// render={() => {
// const Component = dynamic({ path, component })
// cache[path] = Component
// return <Component />
// }}
// />
// }
// })
// }
// <Route key="-1" exact path='/' render={() => (<Redirect to='/home' />)} />
// </Switch>
// )
// }
\ No newline at end of file
export const MainRoutes = () => {
console.log("mainRoutes")
return (
<Switch>
{
_.map(mainRoutes, ({
path,
component,
}, key) => {
return <Route
key={key}
path={path}
render={() => {
const Component = component;
return <Component />
}}
/>
})
}
</Switch>
)
}
\ No newline at end of file
/*
* @Author: 吴文洁
* @Date: 2020-04-28 18:10:07
* @LastEditors: 吴文洁
* @LastEditTime: 2020-08-13 10:59:08
* @Description:
*/
/** 路由配置,最终解析后转给<Route>组件 */
export interface RouteConfig {
/** 标题,用于route组件和kio的description */
name?: string;
/** 子菜单key */
key?: string;
/** 子菜单路径 */
path?: string;
component?: React.ComponentType<any>;
// 是否精确匹配
exact?: boolean;
}
/** 左侧的菜单配置 */
export interface MenuConfig {
// 菜单名称
name: string;
// 菜单key
key: string;
// 菜单对应的路由
path?: string;
// 子路由
routes?: RouteConfig[];
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment