Merge pull request '合并代码' (#794) from Eeeros/forgeplus-react:dev_management into dev_management
|
|
@ -1,3 +1,4 @@
|
|||
@import url(./font/font.css);
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ const Relaction = Loadable({
|
|||
loading: Loading,
|
||||
});
|
||||
const LoginRegisterPage = Loadable({
|
||||
loader: () => import("./modules/loginRegister/LoginRegisterPage"),
|
||||
loader: () => import("./modules/loginRegister/LoginRegisterPageNew"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
/* 导航栏 */
|
||||
@font-face {
|
||||
font-family: "YouSheBiaoTiHei";
|
||||
src: url('./youshebiaotihei-2-webfont.woff2');
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|||
import { Link } from 'react-router-dom';
|
||||
import './activity.css';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import { truncateCommitId } from "../common/util";
|
||||
|
||||
|
||||
class ActivityItem extends Component {
|
||||
|
|
@ -25,9 +26,16 @@ class ActivityItem extends Component {
|
|||
<span className="activity_type">{item.trend_type}</span>
|
||||
</p >
|
||||
:
|
||||
// 如果是commit--CommitLog
|
||||
item.trend_type === "CommitLog" ?
|
||||
<p className="itemLine">
|
||||
<Link to={`/${owner}/${projectsId}/commits/${item.commit_log && truncateCommitId(item.commit_log.commit_id)}`} className="font-16">{item.name}</Link>
|
||||
<span className="activity_type">{item.trend_type}</span>
|
||||
</p >
|
||||
:
|
||||
// 如果是合并请求
|
||||
<p className="itemLine">
|
||||
<Link to={`/${owner}/${projectsId}/pulls/${item.trend_id}`} className="font-16">{item.name}</Link>
|
||||
<Link to={`/${item.project && item.project.owner&& item.project.owner.login}/${item.project && item.project.identifier}/pulls/${item.trend_id}`} className="font-16">{item.name}</Link>
|
||||
<span className="activity_type">{item.trend_type}</span>
|
||||
</p >
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { getOrzCompanyList } from '../../forge/Information/api';
|
|||
import AddProjectModal from './AddProjectModal';
|
||||
import '../../modules/tpm/TPMIndex.css';
|
||||
import CheckProfile from '../Component/ProfileModal/Profile';
|
||||
import logo from './img/logo.png'
|
||||
|
||||
import './header.scss';
|
||||
const { SubMenu } = Menu
|
||||
|
|
@ -334,6 +335,11 @@ class NewHeader extends Component {
|
|||
return (
|
||||
<div className={publicNav ? `newHeaders publicNav`:`newHeaders`} id="nHeader">
|
||||
<div className="headerContent">
|
||||
<div className="title">
|
||||
<img src={logo} alt="" style={{width: '32px'}} />
|
||||
<span className='font32 ml15'>支持持续成长演化的软件平台</span>
|
||||
<span className='font24 ml15'>群智开发</span>
|
||||
</div>
|
||||
{isRender === true ?
|
||||
<LoginDialog
|
||||
{...this.props}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 3.1 KiB |
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState , useRef } from "react";
|
||||
import styled from "styled-components";
|
||||
import { Button ,Spin } from "antd";
|
||||
import { timeFormat, truncateCommitId } from '../common/util';
|
||||
|
|
@ -57,6 +57,24 @@ export default (props) => {
|
|||
const [isSpin, setIsSpin] = useState(true);
|
||||
const { sha , projectsId, owner } = match.params;
|
||||
|
||||
const [ dropLoading, setDropLoading] = useState(false); //加载loading
|
||||
const limit = 100;
|
||||
const fRef = useRef();
|
||||
|
||||
useEffect(()=>{
|
||||
window.addEventListener("scroll",scrollListener);
|
||||
return ()=>{window.removeEventListener("scroll",scrollListener);}
|
||||
},[])
|
||||
|
||||
const scrollListener=()=>{
|
||||
let scrollHeight = document.documentElement.scrollHeight;
|
||||
let clientHeight = document.documentElement.clientHeight;
|
||||
let scrollTop = document.documentElement.scrollTop;
|
||||
if(Math.ceil(scrollTop+clientHeight) >= scrollHeight-5){
|
||||
InitDiffData();
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
if(projectDetail){
|
||||
const { author, name} = projectDetail;
|
||||
|
|
@ -66,17 +84,18 @@ export default (props) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (projectsId && owner && sha) {
|
||||
InitDiffData();
|
||||
|
||||
const url = `/${owner}/${projectsId}/commits/${sha}.json`;
|
||||
axios
|
||||
.get(url)
|
||||
.then(result => {
|
||||
if (result) {
|
||||
setData(result.data);
|
||||
// setData(result.data);
|
||||
setCommit(result.data.commit);
|
||||
setParents(result.data.parents);
|
||||
setCommitter(result.data.committer || (result.data.commit && result.data.commit.committer));
|
||||
setIsSpin(false);
|
||||
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -84,6 +103,28 @@ export default (props) => {
|
|||
});
|
||||
}
|
||||
}, [projectsId , owner, sha]);
|
||||
|
||||
async function InitDiffData (){
|
||||
let f = fRef.current ? fRef.current.files : [];
|
||||
let p = fRef.current ? fRef.current.page : 1;
|
||||
let hm = fRef.current ? fRef.current.hasMore : true;
|
||||
if (!hm || dropLoading || !isSpin) {
|
||||
return;
|
||||
}
|
||||
setDropLoading(true);
|
||||
const url = `/v1/${owner}/${projectsId}/commits/${sha}/files.json`;
|
||||
await axios.get(url,{
|
||||
params:{page:p,limit}
|
||||
}).then(res=>{
|
||||
if(res && res.status === 200){
|
||||
let arr = p === 1 ? res.data.files : [...f,...res.data.files];
|
||||
setData(res.data);
|
||||
fRef.current = {files:arr,page:p+1,hasMore:arr.length === limit};
|
||||
setDropLoading(false);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="main" style={{padding:"0px",border:"none"}}>
|
||||
<Spin spinning={isSpin}>
|
||||
|
|
@ -132,10 +173,13 @@ export default (props) => {
|
|||
<Files
|
||||
history={history}
|
||||
data={data}
|
||||
filesData={fRef.current && fRef.current.files}
|
||||
owner={owner}
|
||||
projectsId={projectsId}
|
||||
parentsSha={parents && parents.length > 0 && parents[0].sha}
|
||||
mergeId={`commits/${sha}`}
|
||||
/>
|
||||
{ dropLoading && <p style={{textAlign:"center",color:"#999",padding:"10px"}}>文件加载中...</p>}
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -513,6 +513,7 @@ class CreateMerge extends Component {
|
|||
changeCommitFunc={this.changeCommitFunc}
|
||||
comparesData={comparesData}
|
||||
pullOwnerLogin={pullOwnerLogin}
|
||||
branchParams = {getBranchParams(this.props.location.pathname)}
|
||||
></MergeFooter>
|
||||
)}
|
||||
</Spin>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
import React ,{useEffect,useState } from 'react';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import { AlignCenter , FlexAJ } from '../Component/layout';
|
||||
import { Tooltip,Progress } from 'antd';
|
||||
import { Tooltip , Progress } from 'antd';
|
||||
import './merge.css';
|
||||
import './Index.scss';
|
||||
import FileDrop from './components/fileDrop';
|
||||
|
||||
function Files({ data,history,owner,projectsId , parentsSha }){
|
||||
const [ files , setFiles ] = useState(data && data.files);
|
||||
const [ copyfileTipTitle, setCopyfileTipTitle] = useState("复制文件路径");
|
||||
function Files({ data , filesData , history,owner,projectsId , parentsSha , mergeId }){
|
||||
const [ files , setFiles ] = useState(filesData);
|
||||
const [ isOpen, setIsOpen] = useState(false);
|
||||
|
||||
useEffect(()=>{
|
||||
if(data){
|
||||
setFiles(data.files);
|
||||
if(filesData){
|
||||
setFiles(filesData);
|
||||
}
|
||||
},[data]);
|
||||
},[filesData]);
|
||||
|
||||
useEffect(()=>{
|
||||
document.addEventListener('click',()=>{setIsOpen(false)})
|
||||
|
|
@ -29,33 +28,22 @@ function Files({ data,history,owner,projectsId , parentsSha }){
|
|||
}
|
||||
}
|
||||
|
||||
function copyFileName(fileName){
|
||||
var copyCont = document.createElement('input');
|
||||
copyCont.defaultValue = fileName;
|
||||
document.body.appendChild(copyCont);
|
||||
copyCont.select(); // 选择对象
|
||||
document.execCommand("Copy"); // 执行浏览器复制命令
|
||||
copyCont.className = 'copyCont';
|
||||
copyCont.style.display='none';
|
||||
setCopyfileTipTitle("复制成功");
|
||||
}
|
||||
|
||||
const folderOpen = (
|
||||
<div className="folders">
|
||||
<div className="folderList">
|
||||
{files && files.map((item, key) => {
|
||||
return (
|
||||
<a href={`#value${key}`}>
|
||||
<FlexAJ className="filesInfo" key={key} onClick={() => {item.flag && showDown(item.flag, key, item.isBin);setIsOpen(false);}}>
|
||||
<FlexAJ className="filesInfo" key={key} onClick={() => {item.flag && showDown(item.flag, key, item.is_bin);setIsOpen(false);}}>
|
||||
<AlignCenter>
|
||||
<i className="iconfont icon-wenjianicon mr4"></i>
|
||||
<span className="cursor-pointer" data-clipboard-text={item.name}>{item.name}</span>
|
||||
<span className="cursor-pointer" data-clipboard-text={item.filename}>{item.filename}</span>
|
||||
</AlignCenter>
|
||||
<div className="see-file">
|
||||
<Tooltip placement="top" title={`${item.addition+item.deletion}处更改${item.addition + item.deletion > 0 ? ":":""}${item.addition>0?item.addition+"处添加":""}${item.addition>0 && item.deletion>0 ?"和":""}${item.deletion>0?item.deletion+"处删除":""}`}>
|
||||
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.addition/(item.addition+item.deletion)*100} />
|
||||
{item.addition >0 && <span className="color-green ml10">+{item.addition}</span>}
|
||||
{item.deletion >0 && <span className="color-red ml10">-{item.deletion}</span>}
|
||||
<Tooltip placement="top" title={`${item.additions+item.deletions}处更改${item.additions + item.deletions > 0 ? ":":""}${item.additions>0?item.additions+"处添加":""}${item.additions>0 && item.deletions>0 ?"和":""}${item.deletions>0?item.deletions+"处删除":""}`}>
|
||||
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.additions/(item.additions+item.deletions)*100} />
|
||||
{item.additions >0 && <span className="color-green ml10">+{item.additions}</span>}
|
||||
{item.deletions >0 && <span className="color-red ml10">-{item.deletions}</span>}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</FlexAJ>
|
||||
|
|
@ -66,22 +54,17 @@ function Files({ data,history,owner,projectsId , parentsSha }){
|
|||
</div>
|
||||
)
|
||||
|
||||
function subStrContent(content){
|
||||
return content ? content.slice(1) :"";
|
||||
}
|
||||
|
||||
return(
|
||||
<div onClick={(e)=>{e.nativeEvent.stopImmediatePropagation()}}>
|
||||
<AlignCenter className="color-grey-9" style={{position:'relative'}}>
|
||||
<div onClick={()=>{setIsOpen(!isOpen)}}>
|
||||
<i className={`iconfont mr5 ${isOpen? "font-18 icon-sanjiaoxing-down":"font-16 icon-triangle"}`}></i>
|
||||
<span className="color-grey-6 update-file-count">
|
||||
共有<span className="color-grey-3"> {data && data.files_count} 个文件 </span>被更改
|
||||
{ data && data.total_addition ? <span>,包括 <span className="color-green">{data && data.total_addition} 次插入</span></span>:"" }
|
||||
{ data && data.total_addition && data.total_deletion ? " 和 ":""}
|
||||
{ data && data.total_deletion ? <span className="color-red"> {data && data.total_deletion} 次删除</span>:""}
|
||||
</span>
|
||||
</div>
|
||||
<AlignCenter className="color-grey-9" style={{position:'relative'}} onClick={()=>{setIsOpen(!isOpen)}}>
|
||||
<div style={{width:20}}><i className={`iconfont mr5 ${isOpen? "font-18 icon-sanjiaoxing-down":"font-16 icon-triangle"}`}></i></div>
|
||||
<span className="color-grey-6 update-file-count">
|
||||
共有<span className="color-grey-3"> {data && data.file_nums} 个文件 </span>被更改
|
||||
{ data && data.total_addition ? <span>,包括 <span className="color-green">{data && data.total_addition} 次插入</span></span>:"" }
|
||||
{ data && data.total_addition && data.total_deletion ? " 和 ":""}
|
||||
{ data && data.total_deletion ? <span className="color-red"> {data && data.total_deletion} 次删除</span>:""}
|
||||
</span>
|
||||
{isOpen && folderOpen}
|
||||
</AlignCenter>
|
||||
{
|
||||
|
|
@ -92,57 +75,7 @@ function Files({ data,history,owner,projectsId , parentsSha }){
|
|||
return(
|
||||
<div className="files" key={key}>
|
||||
<a id= {`value${key}`} className="anchorPoint"></a>
|
||||
<FlexAJ className="filesInfo">
|
||||
<AlignCenter>
|
||||
{!item.isBin ? <i className={!item.flag?"iconfont icon-sanjiaoxing-down color-grey-9":"iconfont icon-triangle font-15 color-grey-9"} onClick={()=>showDown(item.flag,key,item.isBin)}></i>:""}
|
||||
<span className="cursor-pointer" data-clipboard-text={item.name} onClick={()=>showDown(item.flag,key,item.isBin)}>
|
||||
{ item.isRenamed && item.old_name}
|
||||
{ item.isRenamed && <i className="iconfont icon-youjiang font-12 color-grey-8 ml5 mr5"></i> }
|
||||
{item.name}
|
||||
</span>
|
||||
<Tooltip
|
||||
title={copyfileTipTitle}
|
||||
onVisibleChange={()=>setCopyfileTipTitle("复制文件路径")}
|
||||
>
|
||||
<i className="iconfont icon-fuzhiicon ml6" onClick={()=>copyFileName(item.name)}></i>
|
||||
</Tooltip>
|
||||
</AlignCenter>
|
||||
<div className="see-file">
|
||||
<Tooltip placement="top" title={`${item.addition + item.deletion}处更改${item.addition + item.deletion > 0 ? ":":""} ${item.addition > 0 ? item.addition + "处添加" : ""}${item.addition > 0 && item.deletion > 0 ? "和" : ""}${item.deletion > 0 ? item.deletion + "处删除" : ""}`}>
|
||||
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.addition/(item.addition+item.deletion)*100} />
|
||||
<span className="ml10">{item.addition+item.deletion}处</span>
|
||||
</Tooltip>
|
||||
{
|
||||
!item.isSubmodule &&
|
||||
<span className="see-file-btn" onClick={()=>{history.push(`/${owner}/${projectsId}${item.isDeleted ? `/commits/${truncateCommitId(parentsSha)}`:`/tree/${truncateCommitId(item.sha)}/${item.name}`}`)}}>查看文件</span>
|
||||
}
|
||||
</div>
|
||||
</FlexAJ>
|
||||
{
|
||||
item.sections && item.sections.length >= 1 && !item.flag &&
|
||||
<div className="filesContent">
|
||||
{
|
||||
item.sections.map((i,k)=>{
|
||||
return(
|
||||
i.lines && i.lines.length>0 && i.lines.map((item,key)=>{
|
||||
return(
|
||||
<div key={k+key} className={(item.type === 2) ? "linesContent add" : item.type === 3 ? "linesContent reduce": item.type===4?"linesContent translate":"linesContent"}>
|
||||
<span className="lines">
|
||||
<span>{item.leftIdx && item.leftIdx !=="0" ? item.leftIdx :"" }</span>
|
||||
<span>{item.rightIdx && item.rightIdx !=="0" ? item.rightIdx :"" }</span>
|
||||
</span>
|
||||
<p style={{display:"flex"}}>
|
||||
<span className="linetype">{item.type===2 ? "+" : item.type===3 ? "-" :""}</span>
|
||||
{ (item.type===3 || item.type===2) ? subStrContent(item.content) : item.content}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<FileDrop item={item} prekey={key} projectsId={projectsId} owner={owner} history={history} parentsSha={parentsSha} mergeId={mergeId}/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -118,4 +118,11 @@
|
|||
width:30px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
}
|
||||
.diffDesc{
|
||||
padding:30px 0px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
@ -22,14 +22,21 @@ class MergeFooter extends Component {
|
|||
activeKey: '1',
|
||||
commitCount: 0,
|
||||
filesCount: 0,
|
||||
unitData:undefined,
|
||||
// 总评论数量,包含回复
|
||||
commentsTotalCount: 0,
|
||||
page:1,
|
||||
hasMore:true,
|
||||
dropLoading:false,
|
||||
limit:100
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
this.Init();
|
||||
// 为父组件绑定当前,以方便调用方法
|
||||
this.props.bindFootRef && this.props.bindFootRef(this);
|
||||
window.addEventListener("scroll",this.scrollListener);
|
||||
return ()=>{window.removeEventListener("scroll",this.scrollListener);}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
|
|
@ -41,6 +48,18 @@ class MergeFooter extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
scrollListener=()=>{
|
||||
let scrollHeight = document.documentElement.scrollHeight;
|
||||
let clientHeight = document.documentElement.clientHeight;
|
||||
let scrollTop = document.documentElement.scrollTop;
|
||||
if(Math.ceil(scrollTop+clientHeight) >= scrollHeight-5){
|
||||
const { match } = this.props;
|
||||
const { projectsId, owner, mergeId } = match.params;
|
||||
this.getFile(owner, projectsId, mergeId);
|
||||
}
|
||||
}
|
||||
|
||||
Init = (isTabChange) => {
|
||||
const { data, location, match } = this.props;
|
||||
const { pathname } = location;
|
||||
|
|
@ -60,7 +79,7 @@ class MergeFooter extends Component {
|
|||
this.setState({
|
||||
activeKey: activeKey,
|
||||
commitCount: data && data.commits_count,
|
||||
filesCount: data && data.files_count,
|
||||
filesCount:data && data.files_count
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -81,7 +100,7 @@ class MergeFooter extends Component {
|
|||
if (result) {
|
||||
this.setState({
|
||||
commitsData: result.data.commits,
|
||||
commitCount: result.data.commits_count,
|
||||
commitCount: result.data.commits_count
|
||||
});
|
||||
}
|
||||
this.setState({ isSpin: false });
|
||||
|
|
@ -91,29 +110,38 @@ class MergeFooter extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
getFile = (owner, projectsId, mergeId) => {
|
||||
this.setState({ isSpin: true });
|
||||
const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`;
|
||||
axios
|
||||
.get(url)
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
filesData: result.data,
|
||||
filesCount: result.data.files_count,
|
||||
});
|
||||
}
|
||||
this.setState({ isSpin: false });
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({ isSpin: false });
|
||||
});
|
||||
getFile = async(owner, projectsId, mergeId) => {
|
||||
const { page,limit , hasMore , dropLoading , filesData } = this.state;
|
||||
if(!hasMore || dropLoading){
|
||||
return;
|
||||
}
|
||||
this.setState({ isSpin: page === 1 , dropLoading:page > 1 });
|
||||
const url = `/v1/${owner}/${projectsId}/pulls/${mergeId}/files.json`;
|
||||
await axios.get(url,{
|
||||
params:{page,limit}
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
let datas = result.data;
|
||||
let files = page === 1 ? datas.files : filesData.concat(datas.files);
|
||||
this.setState({
|
||||
unitData:datas,
|
||||
filesData: files,
|
||||
hasMore:datas.files && datas.files.length === limit,
|
||||
page:page+1
|
||||
});
|
||||
}
|
||||
this.setState({ dropLoading:false,isSpin: false });
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({ isSpin: false });
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { projectsId, owner, mergeId } = this.props.match.params;
|
||||
|
||||
const { order_id, data = {} } = this.props;
|
||||
const { order_id, data = {} , pullOwnerLogin } = this.props;
|
||||
|
||||
const {
|
||||
isSpin,
|
||||
activeKey,
|
||||
|
|
@ -121,6 +149,8 @@ class MergeFooter extends Component {
|
|||
commitCount,
|
||||
filesData,
|
||||
commitsData = [],
|
||||
unitData,
|
||||
dropLoading
|
||||
} = this.state;
|
||||
|
||||
// 评论数量优先取Comment组件中列表接口返回的,其次取合并请求详情接口中的,都没有取默认值0
|
||||
|
|
@ -128,7 +158,6 @@ class MergeFooter extends Component {
|
|||
this.state.commentsTotalCount || data.comments_total_count || 0,
|
||||
10
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="main mergeRequest" style={{ paddingTop: '0px' }}>
|
||||
<Spin spinning={isSpin}>
|
||||
|
|
@ -193,12 +222,17 @@ class MergeFooter extends Component {
|
|||
}
|
||||
key="3"
|
||||
>
|
||||
<Files
|
||||
{...this.props}
|
||||
data={filesData}
|
||||
projectsId={projectsId}
|
||||
owner={owner}
|
||||
/>
|
||||
<div>
|
||||
<Files
|
||||
{...this.props}
|
||||
data={unitData}
|
||||
filesData={filesData}
|
||||
projectsId={projectsId}
|
||||
owner={owner}
|
||||
mergeId={`pulls/${mergeId}`}
|
||||
/>
|
||||
{ dropLoading && <p style={{textAlign:"center",color:"#999",padding:"10px"}}>文件加载中...</p>}
|
||||
</div>
|
||||
</TabPane>
|
||||
)}
|
||||
</Tabs>
|
||||
|
|
|
|||
|
|
@ -404,12 +404,20 @@ class MessageCount extends Component {
|
|||
{
|
||||
<div className="mt15">
|
||||
<Tag className="pr-branch-tag">
|
||||
<Link
|
||||
to={`/${data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author}/${data.pull_request.is_original?data.project_identifier:projectsId}/tree/${turnbar(data.pull_request && data.pull_request.head)}`}
|
||||
className="ver-middle task-hide" style={{maxWidth:"300px"}} title={`${data.pull_request.fork_project_user}: ${data.pull_request && data.pull_request.head}`}
|
||||
>
|
||||
{data.pull_request && data.pull_request.fork_project_user}: {data.pull_request && data.pull_request.head}
|
||||
</Link>
|
||||
{
|
||||
(data.pull_request.fork_project_user || data.issue.author_name!=="已注销") ?
|
||||
<Link
|
||||
to={`/${data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author}/${data.pull_request.is_original?data.project_identifier:projectsId}/tree/${turnbar(data.pull_request && data.pull_request.head)}`}
|
||||
className="ver-middle task-hide" style={{maxWidth:"300px"}} title={`${data.pull_request.fork_project_user}: ${data.pull_request && data.pull_request.head}`}
|
||||
>
|
||||
{data.pull_request && (data.pull_request.is_original ? data.pull_request.fork_project_user:data.issue.author_name)}: {data.pull_request && data.pull_request.head}
|
||||
</Link>
|
||||
:
|
||||
<span className="ver-middle task-hide" style={{maxWidth:"300px"}} title={`${data.pull_request.fork_project_user}: ${data.pull_request && data.pull_request.head}`}>
|
||||
{data.pull_request && (data.pull_request.is_original ? data.pull_request.fork_project_user:data.issue.author_name)}: {data.pull_request && data.pull_request.head}
|
||||
</span>
|
||||
|
||||
}
|
||||
</Tag>
|
||||
<span className="mr8 ver-middle">
|
||||
<i
|
||||
|
|
@ -638,7 +646,7 @@ class MessageCount extends Component {
|
|||
{...this.props}
|
||||
{...this.state}
|
||||
bindFootRef={this.bindFootRef}
|
||||
pullOwnerLogin={data.pull_request && data.pull_request.fork_project_user}
|
||||
pullOwnerLogin={data.pull_request && (data.pull_request.is_original ? data.pull_request.fork_project_user:data.issue.project_author)}
|
||||
></MergeLinkFooter>
|
||||
</div>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -281,7 +281,6 @@ class NewMerge extends Component {
|
|||
id,
|
||||
comparesData
|
||||
} = this.state;
|
||||
|
||||
const renderBrances = (list, type) => {
|
||||
if (list && list.length > 0) {
|
||||
return list.map((item, key) => {
|
||||
|
|
@ -313,7 +312,9 @@ class NewMerge extends Component {
|
|||
return <div dangerouslySetInnerHTML={{ __html: html }}></div>;
|
||||
};
|
||||
let { project } = this.props;
|
||||
|
||||
// 源仓库所有者login
|
||||
const pullOwnerLogin = projects_names && projects_names.filter(item=>{return item.id === id})[0].project_user_login;
|
||||
console.log("-------------",pullOwnerLogin,projects_names);
|
||||
return (
|
||||
<div>
|
||||
<div className="main">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import axios from "axios";
|
|||
import "../Order/order.scss";
|
||||
import "./merge.css";
|
||||
import MergeForm from "./merge_form";
|
||||
import MergeFooter from "./merge_footer";
|
||||
const Option = Select.Option;
|
||||
class UpdateMerge extends Component {
|
||||
constructor(props) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
import React ,{useEffect,useState } from 'react';
|
||||
import { truncateCommitId } from '../../common/util';
|
||||
import { AlignCenter , FlexAJ } from '../../Component/layout';
|
||||
import { Tooltip , Progress , Spin } from 'antd';
|
||||
import "../Index.scss";
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
function FileDrop({prekey,item,projectsId,owner , history , mergeId,parentsSha}){
|
||||
const [ copyfileTipTitle, setCopyfileTipTitle] = useState("复制文件路径");
|
||||
const [ sections, setSections ] = useState(undefined);
|
||||
const [ show, setShow ] = useState(true);
|
||||
const [ isSpin, setIsSpin ] = useState(false);
|
||||
|
||||
useEffect(()=>{
|
||||
if(prekey < 3 && item && item.filename){
|
||||
showDown(item.filename);
|
||||
}
|
||||
},[prekey,item])
|
||||
|
||||
function copyFileName(fileName){
|
||||
var copyCont = document.createElement('input');
|
||||
copyCont.defaultValue = fileName;
|
||||
document.body.appendChild(copyCont);
|
||||
copyCont.select(); // 选择对象
|
||||
document.execCommand("Copy"); // 执行浏览器复制命令
|
||||
copyCont.className = 'copyCont';
|
||||
copyCont.style.display='none';
|
||||
setCopyfileTipTitle("复制成功");
|
||||
}
|
||||
function subStrContent(content){
|
||||
return content ? " " + content.slice(1) :"";
|
||||
}
|
||||
|
||||
function showDown(filename){
|
||||
if(!sections){
|
||||
setIsSpin(true);
|
||||
const url = `/v1/${owner}/${projectsId}/${mergeId}/files.json`;
|
||||
axios.get(url,{
|
||||
params:{filepath:filename}
|
||||
}).then(res=>{
|
||||
if(res){
|
||||
let files = res.data && res.data.files && res.data.files.length>0 && res.data.files[0];
|
||||
setSections(files.sections);
|
||||
setShow(true);
|
||||
setIsSpin(false);
|
||||
}
|
||||
})
|
||||
}else{
|
||||
setShow(!show);
|
||||
}
|
||||
}
|
||||
return(
|
||||
<div key={prekey}>
|
||||
<Spin spinning={isSpin}>
|
||||
<FlexAJ className="filesInfo">
|
||||
<AlignCenter onClick={()=>setShow(!show)} style={{cursor:!item.is_bin && item.changes !== 0?"pointer":"default"}}>
|
||||
{(!item.is_bin && item.changes !== 0) ? <div style={{width:20}}><i className={show ?"iconfont icon-sanjiaoxing-down color-grey-9":"iconfont icon-triangle font-15 color-grey-9"}></i></div>:""}
|
||||
<span className="cursor-pointer" data-clipboard-text={item.name}>
|
||||
{ item.is_renamed && item.old_name}
|
||||
{ item.is_renamed && <i className="iconfont icon-youjiang font-12 color-grey-8 ml5 mr5"></i> }
|
||||
{item.filename}
|
||||
</span>
|
||||
<Tooltip
|
||||
title={copyfileTipTitle}
|
||||
onVisibleChange={()=>setCopyfileTipTitle("复制文件路径")}
|
||||
>
|
||||
<i className="iconfont icon-fuzhiicon ml6" onClick={(e)=>{e.stopPropagation();copyFileName(item.filename);}}></i>
|
||||
</Tooltip>
|
||||
</AlignCenter>
|
||||
<div className="see-file">
|
||||
<Tooltip placement="top" title={`${item.additions + item.deletions}处更改${item.additions + item.deletions > 0 ? ":":""} ${item.additions > 0 ? item.additions + "处添加" : ""}${item.additions > 0 && item.deletions > 0 ? "和" : ""}${item.deletions > 0 ? item.deletions + "处删除" : ""}`}>
|
||||
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.additions/(item.additions+item.deletions)*100} />
|
||||
<span className="ml10">{item.additions+item.deletions}处</span>
|
||||
</Tooltip>
|
||||
{
|
||||
!item.is_submodule &&
|
||||
<span className="see-file-btn" onClick={()=>{history.push(`/${owner}/${projectsId}${item.is_deleted ? `/commits/${truncateCommitId(parentsSha)}`:`/tree/${truncateCommitId(item.sha)}/${item.filename}`}`)}}>查看文件</span>
|
||||
}
|
||||
</div>
|
||||
</FlexAJ>
|
||||
{
|
||||
(!item.is_bin && item.changes !== 0) && show &&
|
||||
<div className="filesContent">
|
||||
{
|
||||
(sections && sections.length > 0) ? sections.map((i,k)=>{
|
||||
return(
|
||||
i.lines && i.lines.length>0 && i.lines.map((item,keys)=>{
|
||||
return(
|
||||
<div key={k+keys} className={(item.type === 2) ? "linesContent add" : item.type === 3 ? "linesContent reduce": item.type===4?"linesContent translate":"linesContent"}>
|
||||
<span className="lines">
|
||||
<span>{item.left_index && item.left_index !=="0" ? item.left_index :"" }</span>
|
||||
<span>{item.right_index && item.right_index !=="0" ? item.right_index :"" }</span>
|
||||
</span>
|
||||
<div style={{display:"flex"}}>
|
||||
<span className="linetype">{item.type===2 ? "+" : item.type===3 ? "-" :""}</span>
|
||||
<div>
|
||||
<span style={{whiteSpace:"pre-wrap"}}>{(item.type===3 || item.type===2) ? subStrContent(item.content) : item.content}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
})
|
||||
:
|
||||
<div className='diffDesc'>
|
||||
<a onClick={()=>showDown(item.filename)} className='color-blue'>加载差异</a>差异被折叠
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</Spin>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default FileDrop;
|
||||
|
|
@ -197,6 +197,12 @@ form .ant-cascader-picker, form .ant-select {
|
|||
.linesContent .lines > span:first-child{
|
||||
margin-right: 0px;
|
||||
}
|
||||
.linesContent .lines,.linesContent .linetype,.no-select,.filesInfo{
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE/Edge */
|
||||
user-select: none; /* 标准语法 */
|
||||
}
|
||||
.linesContent .lines > span{
|
||||
width: 50%;
|
||||
text-align: right;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Tabs } from 'antd';
|
||||
import { Tabs , Spin } from 'antd';
|
||||
import Commits from './Commits';
|
||||
import Files from './Files';
|
||||
import { returnbar , turnbar } from 'educoder';
|
||||
import { Base64 } from 'js-base64';
|
||||
|
||||
import '../Order/order.scss';
|
||||
import './merge.css';
|
||||
import axios from 'axios';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
|
|
@ -13,9 +16,30 @@ class MergeFooter extends Component {
|
|||
super(props);
|
||||
this.state = {
|
||||
activeKey: '1',
|
||||
diff:undefined,
|
||||
filesData: undefined,
|
||||
page:1,
|
||||
hasMore:true,
|
||||
dropLoading:false,
|
||||
limit:100
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.getFilesInfo();
|
||||
window.addEventListener("scroll",this.scrollListener);
|
||||
return ()=>{window.removeEventListener("scroll",this.scrollListener);}
|
||||
}
|
||||
|
||||
scrollListener=()=>{
|
||||
let scrollHeight = document.documentElement.scrollHeight;
|
||||
let clientHeight = document.documentElement.clientHeight;
|
||||
let scrollTop = document.documentElement.scrollTop;
|
||||
if(Math.ceil(scrollTop+clientHeight) >= scrollHeight-5){
|
||||
this.getFilesInfo();
|
||||
}
|
||||
}
|
||||
|
||||
changeTab = (index) => {
|
||||
this.setState({
|
||||
activeKey: index,
|
||||
|
|
@ -27,11 +51,58 @@ class MergeFooter extends Component {
|
|||
changeCommitFunc&& changeCommitFunc(page);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
// 解决切换tab后浏览器回退不刷新的问题、点击tab后url变化但tab未切换的问题
|
||||
const newPathname = this.props.location.pathname;
|
||||
const prevPathname = prevProps.location.pathname;
|
||||
if (newPathname !== prevPathname) {
|
||||
this.getFilesInfo();
|
||||
}
|
||||
}
|
||||
|
||||
getFilesInfo=()=>{
|
||||
const { hasMore , dropLoading , filesData , page , limit } = this.state;
|
||||
if(!hasMore || dropLoading){
|
||||
return;
|
||||
}
|
||||
this.setState({dropLoading:page>1})
|
||||
const { branchParams = {} } = this.props;
|
||||
const { mergeOwner, projectId } = branchParams;
|
||||
let url = `/v1/${mergeOwner}/${projectId}/${this.getUrl()}/files.json`;
|
||||
axios.get(url,{
|
||||
params:{page,limit}
|
||||
}).then(res=>{
|
||||
if(res){
|
||||
let datas = res.data;
|
||||
let files = page === 1 ? datas.files : filesData.concat(datas.files);
|
||||
this.setState({
|
||||
diff:res.data ,
|
||||
filesData: files,
|
||||
hasMore:datas.files && datas.files.length === limit,
|
||||
dropLoading:false,page:page+1
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getUrl = ()=>{
|
||||
const { branchParams = {} } = this.props;
|
||||
const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId , pullIdentity } = branchParams;
|
||||
let url = `compare`;
|
||||
if (mergeOwner === pullOwner) {
|
||||
url += `/${Base64.encode(returnbar(pullBranch))}...${Base64.encode(returnbar(mergeBranch))}`;
|
||||
} else {
|
||||
url += `/${Base64.encode(returnbar(mergeBranch))}...${pullOwner}/${pullIdentity || projectId}:${Base64.encode(returnbar(pullBranch))}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
const { comparesData = {} ,limit } = this.props;
|
||||
const { commits, diff, commits_count } = comparesData;
|
||||
const { activeKey } = this.state;
|
||||
const { comparesData = {} ,limit ,branchParams } = this.props;
|
||||
const { commits,commits_count } = comparesData;
|
||||
const { activeKey , diff , filesData , dropLoading } = this.state;
|
||||
|
||||
return (commits && commits.length === 0) || !diff ? (
|
||||
''
|
||||
|
|
@ -71,19 +142,24 @@ class MergeFooter extends Component {
|
|||
tab={
|
||||
<span>
|
||||
<span className="font-16">文件</span>
|
||||
{diff.files_count > 0 && (
|
||||
<span className="tabNum">{diff.files_count}</span>
|
||||
{diff.file_nums > 0 && (
|
||||
<span className="tabNum">{diff.file_nums}</span>
|
||||
)}
|
||||
</span>
|
||||
}
|
||||
key="3"
|
||||
>
|
||||
<Files
|
||||
{...this.props}
|
||||
data={diff}
|
||||
projectsId={projectsId}
|
||||
owner={owner}
|
||||
/>
|
||||
<div>
|
||||
<Files
|
||||
{...this.props}
|
||||
data={diff}
|
||||
filesData={filesData}
|
||||
projectsId={projectsId}
|
||||
owner={owner}
|
||||
mergeId={this.getUrl()}
|
||||
/>
|
||||
{ dropLoading && <p style={{textAlign:"center",color:"#999",padding:"10px"}}>文件加载中...</p>}
|
||||
</div>
|
||||
</TabPane>
|
||||
)}
|
||||
</Tabs>
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 79 KiB |
|
|
@ -0,0 +1,146 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Form, Input, Button, Checkbox , Tooltip } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import axios from 'axios';
|
||||
// import educoderLogo from '../login/educoder.png';
|
||||
// import qqlogo from '../login/qq@2x.png';
|
||||
// import WeChatlogo from '../login/WeChat@2x.png';
|
||||
// import giteelogo from '../login/gitee.png';
|
||||
// import githublogo from '../login/github.png';
|
||||
import cookie from 'react-cookies';
|
||||
import './LoginRegisterPageNew.scss';
|
||||
import { Encrypt } from "../../common/Env";
|
||||
|
||||
function Login(props){
|
||||
const [message,setMessage] = useState();
|
||||
// const [setting, setSetting] = useState(undefined);
|
||||
const {form, location, mygetHelmetapi} = props;
|
||||
const {getFieldDecorator } = form;
|
||||
const {search} = location;
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
//控制密码输入框在DOM不可见value
|
||||
clear();
|
||||
//获取第三方登录平台信息
|
||||
// setSetting(JSON.parse(localStorage.getItem("chromesetting")));
|
||||
},[])
|
||||
|
||||
// 配置网页标题
|
||||
useEffect(()=>{
|
||||
if(mygetHelmetapi){
|
||||
const {name} = mygetHelmetapi;
|
||||
document.title = name;
|
||||
}
|
||||
}, [mygetHelmetapi])
|
||||
|
||||
// 登录表单提交
|
||||
function handleSubmit(){
|
||||
setMessage(undefined);
|
||||
form.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
axios.post(`/accounts/login.json`, {
|
||||
login: values.username,
|
||||
password: Encrypt(values.password),
|
||||
autologin: values.remember?1:0,
|
||||
}).then((response) => {
|
||||
if (!response.data.login) {
|
||||
response.data.status === -2 ? setMessage(response.data.message) : setMessage("错误的账号或密码");
|
||||
} else {
|
||||
//判断用户是否选择【下次自动登录】
|
||||
cookie.save('autologin',values.remember);
|
||||
cookie.save('supplyphone',true);
|
||||
cookie.save("login",response.data.login);
|
||||
|
||||
const searchParams = new URLSearchParams(search.substring(1));
|
||||
const goPage = searchParams.get("go_page");
|
||||
//意见反馈
|
||||
window.location.href = goPage ? goPage : `/${response.data.login}`
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log('error',error);
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//清除密码框的value属性->DOM看不见密码值
|
||||
function clear(){
|
||||
const password = document.getElementById("login_password");
|
||||
if(password && password.type==="password"){
|
||||
setTimeout(()=>{
|
||||
password.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return(
|
||||
<div className="right_cont login_content">
|
||||
<div className="login_register_head mb60">
|
||||
<p>欢迎登录 <span className="head_blue">群智开发</span></p>
|
||||
</div>
|
||||
<p className = {message?"message active mb10":"message"}>{message}</p>
|
||||
<Form className="login-form">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('username',{
|
||||
rules:[
|
||||
{
|
||||
required:true,
|
||||
message:"请输入手机号/邮箱/用户名"
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
})(<Input className="account" placeholder="请输入手机号/邮箱/用户名" prefix={<div className="input_icon"></div>} />)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('password', {
|
||||
rules: [
|
||||
{
|
||||
required:true,
|
||||
message:"请输入登录密码"
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
})(
|
||||
<Input.Password className="psd" placeholder="请输入登录密码" onBlur={clear} onChange={clear} prefix={<div className="input_icon"></div>} />,
|
||||
)}
|
||||
</Form.Item>
|
||||
|
||||
<div className="login_register_head login mb60">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('remember', {
|
||||
valuePropName: 'checked',
|
||||
initialValue: cookie.load('autologin'),
|
||||
})(<Checkbox>下次自动登录</Checkbox>)}
|
||||
</Form.Item>
|
||||
{/* <Link to="/resetPassword" className="goResetPsdBut">忘记密码?</Link> */}
|
||||
</div>
|
||||
<Button type="primary" htmlType="submit" onClick={handleSubmit} className="login_register_cofBut">登录</Button>
|
||||
</Form>
|
||||
<div className="link_span">没有账号?<Link to={`/register`}>去注册</Link></div>
|
||||
|
||||
{
|
||||
// setting && setting.third_party_new && setting.third_party_new.length > 0 ?
|
||||
// <p className="quick_logon">
|
||||
// <p className="quick_logon_p"></p>
|
||||
// <span className={"startlogin"}> 快速登录 </span>
|
||||
// {setting.third_party_new.map((item,key)=>{
|
||||
// return(
|
||||
// <a href={`${item.url}`} className="ml15 mr15">
|
||||
// <Tooltip title={`使用${item.name === "qq" ? "QQ":item.name === "wechat" ? "微信" : item.name}账号登录`}>
|
||||
// <img src={item.name === "educoder" ? educoderLogo : item.name === "qq" ? qqlogo : item.name === "wechat" ? WeChatlogo : item.name === "gitee" ? giteelogo : item.name === "github" ? githublogo : ""} width="46px" alt={`${item.name}登录`}/>
|
||||
// </Tooltip>
|
||||
// </a>
|
||||
// )
|
||||
// })
|
||||
// }
|
||||
// </p>
|
||||
// <OtherLogin />
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
export default Form.create({ name: 'login' })(Login);
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import React from "react";
|
||||
import Login from "./LoginNew";
|
||||
import Register from "./RegisterNew";
|
||||
import ResetPassword from "./ResetPasswordNew";
|
||||
import '../loginRegister/LoginRegisterPageNew.scss';
|
||||
|
||||
function LoginRegisterPage(props){
|
||||
const {mygetHelmetapi} = props;
|
||||
return(
|
||||
<div className="loginRegister">
|
||||
<div className="login_register_right">
|
||||
{props.location.pathname === "/login" ?
|
||||
<Login {...props}/>
|
||||
:
|
||||
props.location.pathname === "/register" ?
|
||||
<Register mygetHelmetapi={mygetHelmetapi}/>
|
||||
:
|
||||
<ResetPassword mygetHelmetapi={mygetHelmetapi}/>
|
||||
}
|
||||
</div>
|
||||
<div className="clear"></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default LoginRegisterPage;
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
@import url(./font/font.css);
|
||||
|
||||
.loginRegister{
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
background-image: url(./img/bg1.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: alibaba;
|
||||
}
|
||||
.clear{
|
||||
clear: both;
|
||||
}
|
||||
.login_register_right {
|
||||
width: 1200px;
|
||||
height: 705px;
|
||||
background:#ffffff;
|
||||
box-shadow:0px 0px 20px rgba(37, 106, 206, 0.14);
|
||||
background-image: url(./img/bglogin.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 50% 100%;
|
||||
.Register_content {
|
||||
padding: 70px 75px 70px 75px;
|
||||
.registerNav {
|
||||
margin-bottom: 28px;
|
||||
a {
|
||||
color: #445a7a;
|
||||
display: inline-block;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
}
|
||||
.activeRegisterNav {
|
||||
font-family: alibaba-medium;
|
||||
color: #0d5ef8;
|
||||
border-bottom: 2px solid #0d5ef8;
|
||||
}
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 34px;
|
||||
}
|
||||
}
|
||||
.login_content {
|
||||
padding: 105px 75px 113px 75px;
|
||||
.ant-form-item {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
}
|
||||
.right_cont {
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.login_register_head {
|
||||
font-family: alibaba-medium;
|
||||
color: #283444;
|
||||
font-size: 28px;
|
||||
line-height: 28px;
|
||||
.head_blue {
|
||||
font-size: 26px;
|
||||
color: #0d5ef8;
|
||||
}
|
||||
}
|
||||
.account {
|
||||
.input_icon::before {
|
||||
background-image: url(./img/icon1.png);
|
||||
}
|
||||
&:hover {
|
||||
.input_icon::before {
|
||||
background-image: url(./img/icon2.png);
|
||||
}
|
||||
}
|
||||
}
|
||||
.psd, .psdComfirm, .register_psd {
|
||||
.input_icon::before {
|
||||
background-image: url(./img/icon3.png);
|
||||
}
|
||||
&:hover {
|
||||
.input_icon::before {
|
||||
background-image: url(./img/icon4.png);
|
||||
}
|
||||
}
|
||||
}
|
||||
.email {
|
||||
.input_icon::before {
|
||||
background-image: url(./img/icon7.png);
|
||||
}
|
||||
&:hover {
|
||||
.input_icon::before {
|
||||
background-image: url(./img/icon8.png);
|
||||
}
|
||||
}
|
||||
}
|
||||
.phone {
|
||||
.input_icon::before {
|
||||
background-image: url(./img/icon5.png);
|
||||
}
|
||||
&:hover {
|
||||
.input_icon::before {
|
||||
background-image: url(./img/icon6.png);
|
||||
}
|
||||
}
|
||||
}
|
||||
.input_icon {
|
||||
margin-left: 50px;
|
||||
width: 0px;
|
||||
height: 30px;
|
||||
border: 1px solid;
|
||||
border-color: rgba(20, 49, 179, 0.12);
|
||||
&::before {
|
||||
transform: translate( 50%, -50%);
|
||||
position: absolute;
|
||||
content: "";
|
||||
left: 0;
|
||||
top: 50%;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background-image: url(./img/icon1.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
.ant-input{
|
||||
width: 450px;
|
||||
height: 48px;
|
||||
border: 1px solid;
|
||||
border-color: #9eaacb;
|
||||
border-radius: 4px;
|
||||
background: #FFFFFF !important;
|
||||
color: #283444;
|
||||
padding-left: 80px;
|
||||
&:hover{
|
||||
background: rgba(0, 88, 255, 0.03);
|
||||
border-color: #0d5ef8;
|
||||
}
|
||||
}
|
||||
.login_register_cofBut {
|
||||
width: 450px;
|
||||
height: 56px;
|
||||
background: #0d5ef8;
|
||||
border-radius: 10px;
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
}
|
||||
.link_span {
|
||||
font-size:14px;
|
||||
line-height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
a {
|
||||
color: #0d5ef8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Form, Input, Button, Checkbox, message } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import axios from 'axios';
|
||||
import { setmiyah } from 'educoder';
|
||||
import './LoginRegisterPageNew.scss';
|
||||
import { Encrypt } from "../../common/Env";
|
||||
|
||||
function Register(props){
|
||||
const {form, mygetHelmetapi} = props;
|
||||
const {getFieldDecorator, setFieldsValue } = form;
|
||||
//用户输入的符合规则的邮箱(用于获取验证码)
|
||||
const [emailStr, setEmailStr] = useState(undefined);
|
||||
//用户输入的符合规则的用户名,用于当用户输入符合规则的用户名之后再更改又去触发check.json接口
|
||||
const [loginStr, setLoginStr] = useState(undefined);
|
||||
const [secondsStr, setSecondsStr] = useState(60);
|
||||
const [countDown, setCountDown] = useState(false);
|
||||
const [getCaptchaBut, setGetCaptchaBut] = useState(false);
|
||||
const [mess, setMess] = useState(undefined);
|
||||
const [tipVisable, setTipVisable] = useState(false);
|
||||
//用于表单提交时会再次校验数据
|
||||
const [userNameGo, setUserNameGo] = useState(true);
|
||||
const [emailGo, setEmailGo] = useState(true);
|
||||
// 注册类型(手机号/邮箱)
|
||||
const [registerType, setRegisterType] = useState(0);
|
||||
const [setting, setSetting] = useState(undefined);
|
||||
const seconds = useRef();
|
||||
let interval = undefined;
|
||||
|
||||
useEffect(()=>{
|
||||
//获取第三方登录平台信息
|
||||
setSetting(JSON.parse(localStorage.getItem("chromesetting")));
|
||||
},[])
|
||||
|
||||
// 配置网页标题
|
||||
useEffect(()=>{
|
||||
if(mygetHelmetapi){
|
||||
const {name} = mygetHelmetapi;
|
||||
document.title = name;
|
||||
}
|
||||
}, [mygetHelmetapi])
|
||||
|
||||
//注册表单提交
|
||||
function handleSubmit(){
|
||||
form.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
axios.post(`/accounts/register.json`, {
|
||||
login: values.email,
|
||||
namespace: values.register_username.trim(),
|
||||
password: Encrypt(values.register_psd),
|
||||
password_confirmation: Encrypt(values.psdComfirm),
|
||||
code: "123123"
|
||||
}).then((response)=>{
|
||||
debugger;
|
||||
if(response.data && response.data.status === -6){
|
||||
//验证码不正确
|
||||
form.setFields({captcha: {value:values.captcha,errors:[new Error('验证码错误,请重新输入')]}});
|
||||
//设置邮箱内容-》不设置会被恢复成undefined,从而点击验证码失败
|
||||
setEmailStr(values.email);
|
||||
}else if(response.data && response.data.status === 0){
|
||||
//注册成功,页面跳转即可,注册后登录流程forge处理了
|
||||
window.location.href = "/"+values.register_username.trim();
|
||||
} else {
|
||||
setEmailStr(values.email);
|
||||
setMess(response.data.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//判断用户名(username)是否注册
|
||||
function usernameConfirm(rule, value, callback){
|
||||
setUserNameGo(true);
|
||||
value && (userNameGo || value !== loginStr) ? axios.post(`/accounts/check.json`, {
|
||||
value: value.trim(),
|
||||
type: 1
|
||||
}).then(response => {
|
||||
if (response.data.status === -1) {
|
||||
callback(response.data.message);
|
||||
} else {
|
||||
setLoginStr(value);
|
||||
setUserNameGo(false);
|
||||
callback();
|
||||
}
|
||||
}):callback();setLoginStr(undefined);
|
||||
}
|
||||
|
||||
//判断邮箱/手机号是否符合规范、是否注册
|
||||
function emailConfirm(rule, value, callback) {
|
||||
if(value){
|
||||
if((/^([1][3456789])\d{9}$/.test(value) && !registerType) || (/^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/.test(value) && registerType)){
|
||||
setEmailGo(true);
|
||||
(emailGo || value !== emailStr) ? axios.get(`/accounts/valid_email_and_phone.json`, {
|
||||
params: {
|
||||
login: value,
|
||||
type: 1
|
||||
}
|
||||
}).then(response => {
|
||||
if(!response.data.status){
|
||||
setEmailStr(value);
|
||||
setGetCaptchaBut(true);
|
||||
setEmailGo(false);
|
||||
callback();
|
||||
}else{
|
||||
setGetCaptchaBut(false);
|
||||
// callback(response.data.status === -2 ? `该${registerType ? '邮箱' : '手机号'}已被注册` : response.data.message);
|
||||
callback(response.data.message);
|
||||
}
|
||||
}):callback();// setEmailStr(undefined);
|
||||
}else{
|
||||
callback(`请输入正确的${registerType ? '邮箱地址' : '手机号'}`);
|
||||
}
|
||||
}else{
|
||||
callback(`请输入${registerType ? '邮箱地址' : '手机号'}`);
|
||||
}
|
||||
}
|
||||
|
||||
//确认密码
|
||||
function comfirmPassWord(rule, value, callback, index) {
|
||||
if ((index === 2 && value && form.getFieldValue('register_psd') && value !== form.getFieldValue('register_psd')) || (index === 1 && value && form.getFieldValue('psdComfirm') && value !== form.getFieldValue('psdComfirm'))) {
|
||||
if(index===1){
|
||||
form.setFields({psdComfirm: {value:form.getFieldValue('psdComfirm'),errors:[new Error('密码不一致,请重新输入')]}});
|
||||
callback();
|
||||
}else{
|
||||
callback('密码不一致,请重新输入');
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
//检查密码是否符合格式
|
||||
function checkPassWord(rule, value, callback){
|
||||
if(!value){
|
||||
setTipVisable(true);
|
||||
callback('请输入登录密码');
|
||||
}else if(/(?!.*\s)(?!^[\u4e00-\u9fa5]+$)^.{8,16}$/.test(value)){
|
||||
callback()
|
||||
}else{
|
||||
setTipVisable(true);
|
||||
if(value.length<8 || value.length>16){
|
||||
callback('密码长度为8-16个字符');
|
||||
}else{
|
||||
callback('密码不能使用空格');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//确认勾选服务
|
||||
function comfirmRead(rule, value, callback){
|
||||
if(value){
|
||||
callback();
|
||||
}else{
|
||||
callback("请阅读并接受我们的服务条款");
|
||||
}
|
||||
}
|
||||
|
||||
//获取验证码
|
||||
function getCaptcha() {
|
||||
setMess(undefined);
|
||||
if (emailStr) {
|
||||
// 倒计时开始
|
||||
setCountDown(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);
|
||||
//倒计时结束->可以获取验证码
|
||||
setGetCaptchaBut(true);
|
||||
setCountDown(false);
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
//请求获取验证码接口
|
||||
axios.get(`/accounts/get_verification_code.json`, {
|
||||
params: {
|
||||
login: emailStr,
|
||||
type: 1,
|
||||
smscode: setmiyah(emailStr),
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.data && response.data.status === 0) {
|
||||
//验证码发送成功
|
||||
let email = emailStr.substring(emailStr.indexOf("@")+1);
|
||||
message.success({content:<span>验证码已发送,请注意查收。{registerType ? <a href={`https://mail.${email}`} target="_blank">前往邮箱</a> : ''}</span>});
|
||||
} else {
|
||||
//验证码发送失败,获取验证码按钮变灰并且文案变回【获取验证码】
|
||||
setGetCaptchaBut(false);
|
||||
setCountDown(false);
|
||||
clearInterval(interval);
|
||||
setMess(response.data.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//清除密码框的value属性->DOM看不见密码值
|
||||
function clear(){
|
||||
const password = document.getElementById("register_register_psd");
|
||||
const passwordComfirm = document.getElementById("register_psdComfirm");
|
||||
if(password && password.type==="password"){
|
||||
setTimeout(()=>{
|
||||
password.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
if(passwordComfirm && passwordComfirm.type==="password"){
|
||||
setTimeout(()=>{
|
||||
passwordComfirm.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
}
|
||||
|
||||
function changeRegisterType(type){
|
||||
setGetCaptchaBut(false);
|
||||
setRegisterType(type);
|
||||
setFieldsValue({'email': undefined})
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="right_cont Register_content">
|
||||
<div className="login_register_head mb30">
|
||||
<p>欢迎注册 <span className="head_blue">群智开发</span></p>
|
||||
</div>
|
||||
<div className="registerNav mb28 font-16">
|
||||
<a className={`type ${registerType ? '' : 'activeRegisterNav'}`} onClick={()=>{changeRegisterType(0)}}>手机号注册</a>
|
||||
<a className={`type ${registerType ? 'activeRegisterNav' : ''} ml50`} onClick={()=>{changeRegisterType(1)}}>邮箱注册</a>
|
||||
</div>
|
||||
<p className={mess ? "message active" : "message"}>{mess}</p>
|
||||
<Form className="login-form">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('register_username',{
|
||||
rules:[
|
||||
{
|
||||
transform: (value)=>{return value.trim()}
|
||||
},
|
||||
{
|
||||
required:true,
|
||||
message:"请输入用户名"
|
||||
},
|
||||
{
|
||||
pattern: /^[a-zA-Z]/,
|
||||
message: "用户名必须以字母开头"
|
||||
},
|
||||
{
|
||||
pattern: /[a-zA-Z0-9]$/,
|
||||
message: "用户名只能使用英文字母和数字"
|
||||
},
|
||||
{
|
||||
pattern: /^[^\s]*$/,
|
||||
message: "用户名不能包含空格"
|
||||
},
|
||||
{
|
||||
min: 4,
|
||||
max: 15,
|
||||
message: "用户名长度为4到15个字符"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { usernameConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input className="account" autoFocus placeholder="请输入4-15位用户名,以字母开头,只能使用字母和数字" autoComplete="off" prefix={<div className="input_icon"></div>} />)}
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('email',{
|
||||
rules:[
|
||||
{
|
||||
validator: (rule, value, callback) => { emailConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input className={`${registerType ? 'email' : 'phone'}`} placeholder={`请输入${registerType ? '邮箱地址' : '手机号'}`} autoComplete="off" prefix={<div className="input_icon"></div>} />)}
|
||||
</Form.Item>
|
||||
|
||||
{/* <Form.Item>
|
||||
<div className="login_register_head">
|
||||
{getFieldDecorator('captcha', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: "请输入验证码"
|
||||
}],
|
||||
validateTrigger: "onBlur",
|
||||
})(
|
||||
<Input className="captcha" placeholder="请输入验证码" autoComplete="off"/>
|
||||
)}
|
||||
<Button className={getCaptchaBut ? 'codeBut':'codeBut disable'} disabled={!getCaptchaBut} onClick={getCaptcha}>{getCaptchaBut || (!getCaptchaBut && !countDown)?"获取验证码":`重发(${secondsStr}s)`}</Button>
|
||||
</div>
|
||||
</Form.Item> */}
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('register_psd',{
|
||||
rules:[
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmPassWord(rule, value, callback, 1) }
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { checkPassWord(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input.Password className="register_psd" placeholder="请输入8-16位密码,区分大小写、不能使用空格" onBlur={clear} onChange={clear} autoComplete="new-password" prefix={<div className="input_icon"></div>} />)}
|
||||
</Form.Item>
|
||||
{/* <span className="password_tips" style={{display:tipVisable?"none":"block"}}>请输入8-16位密码,区分大小写、不能使用空格</span> */}
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('psdComfirm', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请确认登录密码"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmPassWord(rule, value, callback, 2) }
|
||||
}
|
||||
],
|
||||
validateTrigger: "onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input.Password className="psdComfirm" placeholder="请确认登录密码" onBlur={clear} onChange={clear} autoComplete="new-password" prefix={<div className="input_icon"></div>} />)}
|
||||
</Form.Item>
|
||||
|
||||
{/* <Form.Item className="register_last_form">
|
||||
{getFieldDecorator('agreement', {
|
||||
valuePropName: 'checked',
|
||||
initialValue: false,
|
||||
rules: [
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmRead(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
})(<Checkbox className="link_span">我已阅读并接受<a className="login-form-forgot" href="https://forum.trustie.net/forums/5029/detail" target="_blank">《软件发展新技术服务协议条款》</a></Checkbox>)}
|
||||
</Form.Item> */}
|
||||
<Button type="primary" htmlType="submit" className="login_register_cofBut" onClick={handleSubmit}>注册</Button>
|
||||
</Form>
|
||||
<div className="link_span">已有账号,<Link to={`/login`}>立即登录</Link></div>
|
||||
{/* <OtherLogin /> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create({ name: 'register' })(Register);
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Form, Input, Button, message } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import axios from 'axios';
|
||||
import { setmiyah } from 'educoder';
|
||||
import './LoginRegisterPageNew.scss';
|
||||
import { Encrypt } from "../../common/Env";
|
||||
|
||||
function ResetPassword(props) {
|
||||
const {form, mygetHelmetapi } = props;
|
||||
const {getFieldDecorator } = form;
|
||||
const [emailStr, setEmailStr] = useState(undefined);
|
||||
const [secondsStr, setSecondsStr] = useState(60);
|
||||
const [countDown, setCountDown] = useState(false);
|
||||
const [getCaptchaBut, setGetCaptchaBut] = useState(false);
|
||||
const [mess, setMess] = useState(undefined);
|
||||
const [tipVisable, setTipVisable] = useState(false);
|
||||
//用于限制表单提交时会再次调用check.json接口校验数据
|
||||
const [emailGo, setEmailGo] = useState(true);
|
||||
const seconds = useRef();
|
||||
let interval = undefined;
|
||||
|
||||
// 配置网页标题
|
||||
useEffect(()=>{
|
||||
if(mygetHelmetapi){
|
||||
const {name} = mygetHelmetapi;
|
||||
document.title = name;
|
||||
}
|
||||
}, [mygetHelmetapi])
|
||||
|
||||
//重置密码表单提交
|
||||
function handleSubmit() {
|
||||
form.validateFieldsAndScroll((err, values) => {
|
||||
if (!err) {
|
||||
axios.post(`/accounts/reset_password.json`, {
|
||||
login: values.email,
|
||||
password: Encrypt(values.psd),
|
||||
password_confirmation: Encrypt(values.psdComfirm),
|
||||
code: values.captcha,
|
||||
}).then((response) => {
|
||||
if (response.data.status === 0) {
|
||||
//重置密码成功,调用登录接口
|
||||
axios.post(`/accounts/login.json`, {
|
||||
login: values.email,
|
||||
password: Encrypt(values.psd)
|
||||
}).then((login_response) => {
|
||||
if (!login_response.data.login) {
|
||||
setMess(login_response.data.message);
|
||||
} else {
|
||||
window.location.href = "/" + login_response.data.login;
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log('error',error);
|
||||
})
|
||||
} else {
|
||||
//设置邮箱内容-》不设置会被恢复成undefined,从而点击验证码失败
|
||||
setEmailStr(values.email);
|
||||
const message = response.data.message;
|
||||
message === "验证码不正确" ? form.setFields({captcha: {value:values.captcha,errors:[new Error('验证码错误,请重新输入')]}}) : setMess(message);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//判断邮箱/手机号是否符合规范、是否注册
|
||||
function emailConfirm(rule, value, callback) {
|
||||
if(/^([1][3456789])\d{9}$/.test(value) || /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/.test(value)){
|
||||
setEmailGo(true);
|
||||
if(value && (emailGo || value !== emailStr)){
|
||||
axios.get(`/accounts/valid_email_and_phone.json`, {
|
||||
params: {
|
||||
login: value,
|
||||
type: 2
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.data && !response.data.status) {
|
||||
setEmailStr(value);
|
||||
setGetCaptchaBut(true);
|
||||
setEmailGo(false);
|
||||
callback();
|
||||
} else {
|
||||
setGetCaptchaBut(false);
|
||||
callback('此手机号/邮箱未注册');
|
||||
}
|
||||
})
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
// setEmailStr(undefined);
|
||||
}else{
|
||||
callback("请输入正确的手机号/邮箱")
|
||||
}
|
||||
}
|
||||
|
||||
//确认密码
|
||||
function comfirmPassWord(rule, value, callback, index) {
|
||||
if ((index === 2 && value && form.getFieldValue('psd') && value !== form.getFieldValue('psd')) || (index === 1 && value && form.getFieldValue('psdComfirm') && value !== form.getFieldValue('psdComfirm'))) {
|
||||
if(index===1){
|
||||
form.setFields({psdComfirm: {value:form.getFieldValue('psdComfirm'),errors:[new Error('密码不一致,请重新输入')]}});
|
||||
callback();
|
||||
}else{
|
||||
callback('密码不一致,请重新输入');
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
//检查密码是否符合格式
|
||||
function checkPassWord(rule, value, callback){
|
||||
if(!value){
|
||||
setTipVisable(true);
|
||||
callback('请输入新密码');
|
||||
}else if(/(?!.*\s)(?!^[\u4e00-\u9fa5]+$)^.{8,16}$/.test(value)){
|
||||
callback()
|
||||
}else{
|
||||
setTipVisable(true);
|
||||
if(value.length<8 || value.length>16){
|
||||
callback('密码长度为8-16个字符');
|
||||
}else{
|
||||
callback('密码不能使用空格');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//获取验证码
|
||||
function getCaptcha() {
|
||||
setMess(undefined);
|
||||
if (emailStr) {
|
||||
// 倒计时开始
|
||||
setCountDown(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 {
|
||||
//倒计时结束->可以获取验证码
|
||||
setGetCaptchaBut(true);
|
||||
setCountDown(false);
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
//请求获取验证码接口
|
||||
axios.get(`/accounts/get_verification_code.json`, {
|
||||
params: {
|
||||
login: emailStr,
|
||||
type: 2,
|
||||
smscode: setmiyah(emailStr),
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.data && response.data.status === 0) {
|
||||
//验证码发送成功
|
||||
let email = emailStr.substring(emailStr.indexOf("@")+1);
|
||||
message.success({content:<span>验证码已发送,请注意查收。{emailStr.indexOf("@") === -1 ? '' : <a href={`https://mail.${email}`} target="_blank">前往邮箱</a>}</span>});
|
||||
} else {
|
||||
//验证码发送失败,获取验证码按钮变灰并且文案变回【获取验证码】
|
||||
setGetCaptchaBut(false);
|
||||
setCountDown(false);
|
||||
clearInterval(interval);
|
||||
setMess(response.data.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//清除密码框的value属性->DOM看不见密码值
|
||||
function clear(){
|
||||
const password = document.getElementById("resetPassword_psd");
|
||||
const passwordComfirm = document.getElementById("resetPassword_psdComfirm");
|
||||
if(password && password.type==="password"){
|
||||
setTimeout(()=>{
|
||||
password.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
if(passwordComfirm && passwordComfirm.type==="password"){
|
||||
setTimeout(()=>{
|
||||
passwordComfirm.removeAttribute('value');
|
||||
},0)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="right_cont ResetPassword_content">
|
||||
<div className="login_register_head mb30">
|
||||
<span>找回密码</span>
|
||||
<span className="link_span">已有账号,<Link to={`/login`}>立即登录</Link></span>
|
||||
</div>
|
||||
<p className={mess ? "message active" : "message"}>{mess}</p>
|
||||
<Form className="login-form">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('email', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入已注册的手机号/邮箱"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { emailConfirm(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger: "onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input autoFocus className="account" placeholder="请输入已注册的手机号/邮箱"/>)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<div className="login_register_head">
|
||||
{getFieldDecorator('captcha', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: "请输入验证码"
|
||||
}],
|
||||
validateTrigger: "onBlur",
|
||||
})(
|
||||
<Input className="captcha" placeholder="请输入验证码" autoComplete="off"/>
|
||||
)}
|
||||
<Button className={getCaptchaBut ? 'codeBut':'codeBut disable'} disabled={!getCaptchaBut} onClick={getCaptcha}>{getCaptchaBut || (!getCaptchaBut && !countDown)?"获取验证码":`重发(${secondsStr}s)`}</Button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('psd', {
|
||||
rules: [
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmPassWord(rule, value, callback,1) }
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { checkPassWord(rule, value, callback) }
|
||||
}
|
||||
],
|
||||
validateTrigger: "onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input.Password className="psd" placeholder="请输入新密码" onBlur={clear} onChange={clear} autoComplete="new-password"/>)}
|
||||
</Form.Item>
|
||||
<span className="password_tips" style={{display:tipVisable?"none":"block"}}>请输入8-16位密码,区分大小写、不能使用空格</span>
|
||||
|
||||
<Form.Item>
|
||||
{getFieldDecorator('psdComfirm', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请确认新密码"
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => { comfirmPassWord(rule, value, callback,2) }
|
||||
}
|
||||
],
|
||||
validateTrigger: "onBlur",
|
||||
validateFirst: true,
|
||||
})(<Input.Password className="psdComfirm" placeholder="请确认新密码" onBlur={clear} onChange={clear} autoComplete="new-password"/>)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" className="login_register_cofBut" onClick={handleSubmit}>重置密码并登录</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
export default Form.create({ name: 'resetPassword' })(ResetPassword);
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* 登录临时用 */
|
||||
|
||||
@font-face {
|
||||
font-family: "alibaba";
|
||||
src: url('./AlibabaPuHuiTi-Regular.woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: "alibaba-medium";
|
||||
src: url('./AlibabaPuHuiTi-Medium.woff2') format('woff');
|
||||
font-display: swap;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 394 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -23,13 +23,11 @@ body>.-task-title {
|
|||
overflow: hidden;
|
||||
}
|
||||
.newHeaders{
|
||||
max-width: unset;
|
||||
width: 100%;
|
||||
height:7vh;
|
||||
min-width: 1200px;
|
||||
z-index: 1001;
|
||||
position: fixed;
|
||||
background: #234175;
|
||||
height: 62px;
|
||||
padding: 0 30px;
|
||||
min-height: 50px;
|
||||
background: url('../../images/headerBg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
color: #fff;
|
||||
}
|
||||
.newHeaders.publicNav{
|
||||
|
|
@ -38,11 +36,21 @@ body>.-task-title {
|
|||
}
|
||||
.headerContent{
|
||||
margin:0px auto;
|
||||
padding:0px 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
justify-content: flex-end;
|
||||
justify-content: space-between;
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: YouSheBiaoTiHei;
|
||||
}
|
||||
.font32 {
|
||||
font-size: 32px;
|
||||
}
|
||||
.font24 {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
.globalSpin {
|
||||
max-height: 700px !important;
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ export function TPMIndexHOC(WrappedComponent) {
|
|||
/> : ""}
|
||||
{npsModalVisible && <NpsModal closeNpsModal={()=>{this.closeNpsModal()}} npsActionType={npsActionType} npsActionId={npsActionId}/>}
|
||||
{ !pathCheck && <Header {...this.state} {...this.props} {...common} publicNav={publicNav}></Header> }
|
||||
{!publicNav && <div style={{height:"7vh"}}></div> }
|
||||
{/* {!publicNav && <div style={{height:"7vh"}}></div> } */}
|
||||
<div className="flexTop">
|
||||
{/* { !(this.hideNavPath(path)) &&
|
||||
<ul className="navBox">
|
||||
|
|
|
|||