diff --git a/public/css/edu-purge.css b/public/css/edu-purge.css index eb8625a44..c289a14dd 100644 --- a/public/css/edu-purge.css +++ b/public/css/edu-purge.css @@ -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; diff --git a/src/App.js b/src/App.js index 0e5921da5..0d86e4341 100644 --- a/src/App.js +++ b/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 { ) } /> + {/* 关联账号 */} + } + > {/* 登录 */} ' + text + '' + return '' + text + '' } marked.setOptions({ silent: true, diff --git a/src/components/render-html.jsx b/src/components/render-html.jsx index 3b7e4b520..9eafa5c74 100644 --- a/src/components/render-html.jsx +++ b/src/components/render-html.jsx @@ -31,6 +31,7 @@ export default ({ rs = rs.replace("

[TOC]

", getTocContent()) cleanToc() } + // 循环匹配所有emoji let matchStr = str.match(strRegexSub); if(matchStr && matchStr.length>0){ for(var i=0;i < matchStr.length;i++){ diff --git a/src/forge/Account/Index.jsx b/src/forge/Account/Index.jsx new file mode 100644 index 000000000..18087d324 --- /dev/null +++ b/src/forge/Account/Index.jsx @@ -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( +
+
+ +
+
+

关联账号

+
+ + 已有账号,进行绑定 + 无账号,注册并绑定 + + { + key === "0" ? + + : + + } +
+
+
+ ) +} +export default Index; \ No newline at end of file diff --git a/src/forge/Account/bind.jsx b/src/forge/Account/bind.jsx new file mode 100644 index 000000000..33453191b --- /dev/null +++ b/src/forge/Account/bind.jsx @@ -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( +
+
+ + {getFieldDecorator('username',{ + rules:[ + { + required:true, + message:"请输入手机号或邮箱地址" + }, + { + validator: (rule, value, callback) => { accountConfirm(rule, value, callback) } + } + ], + validateTrigger:"onInput", + })(} size="large" placeholder="请输入手机号或邮箱地址"/>)} + + + {getFieldDecorator('password', { + rules: [ + { + required:true, + message:"请输入登录密码" + }, + { + validator: (rule, value, callback) => { psdConfirm(rule, value, callback) } + } + ], + validateTrigger:"onInput", + })( + } className="psd" size="large" placeholder="请输入登录密码" />, + )} + + +
+
+ ) +} +export default Form.create({ name: 'Bind' })(Bind); \ No newline at end of file diff --git a/src/forge/Account/image/lock.png b/src/forge/Account/image/lock.png new file mode 100644 index 000000000..4d5d27c2f Binary files /dev/null and b/src/forge/Account/image/lock.png differ diff --git a/src/forge/Account/image/logo.png b/src/forge/Account/image/logo.png new file mode 100644 index 000000000..d474b79d2 Binary files /dev/null and b/src/forge/Account/image/logo.png differ diff --git a/src/forge/Account/image/phone.svg b/src/forge/Account/image/phone.svg new file mode 100644 index 000000000..a33d110a9 --- /dev/null +++ b/src/forge/Account/image/phone.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/forge/Account/image/shield.png b/src/forge/Account/image/shield.png new file mode 100644 index 000000000..475867bf3 Binary files /dev/null and b/src/forge/Account/image/shield.png differ diff --git a/src/forge/Account/image/user.png b/src/forge/Account/image/user.png new file mode 100644 index 000000000..4f03d6c71 Binary files /dev/null and b/src/forge/Account/image/user.png differ diff --git a/src/forge/Account/index.scss b/src/forge/Account/index.scss new file mode 100644 index 000000000..1c9de9ccd --- /dev/null +++ b/src/forge/Account/index.scss @@ -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; } + } + } + } + } +} \ No newline at end of file diff --git a/src/forge/Account/unbind.jsx b/src/forge/Account/unbind.jsx new file mode 100644 index 000000000..57db4d8e3 --- /dev/null +++ b/src/forge/Account/unbind.jsx @@ -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( +
+
+ + {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, + })(} size="large" autoComplete="off"/>)} + + + {getFieldDecorator('username',{ + rules:[ + { + required:true, + message:"请输入手机号或邮箱地址" + }, + { + validator: (rule, value, callback) => { accountConfirm(rule, value, callback) } + } + ], + validateTrigger:"onInput", + })(} size="large" placeholder="请输入手机号或邮箱地址"/>)} + + +
+ {getFieldDecorator('captcha', { + rules: [{ + required: true, + message: "请输入验证码" + }, + { + validator: (rule, value, callback) => { captchaConfirm(rule, value, callback) } + }], + validateTrigger: "onInput", + })( + } placeholder="请输入验证码" autoComplete="off"/> + )} + +
+
+ + {getFieldDecorator('password', { + rules: [ + { + required:true, + message:"请输入登录密码" + }, + { + validator: (rule, value, callback) => { psdConfirm(rule, value, callback) } + } + ], + validateTrigger:"onInput", + })( + } className="psd" size="large" placeholder="请输入登录密码" />, + )} + + + {getFieldDecorator('confirm_password', { + rules: [ + { + required:true, + message:"请再次输入登录密码" + }, + { + validator: (rule, value, callback) => { repsdConfirm(rule, value, callback) } + } + ], + validateTrigger:"onBlur", + })( + } className="psd" size="large" placeholder="请确认登录密码" />, + )} + + +
+
+ ) +} +export default Form.create({ name: 'Bind' })(Bind); \ No newline at end of file diff --git a/src/forge/Main/CoderDepotReadme.jsx b/src/forge/Main/CoderDepotReadme.jsx index 93d8b04c2..5e8bc3532 100644 --- a/src/forge/Main/CoderDepotReadme.jsx +++ b/src/forge/Main/CoderDepotReadme.jsx @@ -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", ""); diff --git a/src/forge/Main/Index.scss b/src/forge/Main/Index.scss index f17bc4805..a2ff111c4 100644 --- a/src/forge/Main/Index.scss +++ b/src/forge/Main/Index.scss @@ -521,7 +521,9 @@ } } } - +.readmeFile{ + overflow: inherit; +} .readmeFile p{ white-space: normal; } \ No newline at end of file