forked from Gitlink/forgeplus-react
第三方登录-第二版
This commit is contained in:
parent
a446c45bff
commit
6610f7f065
|
@ -1080,7 +1080,20 @@ a.shixun-task-btn {
|
|||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.markdown_anchors{
|
||||
position: relative;
|
||||
}
|
||||
.markdown_anchors:hover .anchors{
|
||||
display: inline-block;
|
||||
}
|
||||
.markdown_anchors .anchors:hover{
|
||||
text-decoration: none;
|
||||
}
|
||||
.markdown_anchors .anchors {
|
||||
color: inherit;
|
||||
margin-left: -14px;
|
||||
display: none;
|
||||
}
|
||||
.markdown code {
|
||||
padding: 0;
|
||||
line-height: 23px;
|
||||
|
|
10
src/App.js
10
src/App.js
|
@ -102,11 +102,16 @@ const Home = Loadable({
|
|||
loading: Loading,
|
||||
})
|
||||
|
||||
const Relaction = Loadable({
|
||||
loader: () => import("./forge/Account/Index"),
|
||||
loading: Loading,
|
||||
});
|
||||
const LoginRegisterPage = Loadable({
|
||||
loader: () => import("./modules/loginRegister/LoginRegisterPage"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
|
||||
const AboutUs = Loadable({
|
||||
loader: () => import("./forge/AboutUs/AboutUs"),
|
||||
loading: Loading,
|
||||
|
@ -371,6 +376,11 @@ class App extends Component {
|
|||
)
|
||||
}
|
||||
/>
|
||||
{/* 关联账号 */}
|
||||
<Route
|
||||
path="/bindlogin/:type"
|
||||
render={(props) =><Relaction {...this.props} {...props} mygetHelmetapi={mygetHelmetapi}/>}
|
||||
></Route>
|
||||
|
||||
{/* 登录 */}
|
||||
<Route
|
||||
|
|
|
@ -155,7 +155,7 @@ renderer.heading = function (text, level, raw) {
|
|||
level: level,
|
||||
text: text
|
||||
})
|
||||
return '<h' + level + ' id="' + anchor + '">' + text + '</h' + level + '>'
|
||||
return '<h' + level + ' id="' + anchor + '" class="markdown_anchors"><a href="#'+anchor+'" class="anchors"><i class="iconfont icon-lianjieicon font-14"></i></a>' + text + '</h' + level + '>'
|
||||
}
|
||||
marked.setOptions({
|
||||
silent: true,
|
||||
|
|
|
@ -31,6 +31,7 @@ export default ({
|
|||
rs = rs.replace("<p>[TOC]</p>", getTocContent())
|
||||
cleanToc()
|
||||
}
|
||||
// 循环匹配所有emoji
|
||||
let matchStr = str.match(strRegexSub);
|
||||
if(matchStr && matchStr.length>0){
|
||||
for(var i=0;i < matchStr.length;i++){
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import React , { useState } from 'react';
|
||||
import './index.scss';
|
||||
import logo from './image/logo.png';
|
||||
import { Menu } from 'antd';
|
||||
import Bind from './bind';
|
||||
import UnBind from './unbind';
|
||||
|
||||
function Index(props){
|
||||
const [ key , setKey ] = useState("0");
|
||||
|
||||
// 选择menu
|
||||
function chooseMenuFunc(e){
|
||||
setKey(e.key)
|
||||
}
|
||||
return(
|
||||
<div className={"bodies"}>
|
||||
<div className="logo">
|
||||
<img src={logo} alt="" height="48px" />
|
||||
</div>
|
||||
<div className={"content"}>
|
||||
<p>关联账号</p>
|
||||
<div className="panels">
|
||||
<Menu selectedKeys={[key]} mode={`horizontal`} className="panelsMenu" onClick={chooseMenuFunc}>
|
||||
<Menu.Item key="0">已有账号,进行绑定</Menu.Item>
|
||||
<Menu.Item key="1">无账号,注册并绑定</Menu.Item>
|
||||
</Menu>
|
||||
{
|
||||
key === "0" ?
|
||||
<Bind {...props}/>
|
||||
:
|
||||
<UnBind {...props}/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Index;
|
|
@ -0,0 +1,99 @@
|
|||
import React ,{ useState } from 'react';
|
||||
import { Form , Input , Button } from 'antd';
|
||||
import phone from './image/phone.svg';
|
||||
import lock from "./image/lock.png";
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
const phonereg = /^([1][3456789])\d{9}$/
|
||||
const emailreg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/
|
||||
function Bind(props){
|
||||
const { form } = props;
|
||||
|
||||
const { getFieldDecorator , getFieldsValue } = form;
|
||||
const [ bindFlag , setBindFlag] = useState(true);
|
||||
const type = props.match.params.type;
|
||||
|
||||
// 绑定登录
|
||||
function bindloginFunc(){
|
||||
const {username, password } = getFieldsValue();
|
||||
if(username && password){
|
||||
var url = '/bind_user.json';
|
||||
axios.post(url,{
|
||||
username,password,type
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
window.location.href = "/"+result.data.login;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function accountConfirm(r,v,c){
|
||||
if(v){
|
||||
const {password } = getFieldsValue();
|
||||
if(!(phonereg.test(v) || emailreg.test(v))){
|
||||
setBindFlag(true);
|
||||
c(`请输入正确的手机号或邮箱地址`);
|
||||
}else if(password){
|
||||
setBindFlag(false);
|
||||
}
|
||||
}else{
|
||||
c();
|
||||
setBindFlag(true);
|
||||
}
|
||||
}
|
||||
function psdConfirm(r,v,c){
|
||||
if(v){
|
||||
const { username } = getFieldsValue();
|
||||
if(phonereg.test(username) || emailreg.test(username)){
|
||||
setBindFlag(false);
|
||||
}else{
|
||||
setBindFlag(true);
|
||||
}
|
||||
}else{
|
||||
c();
|
||||
setBindFlag(true);
|
||||
}
|
||||
}
|
||||
return(
|
||||
<div>
|
||||
<Form className="bind_form">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('username',{
|
||||
rules:[
|
||||
{
|
||||
required:true,
|
||||
message:"请输入手机号或邮箱地址"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { accountConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onInput",
|
||||
})(<Input className="account" addonBefore={<img src={phone} alt="" width="13px" />} size="large" placeholder="请输入手机号或邮箱地址"/>)}
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('password', {
|
||||
rules: [
|
||||
{
|
||||
required:true,
|
||||
message:"请输入登录密码"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { psdConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onInput",
|
||||
})(
|
||||
<Input.Password autoComplete="new-password" addonBefore={<img src={lock} alt="" width="13px" />} className="psd" size="large" placeholder="请输入登录密码" />,
|
||||
)}
|
||||
</Form.Item>
|
||||
<Button type="primary" disabled={bindFlag} size="large" style={{width:"100%",marginTop:"40px"}} onClick={bindloginFunc}>
|
||||
绑定并登录
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create({ name: 'Bind' })(Bind);
|
Binary file not shown.
After Width: | Height: | Size: 435 B |
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="10.845" height="14.46" viewBox="0 0 10.845 14.46">
|
||||
<path id="手机号" d="M129.807.994a.818.818,0,0,0-.813.813V12.652a.818.818,0,0,0,.813.813h7.23a.818.818,0,0,0,.813-.813V1.807a.818.818,0,0,0-.813-.813Zm0-.994h7.23a1.807,1.807,0,0,1,1.807,1.807V12.652a1.807,1.807,0,0,1-1.807,1.807h-7.23A1.807,1.807,0,0,1,128,12.652V1.807A1.807,1.807,0,0,1,129.807,0Zm2.35,10.845h2.53a.542.542,0,0,1,0,1.084h-2.53a.542.542,0,0,1,0-1.084Zm0,0" transform="translate(-128)" fill="#b6becc"/>
|
||||
</svg>
|
After Width: | Height: | Size: 530 B |
Binary file not shown.
After Width: | Height: | Size: 420 B |
Binary file not shown.
After Width: | Height: | Size: 413 B |
|
@ -0,0 +1,85 @@
|
|||
.bodies{
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
background-color: rgba(245, 248, 255, 1);
|
||||
.logo{
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
padding:7px 26px;
|
||||
}
|
||||
.content{
|
||||
padding-top: 50px;
|
||||
margin:0px auto;
|
||||
width: 570px;
|
||||
&>p{
|
||||
height:42px;
|
||||
line-height:42px;
|
||||
font-weight:400;
|
||||
color:#000000;
|
||||
font-size:30px;
|
||||
margin-bottom: 32px!important;
|
||||
text-align: center;
|
||||
}
|
||||
.panels{
|
||||
background-color: #fff;
|
||||
border-radius:6.6px;
|
||||
padding:32px 42px;
|
||||
.panelsMenu{
|
||||
border-bottom: none!important;
|
||||
margin-bottom: 36px!important;
|
||||
.ant-menu-item{
|
||||
padding: 0px;
|
||||
margin-right: 60px!important;
|
||||
}
|
||||
}
|
||||
.bind_form{
|
||||
padding-bottom: 48px;
|
||||
.has-error .ant-input:focus,.has-error .ant-input, .has-error .ant-input:hover{
|
||||
border-color: #ff4d4f!important;
|
||||
}
|
||||
.ant-btn-primary[disabled]{
|
||||
background-color:rgba(70, 106, 255,0.55);
|
||||
color: #fff;
|
||||
border:none
|
||||
}
|
||||
.ant-input-group-addon{
|
||||
background-color: transparent;
|
||||
}
|
||||
.ant-input{
|
||||
border-left: none;
|
||||
background-color: #fff!important;
|
||||
}
|
||||
.ant-input:focus,.ant-input:hover{
|
||||
border-right: 1px solid #ddd!important;
|
||||
border-color: #ddd!important;
|
||||
border-left: none!important;
|
||||
}
|
||||
.codeBut{
|
||||
border:1px solid rgba(70, 106, 255, 1)!important;
|
||||
span{
|
||||
color: rgba(70, 106, 255, 1);
|
||||
}
|
||||
}
|
||||
.codeBut.disable{
|
||||
border:1px solid #ddd!important;
|
||||
span{
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
.login_register_head{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
&>span:first-child{
|
||||
font-size: 1.5em;
|
||||
font-weight: 600;
|
||||
color: #000000;
|
||||
line-height: 1.5;
|
||||
}
|
||||
//注册页面的获取验证码输入框
|
||||
.ant-btn{margin-left: 15px; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
import React ,{ useState , useRef } from 'react';
|
||||
import { Form , Input , Button , message } from 'antd';
|
||||
import user from "./image/user.png";
|
||||
import lock from "./image/lock.png";
|
||||
import shield from './image/shield.png';
|
||||
import phone from './image/phone.svg';
|
||||
import axios from 'axios';
|
||||
import { setmiyah } from 'educoder';
|
||||
|
||||
const phonereg = /^([1][3456789])\d{9}$/
|
||||
const emailreg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/
|
||||
function Bind(props){
|
||||
const { form } = props;
|
||||
const seconds = useRef();
|
||||
let interval = undefined;
|
||||
const { getFieldDecorator , getFieldsValue } = form;
|
||||
const [ bindFlag , setBindFlag] = useState(true);
|
||||
const [ captchaFlag , setCaptchaFlag ] = useState(true);
|
||||
const [secondsStr, setSecondsStr] = useState(60);
|
||||
const [ getCaptchaBut , setGetCaptchaBut ] = useState(true);
|
||||
|
||||
|
||||
//判断用户名(username)是否注册
|
||||
function usernameConfirm(rule, value, callback){
|
||||
value ? axios.post(`/accounts/check.json`, {
|
||||
value: value,
|
||||
type: 1
|
||||
}).then(response => {
|
||||
if(response){
|
||||
if (response.data.status === -1) {
|
||||
callback('该名称已经被使用');
|
||||
} else {
|
||||
const { captcha , password , confirm_password,username} = getFieldsValue();
|
||||
if( captcha && password && confirm_password && (password === confirm_password) &&(phonereg.test(username) || emailreg.test(username)) ){
|
||||
setBindFlag(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}):callback();
|
||||
}
|
||||
|
||||
function accountConfirm(rule, value, callback){
|
||||
if(value){
|
||||
const { captcha , password , confirm_password,register_username} = getFieldsValue();
|
||||
if(!(phonereg.test(value) || emailreg.test(value))){
|
||||
setCaptchaFlag(true);
|
||||
callback(`请输入正确的手机号或邮箱地址`);
|
||||
}else{
|
||||
setCaptchaFlag(false);
|
||||
if(captcha && password && confirm_password && (password === confirm_password) && register_username){
|
||||
setBindFlag(false);
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}else{
|
||||
setBindFlag(true);
|
||||
callback();
|
||||
}
|
||||
}
|
||||
function psdConfirm(r,v,c){
|
||||
if(v){
|
||||
const { username , captcha , confirm_password , register_username } = getFieldsValue();
|
||||
if(register_username && (phonereg.test(username) || emailreg.test(username)) && captcha && confirm_password && (v=== confirm_password) ){
|
||||
setBindFlag(false);
|
||||
}else{
|
||||
setBindFlag(true);
|
||||
}
|
||||
c();
|
||||
}else{
|
||||
c();
|
||||
setBindFlag(true);
|
||||
}
|
||||
}
|
||||
function captchaConfirm(r,v,c){
|
||||
if(v){
|
||||
const { username , password , confirm_password , register_username } = getFieldsValue();
|
||||
if(register_username && (phonereg.test(username) || emailreg.test(username)) && password && confirm_password && (password ===confirm_password) ){
|
||||
setBindFlag(false);
|
||||
}else{
|
||||
setBindFlag(true);
|
||||
}
|
||||
c();
|
||||
}else{
|
||||
c();
|
||||
setBindFlag(true);
|
||||
}
|
||||
}
|
||||
function repsdConfirm(r,v,c){
|
||||
if(v){
|
||||
const { username , password , register_username , captcha} = getFieldsValue();
|
||||
if(v !== password){
|
||||
c("两次输入的密码不一样");
|
||||
}else{
|
||||
c();
|
||||
}
|
||||
if((phonereg.test(username) || emailreg.test(username)) && password && register_username && captcha){
|
||||
setBindFlag(false);
|
||||
}else{
|
||||
setBindFlag(true);
|
||||
}
|
||||
c();
|
||||
}else{
|
||||
c();
|
||||
}
|
||||
}
|
||||
|
||||
//获取验证码
|
||||
function getCaptcha() {
|
||||
const { username }= getFieldsValue();
|
||||
if (username) {
|
||||
// 倒计时开始
|
||||
setCaptchaFlag(true);
|
||||
setGetCaptchaBut(false);
|
||||
seconds.current = 60;
|
||||
setSecondsStr(60);
|
||||
!interval && clearInterval(interval);
|
||||
interval = setInterval(() => {
|
||||
if (seconds.current > 1) {
|
||||
let oldSeconds = seconds.current;
|
||||
seconds.current = oldSeconds - 1;
|
||||
setSecondsStr(oldSeconds - 1);
|
||||
} else {
|
||||
clearInterval(interval);
|
||||
//倒计时结束->可以获取验证码
|
||||
setCaptchaFlag(false);
|
||||
setGetCaptchaBut(true);
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
//请求获取验证码接口
|
||||
axios.get(`/accounts/get_verification_code.json`, {
|
||||
params: {
|
||||
login: username,
|
||||
type: 1,
|
||||
smscode: setmiyah(username),
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.data && response.data.status === 0) {
|
||||
//验证码发送成功
|
||||
setGetCaptchaBut(false);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// 绑定登录
|
||||
function bindRegFunc(){
|
||||
form.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
var url = '/accounts/register.json';
|
||||
axios.post(url,{
|
||||
namespace: values.register_username,
|
||||
login: values.username,
|
||||
password: values.password,
|
||||
password_confirmation: values.confirm_password,
|
||||
code: values.captcha
|
||||
}).then(response=>{
|
||||
if(response.data && response.data.status === -6){
|
||||
//验证码不正确
|
||||
form.setFields({captcha: {value:values.captcha,errors:[new Error('验证码错误,请重新输入')]}});
|
||||
|
||||
}else if(response.data && response.data.status === 0){
|
||||
//注册成功,页面跳转即可,注册后登录流程forge处理了
|
||||
window.location.href = "/"+values.register_username;
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
return(
|
||||
<div>
|
||||
<Form className="bind_form">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('register_username',{
|
||||
rules:[
|
||||
{
|
||||
required:true,
|
||||
message:"请输入用户名"
|
||||
},
|
||||
{
|
||||
pattern: /^[a-zA-Z]/,
|
||||
message: "用户名必须以字母开头"
|
||||
},
|
||||
{
|
||||
pattern: /[a-zA-Z0-9]$/,
|
||||
message: "用户名只能使用英文字母和数字"
|
||||
},
|
||||
{
|
||||
min: 4,
|
||||
max: 15,
|
||||
message: "用户名长度为4到15个字符"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { usernameConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input placeholder="请输入4-15位用户名,以字母开头,只能使用字母和数字" addonBefore={<img src={user} alt="" width="13px" />} size="large" autoComplete="off"/>)}
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('username',{
|
||||
rules:[
|
||||
{
|
||||
required:true,
|
||||
message:"请输入手机号或邮箱地址"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { accountConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onInput",
|
||||
})(<Input className="account" addonBefore={<img src={phone} alt="" width="13px" />} size="large" placeholder="请输入手机号或邮箱地址"/>)}
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<div className="login_register_head">
|
||||
{getFieldDecorator('captcha', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: "请输入验证码"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { captchaConfirm(rule, value, callback) }
|
||||
}],
|
||||
validateTrigger: "onInput",
|
||||
})(
|
||||
<Input className="captcha" size="large" addonBefore={<img src={shield} alt="" width="13px" />} placeholder="请输入验证码" autoComplete="off"/>
|
||||
)}
|
||||
<Button type="primary" ghost size="large" className={captchaFlag ? 'codeBut disable':'codeBut'} disabled={captchaFlag} onClick={getCaptcha}>{getCaptchaBut ? "获取验证码":`重发(${secondsStr}s)`}</Button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('password', {
|
||||
rules: [
|
||||
{
|
||||
required:true,
|
||||
message:"请输入登录密码"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { psdConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onInput",
|
||||
})(
|
||||
<Input.Password autoComplete="new-password" addonBefore={<img src={lock} alt="" width="13px" />} className="psd" size="large" placeholder="请输入登录密码" />,
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('confirm_password', {
|
||||
rules: [
|
||||
{
|
||||
required:true,
|
||||
message:"请再次输入登录密码"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { repsdConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
})(
|
||||
<Input.Password autoComplete="new-password" addonBefore={<img src={lock} alt="" width="13px" />} className="psd" size="large" placeholder="请确认登录密码" />,
|
||||
)}
|
||||
</Form.Item>
|
||||
<Button type="primary" disabled={bindFlag} size="large" style={{width:"100%",marginTop:"40px"}} onClick={bindRegFunc}>
|
||||
注册并登录
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create({ name: 'Bind' })(Bind);
|
|
@ -19,7 +19,6 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){
|
|||
},[readme])
|
||||
|
||||
useEffect(()=>{
|
||||
let path = history.location.pathname;
|
||||
const items = $.map($("#readme").find("h1,h2,h3,h4,h5,h6"), function (el, _) {
|
||||
const anchor = el.id;
|
||||
const level = el.tagName.replace("H", "");
|
||||
|
|
|
@ -521,7 +521,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.readmeFile{
|
||||
overflow: inherit;
|
||||
}
|
||||
.readmeFile p{
|
||||
white-space: normal;
|
||||
}
|
Loading…
Reference in New Issue