第三方登录-第二版

This commit is contained in:
caishi 2022-12-26 15:26:57 +08:00
parent a446c45bff
commit 6610f7f065
15 changed files with 525 additions and 4 deletions

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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++){

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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; }
}
}
}
}
}

View File

@ -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);

View File

@ -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", "");

View File

@ -521,7 +521,9 @@
}
}
}
.readmeFile{
overflow: inherit;
}
.readmeFile p{
white-space: normal;
}