forked from Gitlink/forgeplus-react
Merge branch 'gitlink_server' of https://git.trustie.net/Gitlink/forgeplus-react into gitlink_server
This commit is contained in:
commit
93ddee8c9e
|
@ -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;
|
||||
|
|
14
src/App.js
14
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,
|
||||
|
@ -131,7 +136,7 @@ const WebIDE = Loadable({
|
|||
// })
|
||||
|
||||
// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。
|
||||
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder", "glcc"];
|
||||
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder", "glcc","bindlogin"];
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
|
@ -154,7 +159,7 @@ class App extends Component {
|
|||
|
||||
const login = cookie.load("login");
|
||||
let path = this.props.history.location.pathname;
|
||||
if(login && (path === "/login" || path === "/register" ||path === "/resetPassword" )){
|
||||
if(login && (path === "/login" || path === "/register" || path === "/resetPassword" || path.indexOf("/bindlogin") >-1 )){
|
||||
this.props.history.push(`/${login}`);
|
||||
}
|
||||
// 添加路由监听,决定组织还是个人
|
||||
|
@ -371,6 +376,11 @@ class App extends Component {
|
|||
)
|
||||
}
|
||||
/>
|
||||
{/* 关联账号 */}
|
||||
<Route
|
||||
path="/bindlogin/:type"
|
||||
render={(props) =><Relaction {...this.props} {...props} mygetHelmetapi={mygetHelmetapi}/>}
|
||||
></Route>
|
||||
|
||||
{/* 登录 */}
|
||||
<Route
|
||||
|
|
|
@ -2,7 +2,6 @@ import axios from 'axios';
|
|||
import { requestProxy } from "./indexEduplus2RequestProxy";
|
||||
import { broadcastChannelOnmessage, isDev, queryString } from 'educoder';
|
||||
import { notification } from 'antd';
|
||||
import cookie from 'react-cookies';
|
||||
|
||||
import './index.css';
|
||||
|
||||
|
@ -17,7 +16,7 @@ function locationurl(list) {
|
|||
}
|
||||
}
|
||||
// TODO 开发期多个身份切换
|
||||
let debugType = "";
|
||||
let debugType = ""
|
||||
if (isDev) {
|
||||
const _search = window.location.search;
|
||||
let parsed = {};
|
||||
|
|
|
@ -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,103 @@
|
|||
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';
|
||||
import cookie from 'react-cookies';
|
||||
|
||||
|
||||
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 && result.data.status === 0){
|
||||
cookie.save("supplyphone",true);
|
||||
cookie.save("login",result.data.login);
|
||||
window.location.href = "/"+result.data.login;
|
||||
}else{
|
||||
props.showNotification(result.data.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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,320 @@
|
|||
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 cookie from 'react-cookies';
|
||||
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);
|
||||
|
||||
const type = props.match.params.type;
|
||||
|
||||
//判断用户名(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{
|
||||
axios.get(`/accounts/valid_email_and_phone.json`, {
|
||||
params: {
|
||||
login: value,
|
||||
type: 1
|
||||
}
|
||||
}).then(response => {
|
||||
if(response){
|
||||
if (response.data.status === -2) {
|
||||
callback(response.data.message);
|
||||
} 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){
|
||||
setBindFlag(true);
|
||||
c('请输入登录密码');
|
||||
}else if(/(?!.*\s)(?!^[\u4e00-\u9fa5]+$)^.{8,16}$/.test(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{
|
||||
if(v.length<8 || v.length>16){
|
||||
setBindFlag(true);
|
||||
c('密码长度为8-16个字符');
|
||||
}else{
|
||||
setBindFlag(true);
|
||||
c('密码不能使用空格');
|
||||
}
|
||||
}
|
||||
}
|
||||
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){
|
||||
setBindFlag(true);
|
||||
c("请重复输入登录密码");
|
||||
}else if(/(?!.*\s)(?!^[\u4e00-\u9fa5]+$)^.{8,16}$/.test(v)){
|
||||
const { username , password , register_username , captcha} = getFieldsValue();
|
||||
if(v !== password){
|
||||
c("两次输入的密码不一样");
|
||||
}else if((phonereg.test(username) || emailreg.test(username)) && password && register_username && captcha){
|
||||
setBindFlag(false);
|
||||
}else{
|
||||
setBindFlag(true);
|
||||
}
|
||||
c();
|
||||
}else{
|
||||
if(v.length<8 || v.length>16){
|
||||
setBindFlag(true);
|
||||
c('密码长度为8-16个字符');
|
||||
}else{
|
||||
setBindFlag(true);
|
||||
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,
|
||||
type
|
||||
}).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处理了
|
||||
cookie.save("supplyphone",true);
|
||||
cookie.save("login",response.data.login);
|
||||
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:"onBlur",
|
||||
validateFirst: true,
|
||||
})(<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:"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={bindRegFunc}>
|
||||
注册并登录
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create({ name: 'Bind' })(Bind);
|
|
@ -1,5 +1,6 @@
|
|||
import React , { Component } from 'react';
|
||||
import { Dropdown , Menu , Icon , Pagination , Spin } from 'antd';
|
||||
import { Dropdown , Menu , Icon , Pagination , Spin , Tooltip } from 'antd';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import '../css/index.scss';
|
||||
import '../Branch/branch.scss';
|
||||
import './activity.css';
|
||||
|
@ -49,6 +50,8 @@ class Activity extends Component{
|
|||
data:undefined,
|
||||
project_trends:undefined,
|
||||
|
||||
codeStatus:undefined,
|
||||
|
||||
isSpin:false
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +62,19 @@ class Activity extends Component{
|
|||
isSpin:true
|
||||
})
|
||||
this.getInfo(time,type,status,page);
|
||||
this.getCodeInfo();
|
||||
}
|
||||
|
||||
getCodeInfo(){
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const url = `/v1/${owner}/${projectsId}/code_stats.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
this.setState({
|
||||
codeStatus:result.data
|
||||
})
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
componentDidUpdate(){
|
||||
|
@ -140,7 +156,7 @@ class Activity extends Component{
|
|||
render(){
|
||||
const { time , data , page , project_trends , isSpin ,
|
||||
pr_count , new_pr_count , close_issues_count , open_issues_count , pr_all_count ,issues_count,
|
||||
type,status } = this.state;
|
||||
type,status , codeStatus } = this.state;
|
||||
let name = time ? ARRAY.filter(item=>item.id === parseInt(time)) :[{name:"全部"}];
|
||||
|
||||
const first_per = pr_all_count > 0 ? `${parseFloat(pr_count/pr_all_count).toFixed(2)*100}%` :"50%";
|
||||
|
@ -148,6 +164,7 @@ class Activity extends Component{
|
|||
const third_per =issues_count > 0 ?`${parseFloat(close_issues_count/issues_count).toFixed(2)*100}%` :"50%";
|
||||
const fourth_per =issues_count > 0 ?`${parseFloat(open_issues_count/issues_count).toFixed(2)*100}%` :"50%";
|
||||
|
||||
const {projectDetail} = this.props;
|
||||
return(
|
||||
<div className="main mt20">
|
||||
|
||||
|
@ -187,6 +204,41 @@ class Activity extends Component{
|
|||
<span className={type==="Issue"&& status==="not_delay" ?`change active`:"change"} onClick={()=>this.changeTrends("Issue","not_delay")}>未处理的疑修</span>
|
||||
</li>
|
||||
</ul>
|
||||
{
|
||||
codeStatus &&
|
||||
<div className="prMsg">
|
||||
<div>排除合并,
|
||||
<span className="fontbold">{codeStatus.author_count} 作者</span> 已经推送 <span className="fontbold">{codeStatus.commit_count} 提交</span> 到
|
||||
{codeStatus.commit_count_in_all_branches && codeStatus.commit_count_in_all_branches>0?<span> {projectDetail && projectDetail.default_branch} 和 <span>{codeStatus.commit_count_in_all_branches} 提交</span> 到所有分支</span>:""}。 在 {projectDetail && projectDetail.default_branch} 上,
|
||||
{codeStatus.change_files && codeStatus.change_files >0 ? <span><span className="fontbold">{codeStatus.change_files} 文件</span> 已经改变 而且</span>:""}
|
||||
{codeStatus.additions && codeStatus.additions >0 ?<span><span className="fontbold greencount">新增 {codeStatus.additions} 行</span></span>:""}
|
||||
{(codeStatus.additions && codeStatus.additions >0) &&(codeStatus.deletions && codeStatus.deletions >0) ?<span> 和</span>:""}
|
||||
{codeStatus.deletions && codeStatus.deletions >0 ?<span><span className="fontbold redcount"> 删除 {codeStatus.deletions} 行</span></span>:""}.</div>
|
||||
{
|
||||
codeStatus.authors && codeStatus.authors.length > 0 &&
|
||||
<ul className="prAuthor">
|
||||
{
|
||||
codeStatus.authors.map((i,v)=>{
|
||||
return(
|
||||
i.author ?
|
||||
!i.author.id ?
|
||||
<span>
|
||||
<img src={getImageUrl(i.author && i.author.image_url)} width="38px" alt=""/>
|
||||
<Tooltip title={i.author && i.author.name} placement="bottom"><span>{i.author && i.author.name}</span></Tooltip>
|
||||
</span>
|
||||
:
|
||||
<a href={i.author.login ? `/${i.author.login}` : `mailto:${i.author.email}`}>
|
||||
<img src={getImageUrl(i.author && i.author.image_url)} width="38px" alt=""/>
|
||||
<Tooltip title={i.author && i.author.name} placement="bottom"><span>{i.author && i.author.name}</span></Tooltip>
|
||||
</a>
|
||||
:""
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div className="df trendsTop mt20">
|
||||
<div className="branchDropdown f-wrap-alignCenter">
|
||||
|
|
|
@ -60,6 +60,48 @@
|
|||
.percentBox > li:last-child{
|
||||
border-right: none;
|
||||
}
|
||||
.prMsg{
|
||||
padding:0px 20px;
|
||||
border-top: 1px solid #f4f4f4;
|
||||
}
|
||||
.prMsg > div{
|
||||
padding:20px 20px 20px 0px;
|
||||
line-height: 22px;
|
||||
border-right:1px solid #f4f4f4;
|
||||
width: 50%;
|
||||
}
|
||||
.prMsg > div span.fontbold{
|
||||
font-weight: 500;
|
||||
}
|
||||
.prMsg > div span.fontbold.greencount{
|
||||
color: green;
|
||||
}
|
||||
.prMsg > div span.fontbold.redcount{
|
||||
color: red;
|
||||
}
|
||||
.prAuthor{
|
||||
padding-bottom: 20px;
|
||||
display: flex;
|
||||
border-right:1px solid #f4f4f4;
|
||||
width: 50%;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.prAuthor a,.prAuthor> span{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 78px;
|
||||
}
|
||||
.prAuthor a img,.prAuthor> span img{
|
||||
border-radius: 50%;
|
||||
}
|
||||
.prAuthor a span,.prAuthor> span span{
|
||||
display: block;
|
||||
max-width: 78px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.activity_list .activity_item{
|
||||
border-bottom: 1px solid #f4f4f4;
|
||||
padding:15px 0px;
|
||||
|
|
|
@ -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", "");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React , { Component } from 'react';
|
||||
import { Spin , Pagination, Timeline } from 'antd';
|
||||
import { Spin , Pagination, Timeline , Tooltip } from 'antd';
|
||||
import { getImageUrl , returnbar } from 'educoder';
|
||||
import { truncateCommitId ,timeFormat } from '../common/util';
|
||||
import { AlignTop } from '../Component/layout';
|
||||
|
@ -200,7 +200,9 @@ class CoderRootCommit extends Component{
|
|||
</span>
|
||||
<CopyTool beforeText="复制commit id" afterText="复制成功" inputId={`value${k}`}/>
|
||||
</div>
|
||||
<button className="btn-83" onClick={()=>{window.location.href=`/${owner}/${projectsId}/tree/${truncateCommitId(item.sha)}`}}>浏览文件</button>
|
||||
<Tooltip title="浏览该提交对应历史版本的所有文件">
|
||||
<button className="btn-83" onClick={()=>{window.location.href=`/${owner}/${projectsId}/tree/${truncateCommitId(item.sha)}`}}>浏览文件</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -521,7 +521,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.readmeFile{
|
||||
overflow: inherit;
|
||||
}
|
||||
.readmeFile p{
|
||||
white-space: normal;
|
||||
}
|
|
@ -260,9 +260,8 @@ export default Form.create()(
|
|||
<div className="infosTip">
|
||||
<p className="font-16 mb14 weight">附件大小说明</p>
|
||||
<p>
|
||||
单个附件不能超过 100M(GVP 项目200M),每个仓库总附件不可超过
|
||||
1G(推荐项目不可超过 5G;GVP 项目不可超过
|
||||
20G)。附件总容量统计包括仓库附件和发行版附件。
|
||||
单个附件不能超过 100M,每个仓库总附件不可超过
|
||||
1G。附件总容量统计包括仓库附件和发行版附件。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -635,7 +635,7 @@ class Index extends Component {
|
|||
</div>
|
||||
<Form.Item className="formTip mt20">
|
||||
<Button type="primary" onClick={this.subMitFrom} className="mr20">{projectsType && projectsType === "mirror" ? "导入" : "创建"}项目</Button>
|
||||
<Link to={'/explore'} className="btn_32">取消</Link>
|
||||
<a onClick={()=>window.history.back(-1)} className="btn_32">取消</a>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Form>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { Component, useRef } from "react";
|
||||
import React, { Component } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import axios from "axios";
|
||||
|
|
|
@ -1,6 +1,30 @@
|
|||
ul,ol,dl{
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.markdown-body{
|
||||
overflow: inherit;
|
||||
}
|
||||
.markdown-body a{
|
||||
color: #6e90ff;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.newMain{
|
||||
background-color: #fff;
|
||||
}
|
||||
|
|
|
@ -142,8 +142,6 @@ class Infos extends Component {
|
|||
});
|
||||
const { current_user } = this.props;
|
||||
const { username } = this.props.match.params;
|
||||
const { pathname } = this.props.location;
|
||||
const { notice } = this.state;
|
||||
|
||||
let url = `/users/${username || (current_user && current_user.login)}.json`;
|
||||
axios.get(url).then((result) => {
|
||||
|
@ -461,7 +459,7 @@ class Infos extends Component {
|
|||
<Route
|
||||
path="/:username"
|
||||
render={(props) => {
|
||||
return <GeneralView {...this.props} {...this.state} menuKey={menuKey} show_super_description={user && user.show_super_description}/>;
|
||||
return <GeneralView {...this.props} {...this.state} menuKey={menuKey} show_super_description={user && user.show_super_description} generalFetchUser={this.fetchUser}/>;
|
||||
}}
|
||||
></Route>
|
||||
{/* <Route
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Divider } from 'antd';
|
|||
import axios from 'axios';
|
||||
|
||||
function Personal(props){
|
||||
const { user ,current_user , resetUserInfo } = props;
|
||||
const { user ,current_user , generalFetchUser } = props;
|
||||
const [ edit , setEdit ] = useState(false);
|
||||
const [ showedit , setShowEdit ] = useState(false);
|
||||
const [ description ,setDescription ] = useState("");
|
||||
|
@ -18,7 +18,7 @@ function Personal(props){
|
|||
setCopyDescription(user.super_description);
|
||||
setShowEdit(true);
|
||||
}
|
||||
},[user])
|
||||
},[user && user.super_description])
|
||||
|
||||
function onContentChange(value){
|
||||
setDescription(value);
|
||||
|
@ -51,7 +51,7 @@ function Personal(props){
|
|||
setCopyDescription(description);
|
||||
setEdit(false);
|
||||
setShowEdit(description ?true :false);
|
||||
resetUserInfo && resetUserInfo();
|
||||
generalFetchUser && generalFetchUser();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ import { notification , Tooltip } from 'antd';
|
|||
|
||||
import axios from 'axios';
|
||||
import educoderLogo from './educoder.png';
|
||||
import qqlogo from './qq.png';
|
||||
import WeChatlogo from './WeChat.png';
|
||||
import qqlogo from './qq@2x.png';
|
||||
import WeChatlogo from './WeChat@2x.png';
|
||||
import giteelogo from './gitee.png';
|
||||
import githublogo from './github.png';
|
||||
import cookie from 'react-cookies';
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import React, { Component } from 'react';
|
||||
import { SnackbarHOC } from 'educoder';
|
||||
import {BrowserRouter as Router,Route,Switch,Link} from 'react-router-dom';
|
||||
import {Tooltip,Menu,Pagination,Spin, Dropdown,Checkbox} from 'antd';
|
||||
import {Menu,Pagination,Spin, Dropdown,Checkbox} from 'antd';
|
||||
import axios from 'axios';
|
||||
import {getImageUrl,WordsBtn} from 'educoder';
|
||||
import moment from 'moment';
|
||||
import Modals from '../../modals/Modals';
|
||||
import SendTopics from '../../modals/SendTopics'
|
||||
|
@ -313,12 +310,6 @@ class InfosTopics extends Component{
|
|||
let user_type=this.props.current_user&&this.props.current_user.user_identity;
|
||||
let targetuserid=this.props.data&&this.props.data.id;
|
||||
|
||||
|
||||
|
||||
// console.log(is_current)
|
||||
// console.log(current_user)
|
||||
// console.log(current_user.is_teacher)
|
||||
// console.log(current_user.admin)
|
||||
const menu = (
|
||||
<Menu>
|
||||
<Menu.Item onClick={()=>this.updatedlist("updated_at")}>
|
||||
|
|
Loading…
Reference in New Issue