pr部分与版本发布部分

dev_forge
dingyongkang 5 years ago
parent 9382c21a2a
commit 30434866cb

@ -45,7 +45,7 @@ export function initAxiosInterceptors(props) {
// https://github.com/axios/axios/issues/1497
// TODO 读取到package.json中的配置
var proxy = "http://localhost:3000"
var //proxy = "http://localhost:3000"
//proxy = "http://testbdweb.trustie.net"
//proxy = "http://testbdweb.educoder.net"
// proxy = "https://testeduplus2.educoder.net"
@ -54,7 +54,7 @@ export function initAxiosInterceptors(props) {
// proxy="https://test-newweb.educoder.net"
//proxy="https://test-jupyterweb.educoder.net"
//proxy="http://192.168.2.63:3001"
// proxy="http://123.59.135.93:56666"
proxy="http://123.59.135.93:56666"
// 在这里使用requestMap控制避免用户通过双击等操作发出重复的请求
// 如果需要支持重复的请求考虑config里面自定义一个allowRepeat参考来控制

@ -66,6 +66,38 @@ const MergeIndexDetail = Loadable({
loader: () => import('../Merge/merge'),
loading: Loading,
})
const CreateMerge = Loadable({
loader: () => import('../Merge/NewMerge'),
loading: Loading,
})
const MessageCount = Loadable({
loader: () => import('../Merge/MessageCount'),
loading: Loading,
})
const MergeSubmit = Loadable({
loader: () => import('../Merge/MergeSubmit'),
loading: Loading,
})
const UpdateMerge = Loadable({
loader: () => import('../Merge/UpdateMerge'),
loading: Loading,
})
//版本发布
const VersionIndex = Loadable({
loader: () => import('../Version/version'),
loading: Loading,
})
const NewVersionIndex = Loadable({
loader: () => import('../Version/NewVersion'),
loading: Loading,
})
const TrendsIndex = Loadable({
loader: () => import('../Activity/Activity'),
loading: Loading,
@ -274,7 +306,7 @@ class Detail extends Component{
<li className={(url.indexOf("coder")>0 || urlFlag)? "active" : ""}><Link to={`/projects/${projectsId}/coder`}>代码</Link></li>
<li className={url.indexOf("orders")>0 ? "active" : ""}><Link to={`/projects/${projectsId}/orders`}>工单{projectDetail&&projectDetail.issues_count===0?"":projectDetail&&projectDetail.issues_count===0?projectDetail.issues_count:""}</Link></li>
<li className={url.indexOf("merge")>0 ? "active" : ""}><Link to={`/projects/${projectsId}/merge`}>合并请求{projectDetail&&projectDetail.pull_requests_count===0?"":projectDetail&&projectDetail.pull_requests_count===0?projectDetail.pull_requests_count:""}</Link></li>
<li className={url.indexOf("edition")>0 ? "active" : ""}><Link to={`/projects/${projectsId}/edition`}>版本发布</Link></li>
<li className={url.indexOf("version")>0 ? "active" : ""}><Link to={`/projects/${projectsId}/version`}>版本发布</Link></li>
<li className={url.indexOf("trends")>0 ? "active" : ""}><Link to={`/projects/${projectsId}/trends`}>动态</Link></li>
{
isManager &&
@ -373,6 +405,43 @@ class Detail extends Component{
(props) => (<OrderIndex {...this.props} {...props} {...this.state}/>)
}
></Route>
<Route path="/projects/:projectsId/merge/new"
render={
(props) => (<CreateMerge {...this.props} {...props} {...this.state}/>)
}
></Route>
<Route path="/projects/:projectsId/merge/:mergeId/UpdateMerge"
render={
(props) => (<UpdateMerge {...this.props} {...props} {...this.state}/>)
}
></Route>
<Route path="/projects/:projectsId/merge/:mergeId/Messagecount"
render={
(props) => (<MessageCount {...this.props} {...props} {...this.state}/>)
}
></Route>
<Route path="/projects/:projectsId/merge/:mergeId/MergeSubmit"
render={
(props) => (<MergeSubmit {...this.props} {...props} {...this.state}/>)
}
></Route>
<Route path="/projects/:projectsId/version/new"
render={
(props) => (<NewVersionIndex {...this.props} {...props} {...this.state}/>)
}
></Route>
<Route path="/projects/:projectsId/version"
render={
(props) => (<VersionIndex {...this.props} {...props} {...this.state}/>)
}
></Route>
<Route path="/projects/:projectsId/merge"
render={
(props) => (<MergeIndexDetail {...this.props} {...props} {...this.state}/>)

@ -0,0 +1,322 @@
import React , {Component} from 'react';
import {Link} from 'react-router-dom';
import axios from 'axios';
import Nav from '../Order/Nav';
import UploadComponent from '../Upload/Index';
import{ Modal,Col,Form,Input,Tooltip,Popconfirm } from 'antd'
import NoneData from '../../modules/courses/coursesPublic/NoneData';
const TextArea = Input.TextArea;
class MergeDetail extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
isShow:false,
imgsrc:'',
journalsdata:undefined,
//图片区域是否显示 none 隐藏 block 显示
display:'none',
titledisplay:'none',
countvalue:'',
//是否需要编辑
isedit:'block'
}
}
componentDidMount=()=>{
this.getDetail();
}
getDetail=()=>{
const { projectsId , mergeid} = this.props.match.params;
const url = `/projects/${projectsId}/pull_requests/${mergeid}.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
data:result.data,
})
this.getjournalslist();
}
}).catch((error)=>{
console.log(error);
})
}
handleok=() => {
this.setState({
isShow:false
});
};
handleCancel=()=>{
this.setState({
isShow:false
});
}
imgshow=()=>{
this.setState({
isShow:true
});
};
//添加评论
addjournals=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
const { data } = this.state;
const url = `/issues/${data.pull_request.id}/journals.json`;
axios.post(url,{
...values,
issue_id:data.id,
}).then(result=>{
if(result){
this.getjournalslist();
}
}).catch(error=>{
console.log(error);
})
}
})
}
//获取评论信息
getjournalslist=()=>{
const { data } = this.state;
const url = `/issues/${data.pull_request.id}/journals.json`;
let id=data.id;
axios.get(url,{
params:{
id
}
}).then(result=>{
if(result){
this.setState({
journalsdata:result.data
})
}
}).catch(error=>{
console.log(error);
})
}
//关闭工单
closedetail=(id)=>{
const {projectsId,orderId} = this.props.match.params;
const url = `/projects/${projectsId}/issues/${orderId}/close_issue.json`;
axios.post(url,{
project_id:projectsId,
id:orderId,
status_id:id,
}).then(result=>{
if(result){
this.getDetail();
}
}).catch(error=>{
console.log(error);
})
}
//修改评论
updatedetail=(id)=>{
const {mergeid} = this.props.match.params;
const url = `/issues/${mergeid}/journals/${id}.json`;
axios.put(url,{
issue_id:mergeid,
id:id,
content:this.state.countvalue
}).then(result=>{
if(result){
this.setState({
isedit:'block'
})
this.getjournalslist();
}
}).catch(error=>{
console.log(error);
})
}
changmodelname=(e)=>{
this.setState({
countvalue:e.target.value
})
}
editdetail=(count,status)=>{
this.setState({
countvalue:count,
isedit:status
})
}
render(){
const { projectsId,mergeid} = this.props.match.params;
const { data,journalsdata } = this.state;
const { getFieldDecorator } = this.props.form;
const url = this.props.history.location.pathname;
const renderList =()=>{
if(journalsdata && journalsdata.issue_journals && journalsdata.issue_journals.length>0 ){
return(
<div className="tagList">{
journalsdata.issue_journals.map((item,key)=>{
return(
<li>
<div className="df">
<Link to={``}><img class="user_img" src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/></Link>
<div className="detail_context" >
<div className="topWrapper_detali">
<p className="detail_p">{item.user_name}
<Tooltip title={item.format_time} placement="bottom">
<span className="commenttitle">{item.created_at}</span>
</Tooltip>
评论</p>
<div className="detail_right">
<i className="iconfont icon-weibiaoti1 font-18 mr3" onClick={()=>this.editdetail(item.content,'none')}></i>
<div style={{width:20}}></div>
<Popconfirm placement="bottom" title={'确定要删除当前评论吗'} okText="是" cancelText="否" onConfirm={()=>this.deletedetail(item.id)}>
<i className="iconfont icon-yiguanbi1 font-18 mr3"></i>
</Popconfirm>
</div>
</div>
<div className="detail_ptitlecount">
<p style={{display:this.state.isedit}} >{item.content}</p>
<div style={{display:this.state.isedit==='none'?'block':'none'}}>
<TextArea style={{height:"200px"}} value={this.state.countvalue} onChange={this.changmodelname}/>
<p className="clearfix mt15">
<a className="topWrapper_btn fr" type="submit" onClick={()=>this.updatedetail(item.id)}>保存</a>
<a className="Closeor_btn fr" type="submit" onClick={()=>this.editdetail(item.content,'block')}>取消</a>
</p>
</div>
</div>
<div style={{display: this.state.display}}>
<div className="div_line" ></div>
{/* <List
grid={{ gutter: 16, column: 6 }}
dataSource={valuse}
renderItem={obj => (
<List.Item>
<img class="list_img" onClick={this.imgshow} src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/>
</List.Item>
)}
/> */}
</div>
</div>
</div>
<div className="order_line" style={{marginLeft:80}}></div>
</li>
)
})
}
</div>
)
}else{
return(
<NoneData />
)
}
}
return(
<div className="main">
<div className="topWrapper">
<Nav {...this.props} {...this.state}/>
<Link to={`/projects/${projectsId}/merge/new`} className="topWrapper_btn">创建合并请求</Link>
</div>
<div>
<div className="detailContent">
<p>
<span className="font-16" > { data && data.issue.subject}</span>
<div>
<Link to={`/projects/${projectsId}/merge/${mergeid}/updatemerge`} className="color-blue fr">编辑</Link>
</div>
</p>
<p className="mt15">{ data && data.issue.description}</p>
<p className="mt10 color-grey-c">
<div className={data&&data.issue_status==="关闭"?"closedetail":"opendetail"}>{data&&data.issue_status==="关闭"?"关闭中!":"开启中!"} </div>
{ data && data.issue.author_name} { data && data.issue.created_at }创建{ data && data.issue.journals_count && data.issue.journals_count > 0 ?` · ${data.issue.journals_count} 条评论`:""}
</p>
</div>
<div className="detailHeader-wrapper">
<div className="normal f-wrap-between">
<ul className="headerMenu-wrapper">
<li className={url.indexOf("Messagecount")>0? "active" : ""}><Link to={`/projects/${projectsId}/merge/${mergeid}/Messagecount`}>对话内容</Link></li>
<li className={url.indexOf("MergeSubmit")>0 ? "active" : ""}><Link to={`projects/${projectsId}/merge/${mergeid}/MergeSubmit`}>代码提交</Link></li>
</ul>
</div>
</div>
<div className="f-wrap-between mt20" style={{alignItems:"flex-start"}}>
<div className="list-right df divwidth" >
<ul className="ul_width">
{renderList()}
<li>
<div className="df">
<Link to={``}><img class="user_img" onClick={this.imgshow} src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/> </Link>
<div className="new_context">
<Form.Item>
{getFieldDecorator('content', {
rules: [{
required: true, message: '请输入内容'
}],
})(
<TextArea placeholder="添加一个可选的扩展描述。。。" style={{height:"200px"}}/>
)}
</Form.Item>
<UploadComponent load={this.UploadFunc}></UploadComponent>
<p className="clearfix mt15">
<a className="topWrapper_btn fr" type="submit" onClick={this.addjournals}>评论</a>
<a className="Closeor_btn fr" type="submit" onClick={()=>this.closedetail(data&&data.issue_status==="关闭"?2:5)}>{data&&data.issue_status==="关闭"?"开启":"关闭"}</a>
</p>
</div>
</div>
</li>
</ul>
</div>
<div className="list-left DetailRight">
<p>
<span className="span_title">当前状态</span>
<span>{data && data.issue.issue_status}</span>
</p>
<p>
<span className="span_title">优先级</span>
<span>{data && data.issue.priority}</span>
</p>
<p>
<span className="span_title">指派给</span>
<span>{data && data.issue.assign_user_name}</span>
</p>
<p>
<span className="span_title">里程碑</span>
<span>{data&&data.issue.version===null?"未添加里程碑":data&&data.issue.version.length===0?data.issue.version:'未添加里程碑'}</span>
</p>
</div>
</div>
</div>
<Modal
onCancel={this.handleCancel}
visible={this.state.isShow}
width="400px"
footer={
[]
}
bodyStyle={{textAlign:'center'}}
>
<img class="list_img" src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/>
</Modal>
</div>
)
}
}
const WrappedMergeDetailForm = Form.create({ name: 'MergeDetailOrderForm' })(MergeDetail);
export default WrappedMergeDetailForm;

@ -14,22 +14,13 @@ class MergeItem extends Component{
<div className="flex-1">
<p className="mb15 df">
<span className="issueNo"># {search_count - (key + (page-1) * limit)}</span>
<Link to={`/projects/${projectsId}/orders/${item.id}/detail`} className="flex-1 hide-1 font-16 color-grey-3 lineh-30">{item.name}</Link>
<Link to={`/projects/${projectsId}/merge/${item.pull_request_id}/Messagecount`} className="flex-1 hide-1 font-16 color-grey-3 lineh-30">{item.name}</Link>
</p>
<p className="color-grey-6">
<span>{item.created_at}</span>
{ item.journals_count ? <span className="ml20"><i className="iconfont icon-pinglun1 mr3 font-16"></i>{item.journals_count}</span> : "" }
</p>
</div>
<ul className="topWrapper_select">
<li>{item.issue_tags || "--"}</li>
<li>{item.issue_type || "--"}</li>
<li>{item.tracker || "--"}</li>
<li>{item.author_name || "--"}</li>
<li>{item.assign_user_name || "--"}</li>
<li>{item.priority || "--"}</li>
<li>{item.done_ratio || "--"}</li>
</ul>
</div>
)
})

@ -0,0 +1,204 @@
import React , {Component} from 'react';
import {Link} from 'react-router-dom';
import axios from 'axios';
import Nav from '../Order/Nav';
import UploadComponent from '../Upload/Index';
import{ Modal,Col,Form,Input,Tooltip,Popconfirm,Table} from 'antd'
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import { getImageUrl } from 'educoder';
const TextArea = Input.TextArea;
class MergeSubmit extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
isShow:false,
imgsrc:'',
journalsdata:undefined,
//图片区域是否显示 none 隐藏 block 显示
display:'none',
titledisplay:'none',
countvalue:'',
//是否需要编辑
isedit:'block',
limit:50,
page:1,
titledata:undefined,
}
}
componentDidMount=()=>{
this.getDetail();
}
getDetail=()=>{
const { projectsId , mergeId} = this.props.match.params;
const url = `/projects/${projectsId}/pull_requests/${mergeId}.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
data:result.data,
})
const { page , limit } = this.state;
this.getCommitList( result.data.pull_request.base , page , limit );
}
}).catch((error)=>{
console.log(error);
})
}
handleok=() => {
this.setState({
isShow:false
});
};
handleCancel=()=>{
this.setState({
isShow:false
});
}
imgshow=()=>{
this.setState({
isShow:true
});
};
//获取提交列表
getCommitList=(branch , page , limit)=>{
const { login } = this.props.current_user;
const { projectsId } = this.props.match.params;
const url = `/${login}/${projectsId}/commits.json`;
axios.get(url,{
params:{
sha:branch,
page,
limit
}
}).then((result)=>{
if(result){
const array = [];
result.data && result.data.commits.length > 0 && result.data.commits.map((item,key)=>{
array.push({
name:item.author && item.author.name,
image_url:item.author && item.author.image_url,
sha:item.sha,
time_from_now:item.time_from_now,
message:item.message
})
})
this.setState({
titledata:array,
dataCount:result.data.total_count,
isSpin:false
})
}
}).catch((error)=>{console.log(error)})
}
render(){
const { projectsId,mergeId} = this.props.match.params;
const { data,titledata} = this.state;
const columns=[{
title:"作者",
dataIndex: 'name',
width:"10%",
render: (text,item) => (
<span className="f-wrap-alignCenter">
<img src={getImageUrl(`images/${item.image_url}`)} alt="" width="28px" height="28px" className="mr3 radius"/>
<label className="hide-1" style={{maxWidth:"75px"}}>{text}</label>
</span>
),
},{
title:"SHA",
dataIndex: 'sha',
render: (text) => (
<span className="commitKey">{text}</span>
)
},{
title:"备注",
dataIndex: 'message',
render: (text) => (
<span>{text}</span>
)
},{
title:"提交时间",
className:"edu-txt-right",
dataIndex: 'time_from_now',
render: (text) => (
<span>{text}</span>
)
}]
const title =()=>{
return(
<div className="f-wrap-between" style={{alignItems:"center"}}>
<span className="font-16">提交列表</span>
{/* <div className="f-wrap-alignCenter">
<Input placeholder="搜索提交历史" style={{width:"300px"}}/>
<Checkbox className="ml15">所有分支</Checkbox>
<a className="btn_32 ml15">搜索</a>
</div> */}
</div>
)
}
const url = this.props.history.location.pathname;
return(
<div className="main">
<div className="topWrapper">
<Nav {...this.props} {...this.state}/>
<Link to={`/projects/${projectsId}/merge/new`} className="topWrapper_btn">创建合并请求</Link>
</div>
<div>
<div className="detailContent">
<p>
<span className="font-16" > { data && data.issue.subject}</span>
<div>
<Link to={`/projects/${projectsId}/merge/${mergeId}/UpdateMerge`} className="color-blue fr">编辑</Link>
</div>
</p>
<p className="mt15">{ data && data.issue.description}</p>
<p className="mt10 color-grey-c">
<div className={data&&data.issue_status==="关闭"?"closedetail":"opendetail"}>{data&&data.issue_status==="关闭"?"关闭中!":"开启中!"} </div>
{ data && data.issue.author_name} { data && data.issue.created_at }创建{ data && data.issue.journals_count && data.issue.journals_count > 0 ?` · ${data.issue.journals_count} 条评论`:""}
</p>
</div>
<div className="detailHeader-wrapper">
<div className="normal f-wrap-between">
<ul className="headerMenu-wrapper">
<li className={url.indexOf("Messagecount")>0? "active" : ""}><Link to={`/projects/${projectsId}/merge/${mergeId}/Messagecount`}>对话内容</Link></li>
<li className={url.indexOf("MergeSubmit")>0 ? "active" : ""}><Link to={`/projects/${projectsId}/merge/${mergeId}/MergeSubmit`}>代码提交</Link></li>
</ul>
</div>
</div>
<Table
className="mt20 wrap-commit-table"
columns={columns}
dataSource={titledata}
showHeader={false}
size="small"
pagination={false}
title={() => title()}
/>
</div>
</div>
)
}
}
const WrappedMergeSubmitForm = Form.create({ name: 'MergeSubmitForm' })(MergeSubmit);
export default WrappedMergeSubmitForm;

@ -0,0 +1,472 @@
import React , {Component} from 'react';
import {Link} from 'react-router-dom';
import axios from 'axios';
import Nav from '../Order/Nav';
import UploadComponent from '../Upload/Index';
import { getImageUrl } from 'educoder';
import {Modal, Col, Form, Input, Tooltip, Popconfirm, Pagination , Spin} from 'antd'
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import Attachments from '../Upload/attachment'
const TextArea = Input.TextArea;
class MessageCount extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
isShow:false,
imgsrc:'',
journalsdata:undefined,
//图片区域是否显示 none 隐藏 block 显示
display:'none',
titledisplay:'none',
countvalue:'',
//是否需要编辑
isedit:undefined,
fileList:undefined,
limit:10,
page:1,
search_count:undefined,
isSpin:false,
showFiles: true
}
}
componentDidMount=()=>{
this.getDetail();
}
getDetail=()=>{
const { projectsId , mergeId} = this.props.match.params;
const url = `/projects/${projectsId}/pull_requests/${mergeId}.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
data:result.data
})
this.getjournalslist();
}
}).catch((error)=>{
console.log(error);
})
}
handleok=() => {
this.setState({
isShow:false
});
};
handleCancel=()=>{
this.setState({
isShow:false
});
}
imgshow=()=>{
this.setState({
isShow:true
});
};
//添加评论
addjournals=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
const { data, page, limit, fileList } = this.state;
const url = `/issues/${data.issue.id}/journals.json`;
axios.post(url,{
...values,
issue_id:data.id,
attachment_ids:fileList
}).then(result=>{
if(result){
this.props.form.setFieldsValue({
content: "",
attachments_ids: undefined
});
this.setState({
showFiles: false
})
this.getjournalslist(page, limit);
this.props.showNotification("评论成功!");
// this.UploadFunc(undefined)
}
}).catch(error=>{
console.log(error);
})
}
})
}
//获取评论信息
getjournalslist=(page, limit)=>{
const { data} = this.state;
const url = `/issues/${data.issue.id}/journals.json`;
let id=data.id;
axios.get(url,{
params:{
id,page,limit
}
}).then(result=>{
if(result){
this.setState({
journalsdata:result.data,
search_count:result.data.journals_count,
isSpin:false,
fileList:undefined,
showFiles: true
})
}
}).catch(error=>{
console.log(error);
})
}
//关闭工单
closedetail=(id)=>{
const {projectsId,orderId} = this.props.match.params;
const {data } = this.state;
const url = `/projects/${projectsId}/issues/${data.issue.id}/close_issue.json`;
axios.post(url,{
project_id:projectsId,
id:orderId,
status_id:id,
}).then(result=>{
if(result){
this.getDetail();
}
}).catch(error=>{
console.log(error);
})
}
//修改评论
updatedetail=(id)=>{
console.log("updtedetail", this.state)
const {page, limit,data } = this.state;
const {orderId} = this.props.match.params;
const url = `/issues/${data.issue.id}/journals/${id}.json`;
axios.put(url,{
issue_id:orderId,
id:id,
content:this.state.countvalue
}).then(result=>{
if(result){
this.setState({
isedit: undefined
})
this.getjournalslist(page, limit);
}
}).catch(error=>{
console.log(error);
})
}
// 获取上传后的文件id数组
UploadFunc=(fileList)=>{
this.setState({
fileList
})
}
//删除评论
deleteorder=(id)=>{
const { orderId} = this.props.match.params;
const { page, limit,data } = this.state;
const url = `/issues/${data.issue.id}/journals/${id}.json`;
axios.delete(url,{ data: {
issue_id: orderId,
id:id
}
}).then((result)=>{
if(result){
this.getjournalslist(page,limit)
}
}).catch((error)=>{
console.log(error);
})
}
changmodelname=(e)=>{
this.setState({
countvalue:e.target.value
})
}
editdetail=(count,status)=>{
this.setState({
countvalue:count,
isedit:status
})
}
renderJournalList=(list)=>{
if(list && list.length >0){
return(
list.map((item,key)=>{
return(
<div key={key+1} className="journal-list-item">
<span className="font-weight-bold mr3">
{item.detail}
</span>
<span className="mr5 color-grey-9">
{item.old_value.length > 0 ? "更新为" : "新增"}
</span>
<span>
{item.value && item.value.length > 0 ?
item.detail === "标签" ? <span className="issue-tag-show" style={{background: item.value[0].color}}>{item.value[0].name}</span> : item.value
:
"无"
}
</span>
</div>
)
})
)
}else{
return(
<div>
<span>没有评论~</span>
</div>
)
}
}
// 翻页
ChangePage=(page)=>{
this.setState({
page,
isSpin:true
})
const {limit} = this.state;
this.getjournalslist(page,limit);
}
render(){
const { projectsId,mergeId} = this.props.match.params;
const { data,journalsdata, page, limit, search_count, isSpin, isedit, showFiles } = this.state;
const { getFieldDecorator } = this.props.form;
const { current_user } = this.props;
const url = this.props.history.location.pathname;
const Paginations = (
<React.Fragment>
{
search_count > limit ?
<div className="pt30 mb50 edu-txt-center btp1">
<Pagination simple defaultCurrent={page} total={search_count} pageSize={limit} onChange={this.ChangePage}></Pagination>
</div>:""
}
</React.Fragment>
)
const renderList =()=>{
if(journalsdata && journalsdata.issue_journals && journalsdata.issue_journals.length>0 ){
return(
<div className="tagList">{
journalsdata.issue_journals.map((item,key)=>{
return(
<li key={key}>
<div className="df">
<Link to={``}><img className="user_img" src={getImageUrl(`images/${item.user_picture && item.user_picture}`)} alt=""/></Link>
<div className="detail_context" >
<div className="topWrapper_detali">
<p className="ml6 detail_p lineH40">
{item.user_name}
<span className="color-grey-9 ml3 mr3">评论于</span>
<Tooltip title={item.format_time} placement="bottom">
<span>{item.created_at}</span>
</Tooltip>
</p>
<div className="detail_right" style={{display: current_user && (current_user.admin || current_user.login === item.user_login) ? "block" : "none"}}>
<span onClick={()=>this.editdetail(item.content,item.id)} className="detail_edit_action">编辑</span>
<Popconfirm placement="bottom" title={'确定要删除当前评论吗'} okText="是" cancelText="否" onConfirm={()=>this.deleteorder(item.id)}>
<span className="detail_edit_action">删除</span>
</Popconfirm>
</div>
</div>
<div className="detail_ptitlecount">
<div style={{display: (isedit && isedit === item.id) ? "none" : "block"}} >
{
item.content ?
<div>{item.content}</div>
:
<div>
{this.renderJournalList(item.journal_details)}
</div>
}
{
item && item.attachments.length > 0 ?
<Attachments attachments={item.attachments} showNotification={this.props.showNotification} canDelete={current_user && (current_user.admin || current_user.login === item.user_login)}/>
:
""
}
</div>
<div style={{display: (isedit && isedit === item.id) ? "block" : "none"}}>
<TextArea style={{height:"200px"}} value={this.state.countvalue} onChange={this.changmodelname}/>
<p className="clearfix mt15">
<a className="topWrapper_btn fr" type="submit" onClick={()=>this.updatedetail(item.id)}>保存</a>
<a className="a_btn cancel_btn fr" type="submit" onClick={()=>this.editdetail(item.content,undefined)}>取消</a>
</p>
</div>
</div>
<div style={{display: this.state.display}}>
<div className="div_line" ></div>
</div>
</div>
</div>
<div className="order_line" style={{marginLeft:80}}></div>
</li>
)
})
}
</div>
)
}
}
return(
<div className="main">
<div className="topWrapper">
<Nav {...this.props} {...this.state}/>
<Link to={`/projects/${projectsId}/merge/new`} className="topWrapper_btn">创建合并请求</Link>
</div>
<div>
<div className="detailContent">
<p>
{
data ?
<span className="font-20">{ data.issue.tracker}</span>
:
""
}
<span className="font-20" > { data && data.issue.subject }</span>
</p>
<p className="mt10 color-grey-c">
<span className={data&&data.issue_status==="关闭"?"closedetail":"opendetail"}>{data&&data.issue_status==="关闭"?"关闭中":"开启中"} </span>
<span className="ml10 lineH32">
{ data && data.issue.author_name} { data && data.issue.created_at }创建{ data && data.issue.journals_count && data.issue.journals_count > 0 ?` · ${data.issue.journals_count} 条评论`:""}
</span>
<span className="pull-right lineH32">
<Link to={`/projects/${projectsId}/merge/${mergeId}/UpdateMerge`} className="color-blue fr">编辑</Link>
</span>
</p>
<div className="df mt20">
{
data && data.attachments.length > 0 ?
<Attachments attachments={data.attachments} showNotification={this.props.showNotification}/>
:
""
}
</div>
<div className="detailHeader-wrapper">
<div className="normal f-wrap-between">
<ul className="headerMenu-wrapper">
<li className={url.indexOf("Messagecount")>0? "active" : ""}><Link to={`/projects/${projectsId}/merge/${mergeId}/Messagecount`}>对话内容</Link></li>
<li className={url.indexOf("MergeSubmit")>0 ? "active" : ""}><Link to={`/projects/${projectsId}/merge/${mergeId}/MergeSubmit`}>代码提交</Link></li>
</ul>
</div>
</div>
</div>
<div className="f-wrap-between mt5" style={{alignItems:"flex-start"}}>
<div className="item-list-right" >
<Spin spinning={isSpin}>
<ul className="ul_width">
{renderList()}
</ul>
</Spin>
{ Paginations }
<div className="df">
<Link to={``}><img className="user_img"
src={getImageUrl(`images/${current_user && current_user.image_url}`)} alt=""/></Link>
<div className="new_context">
<Form.Item>
{getFieldDecorator('content', {
rules: [{
required: true, message: '请输入内容'
}],
})(
<TextArea placeholder="添加评论..." style={{height: "200px"}}/>
)}
</Form.Item>
<UploadComponent load={this.UploadFunc} isComplete={showFiles}></UploadComponent>
<p className="clearfix mt15">
<a className="topWrapper_btn fr" type="submit" onClick={this.addjournals}>评论</a>
<a className="Closeor_btn fr" type="submit"
onClick={() => this.closedetail(data && data.issue.issue_status === "关闭" ? 2 : 5)}>{data && data.issue.issue_status === "关闭" ? "开启" : "关闭"}</a>
</p>
</div>
</div>
</div>
<div className="list-left DetailRight mt10">
<p>
<span className="span_title">分支</span>
<span>{
data && data.issue.branch_name ? data.issue.branch_name : "--"
}</span>
</p>
<p>
<span className="span_title">标签</span>
<span>{
data && data.issue.issue_tags ? <span className="issue-tag-show" style={{background: data.issue.issue_tags[0].color}}>{data.issue.issue_tags[0].name}</span> : "--"
}</span>
</p>
<p>
<span className="span_title">里程碑</span>
<span>{
data && data.issue.version ? data.issue.version : "--"
}</span>
</p>
<p>
<span className="span_title">当前状态</span>
<span>{
data && data.issue.issue_status ? data.issue.issue_status : "--"
}</span>
</p>
<p>
<span className="span_title">分类</span>
<span>{
data && data.issue.tracker ? data.issue.tracker : "--"
}</span>
</p>
<p>
<span className="span_title">指派给</span>
<span>{data && data.issue.assign_user_name ? data.issue.assign_user_name : "--"}</span>
</p>
<p>
<span className="span_title">优先级</span>
<span>{data && data.issue.priority ? data.issue.priority : "--"}</span>
</p>
<p>
<span className="span_title">完成度</span>
<span>{data && data.issue.done_ratio ? data.issue.done_ratio : "--"}</span>
</p>
</div>
</div>
</div>
<Modal
onCancel={this.handleCancel}
visible={this.state.isShow}
width="400px"
footer={
[]
}
bodyStyle={{textAlign:'center'}}
>
<img className="list_img" src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/>
</Modal>
</div>
)
}
}
const MessageCountForm = Form.create({ name: 'MessageCountForm' })(MessageCount);
export default MessageCountForm;

@ -0,0 +1,353 @@
import React , {Component} from 'react';
import { Link } from 'react-router-dom';
import {Radio, Form,Menu,Dropdown,Input,Select,Table} from 'antd';
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import reactCSS from 'reactcss'
import axios from 'axios';
import moment from 'moment'
import UploadComponent from '../Upload/Index';
import { getImageUrl } from 'educoder';
const { Group, Button } = Radio;
const Option = Select.Option;
const TextArea = Input.TextArea;
class NewMerge extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
//合并 拉取
merge:undefined,
pull:undefined,
//判断 是否显示创建合并请求的页面
iscreatemerge:'none',
issue_tag_ids:"",
fixed_version_id:"",
assigned_to_id:"",
titledata:undefined,
dataCount:undefined,
limit:50,
page:1,
isSpin:false
}
}
componentDidMount=()=>{
this.getmergelist();
}
onPanelChange=(time, mode)=>{
this.setState({
value:time
});
}
onSelect=(time)=>{
this.setState({
value:time,
selectedValue: time,
});
}
getOption=(name,id)=>{
if(id==='branches'){
this.setState({
merge:name
})
}else{
if(this.state.merge===name){
}else{
const { page , limit } = this.state;
this.getCommitList( name , page , limit );
}
this.setState({
pull:name
})
}
}
ismerge=()=>{
this.setState({
iscreatemerge:'block'
})
const { page , limit } = this.state;
this.getCommitList( this.state.pull , page , limit );
}
//获取新建分枝数据
getmergelist=()=>{
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/pull_requests/new.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
data:result.data,
merge:result.data.branches[0],
pull:result.data.branches[0],
})
}
}).catch((error)=>{
console.log(error);
})
}
renderMenu =(array,id)=>{
return(
<Menu>
{
array && array.length > 0 && array.map((item,key)=>{
return(
<Menu.Item key={item} onClick={()=>this.getOption(item,id)}>{item}</Menu.Item>
)
})
}
</Menu>
)
}
renderSelect=(list)=>{
if(list && list.length >0){
return(
list.map((item,key)=>{
return(
<Option key={key+1} value={item.id+''}>{item.name}</Option>
)
})
)
}
}
//创建合并请求
submit=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/pull_requests.json`;
if(values.issue_tag_ids.length > 0){
values.issue_tag_ids = [parseInt(values.issue_tag_ids)]
}
axios.post(url,{
...values,
project_id:projectsId,
head:this.state.merge,
base:this.state.pull,
}).then(result=>{
if(result){
this.props.history.push(`/projects/${projectsId}/merge`);
}
}).catch(error=>{
console.log(error);
})
}
})
}
//获取提交列表
getCommitList=(branch , page , limit)=>{
const { login } = this.props.current_user;
const { projectsId } = this.props.match.params;
const url = `/${login}/${projectsId}/commits.json`;
axios.get(url,{
params:{
sha:branch,
page,
limit
}
}).then((result)=>{
if(result){
const array = [];
result.data && result.data.commits.length > 0 && result.data.commits.map((item,key)=>{
array.push({
name:item.author && item.author.name,
image_url:item.author && item.author.image_url,
sha:item.sha,
time_from_now:item.time_from_now,
message:item.message
})
})
this.setState({
titledata:array,
dataCount:result.data.total_count,
isSpin:false
})
}
}).catch((error)=>{console.log(error)})
}
render(){
const { getFieldDecorator } = this.props.form;
const { projectsId } = this.props.match.params;
const { current_user } = this.props;
const { issue_tag_ids , fixed_version_id ,assigned_to_id ,issue_chosen,data,titledata} = this.state;
const columns=[{
title:"作者",
dataIndex: 'name',
width:"10%",
render: (text,item) => (
<span className="f-wrap-alignCenter">
<img src={getImageUrl(`images/${item.image_url}`)} alt="" width="28px" height="28px" className="mr3 radius"/>
<label className="hide-1" style={{maxWidth:"75px"}}>{text}</label>
</span>
),
},{
title:"SHA",
dataIndex: 'sha',
render: (text) => (
<span className="commitKey">{text}</span>
)
},{
title:"备注",
dataIndex: 'message',
render: (text) => (
<span>{text}</span>
)
},{
title:"提交时间",
className:"edu-txt-right",
dataIndex: 'time_from_now',
render: (text) => (
<span>{text}</span>
)
}]
const title =()=>{
return(
<div className="f-wrap-between" style={{alignItems:"center"}}>
<span className="font-16">提交列表</span>
{/* <div className="f-wrap-alignCenter">
<Input placeholder="搜索提交历史" style={{width:"300px"}}/>
<Checkbox className="ml15">所有分支</Checkbox>
<a className="btn_32 ml15">搜索</a>
</div> */}
</div>
)
}
return(
<div className="main">
<h1 style={{marginLeft:15}}>创建合并请求</h1>
<h5 style={{marginLeft:15}}>选择合并的目标分支和源分支</h5>
<div style={{display:'flex'}}>
<div className="mergediv">
<div>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(this.state.data &&this.state.data.branches,'branches')} trigger={['click']} placement="bottomCenter">
<Button>合并到{this.state.merge}</Button>
</Dropdown>
...
<Dropdown overlay={this.renderMenu(this.state.data &&this.state.data.branches,'pull')} trigger={['click']} placement="bottomCenter">
<Button>拉取从{this.state.pull}</Button>
</Dropdown>
</div>
</div>
</div>
<div style={{display:this.state.iscreatemerge==='none'?'block':'none'}}>
<div className="mergediv" style={{marginTop:15}} >
{this.state.merge===this.state.pull?'分支内容相同,无需创建合并请求。':<Button className="topWrapper_btn" onClick={()=>this.ismerge()}>创建合并请求</Button>}
</div>
</div>
<div style={{display:this.state.iscreatemerge==='none'?'none':'block'}}>
<Form>
<div className="f-wrap-between mt20" style={{alignItems:"flex-start"}}>
<div className="list-right df">
<Link to={``}><img class="user_img" src={getImageUrl(`images/${current_user && current_user.image_url}`)} alt=""/></Link>
<div className="new_context">
<Form.Item>
{getFieldDecorator('title', {
rules: [{
required: true, message: '请填写请求标题'
}],
})(
<Input placeholder="标题"/>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('body', {
rules: [],
})(
<TextArea placeholder="添加一个可选的扩展描述。。。" style={{height:"300px"}}/>
)}
</Form.Item>
<UploadComponent load={this.UploadFunc}></UploadComponent>
<p className="clearfix mt15">
<a className="topWrapper_btn fr" type="submit" onClick={this.submit}>创建合并请求</a>
</p>
</div>
</div>
<div className="list-left" style={{paddingRight:"0px",paddingLeft:"15px",paddingTop:"10px"}}>
<div className="list-l-panel">
<Form.Item
label="标签"
>
{getFieldDecorator('issue_tag_ids', {
initialValue:0,
rules: [],
})(
<Select value={issue_tag_ids}>
<Option value={0}>未选择标签</Option>
{ this.renderSelect(data && data.issue_tags) }
</Select>
)}
</Form.Item>
<Form.Item
label="里程碑"
>
{getFieldDecorator('fixed_version_id', {
initialValue:0,
rules: [],
})(
<Select value={fixed_version_id}>
<Option value={0}>未选择里程碑</Option>
{ this.renderSelect(data && data.issue_versions) }
</Select>
)}
</Form.Item>
<Form.Item
label="指派成员"
>
{getFieldDecorator('assigned_to_id', {
initialValue:0,
rules: [{
}],
})(
<Select value={assigned_to_id}>
<Option value={0}>未指派成员</Option>
{ this.renderSelect(data && data.members) }
</Select>
)}
</Form.Item>
</div>
</div>
</div>
</Form>
</div>
<div style={{display:this.state.iscreatemerge==='none'?'none':'block'}}>
<Table
className="mt20 wrap-commit-table"
columns={columns}
dataSource={titledata}
showHeader={false}
size="small"
pagination={false}
title={() => title()}
/>
</div>
</div>
)
}
}
const WrappedNewMerge = Form.create({ name: 'NewMergeFrom' })(NewMerge);
export default WrappedNewMerge;

@ -0,0 +1,355 @@
import React , {Component} from 'react';
import {Link} from 'react-router-dom';
import axios from 'axios';
import Nav from '../Order/Nav';
import UploadComponent from '../Upload/Index';
import { getImageUrl } from 'educoder';
import{ Modal,Col,Form,Input,Tooltip,Select } from 'antd'
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import Attachments from '../Upload/attachment'
const TextArea = Input.TextArea;
const Option = Select.Option;
class UpdateMerge extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
isShow:false,
imgsrc:'',
journalsdata:undefined,
//图片区域是否显示 none 隐藏 block 显示
display:'none',
titledisplay:'none',
subject:'',
branch_name:"",
issue_tag_ids:"",
fixed_version_id:"",
tracker_id:0,
issue_type:0,
status_id:0,
assigned_to_id:"",
priority_id:0,
done_ratio:0,
textcount:"",
fileList:undefined,
get_attachments: undefined
}
}
componentDidMount=()=>{
this.InitData();
this.getDetail();
//this.getSelectList();
}
InitData=()=>{
// this.props.form.setFieldsValue({
// ...this.state
// });
}
getDetail=()=>{
const { projectsId , mergeId} = this.props.match.params;
const url = `/projects/${projectsId}/pull_requests/${mergeId}/edit.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
data:result.data,
subject:result.data.issue.subject,
issue_chosen:result.data.issue.issue_chosen,
branches:result.data.issue.branches,
tracker_id:result.data.issue.tracker_id,
issue_type:result.data.issue.issue_type,
status_id:result.data.issue.status_id,
priority_id:result.data.issue.priority_id,
done_ratio:result.data.issue.done_ratio,
textcount:result.data.issue.description,
branch_name: result.data.issue.branch_name,
get_attachments: result.data.issue.attachments,
fileList:undefined,
issue_tag_ids: result.data.issue.issue_tags && result.data.issue.issue_tags[0].id,
fixed_version_id: result.data.issue.fixed_version_id,
assigned_to_id: result.data.issue.assigned_to_id
})
// this.getjournalslist();
}
}).catch((error)=>{
console.log(error);
})
}
handleok=() => {
this.setState({
isShow:false
});
};
handleCancel=()=>{
this.setState({
isShow:false
});
}
imgshow=()=>{
this.setState({
isShow:true
});
};
changmodelname=(e)=>{
this.setState({
subject:e.target.value
})
}
changmodelcount=(e)=>{
this.setState({
textcount:e.target.value
})
}
renderSelect=(list)=>{
if(list && list.length >0){
return(
list.map((item,key)=>{
return(
<Option key={key+1} value={item.id}>{item.name}</Option>
)
})
)
}
}
// 获取上传后的文件id数组
UploadFunc=(fileList)=>{
this.setState({
fileList
})
}
handleSubmit=()=>{
const { fileList } = this.state;
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
const { projectsId} = this.props.match.params;
const { subject ,data} = this.state;
const url = `/projects/${projectsId}/issues/${data.issue.id}.json`;
if(values.issue_tag_ids===0){
values.issue_tag_ids = ""
}else{
values.issue_tag_ids = [values.issue_tag_ids]
}
if(values.assigned_to_id===0){
values.assigned_to_id = ""
}
axios.put(url,{
project_id:projectsId,
subject:subject,
id: data.issue.id,
description:this.state.textcount,
attachment_ids:fileList,
...values
}).then(result=>{
if(result){
this.props.history.push(`/projects/${projectsId}/merge`);
}
}).catch(error=>{
console.log(error);
})
}
})
}
render(){
const { projectsId,mergeId } = this.props.match.params;
const { getFieldDecorator } = this.props.form;
const { current_user } = this.props;
const { issue_tag_ids , fixed_version_id , branch_name , status_id , tracker_id , issue_type ,assigned_to_id , priority_id , done_ratio,
issue_chosen , branches, subject, textcount,get_attachments } = this.state;
return(
<div className="main">
<div className="topWrapper">
<Nav {...this.props} {...this.state}/>
</div>
<div>
<Form>
<div className="f-wrap-between mt20" style={{alignItems:"flex-start"}}>
<div className="list-right df" >
<Link to={``}><img class="user_img" src={getImageUrl(`images/${current_user && current_user.image_url}`)} alt=""/></Link>
<div className="new_context">
<Form.Item>
{getFieldDecorator('subject', {
rules: [{
required: true, message: '请填写工单标题'
}],
initialValue: subject
})(
<Input placeholder="标题" onChange={this.changmodelname}/>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('description', {
rules: [],
initialValue: textcount
})(
<TextArea placeholder="请输入工单的描述..." style={{height:"300px"}} onChange={this.changmodelcount}/>
)}
</Form.Item>
<UploadComponent load={this.UploadFunc} showNotification={this.props.showNotification}></UploadComponent>
{
get_attachments ?
<Attachments attachments={get_attachments} showNotification={this.props.showNotification} canDelete={true}/>
:
""
}
<p className="clearfix mt15 text-right">
<a className="topWrapper_btn fr" type="submit" style={{marginLeft:5}} onClick={this.handleSubmit}>保存</a>
<Link to={`/projects/${projectsId}/merge/${mergeId}/Messagecount`} className="a_btn cancel_btn fr">取消</Link>
</p>
</div>
</div>
<div className="list-left" style={{paddingRight:"0px",paddingLeft:"15px",paddingTop:"10px"}}>
<div className="list-l-panel">
<Form.Item
label="分支"
>
{getFieldDecorator('branch_name', {
initialValue: branch_name,
rules: [],
})(
<Select>
<Option value={''}>分支未指定</Option>
{
branches && branches.length >0 && branches.map((item,key)=>{
return(
<Option value={item}>{item}</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item
label="标签"
>
{getFieldDecorator('issue_tag_ids', {
initialValue: issue_tag_ids ? [issue_tag_ids] : '',
rules: [],
})(
<Select>
<Option value={''}>未选择标签</Option>
{ this.renderSelect(issue_chosen && issue_chosen.issue_tag) }
</Select>
)}
</Form.Item>
<Form.Item
label="里程碑"
>
{getFieldDecorator('fixed_version_id', {
initialValue: fixed_version_id ? fixed_version_id : "",
rules: [],
})(
<Select>
<Option value={''}>未选择里程碑</Option>
{ this.renderSelect(issue_chosen && issue_chosen.issue_version) }
</Select>
)}
</Form.Item>
<Form.Item
label="状态"
>
{getFieldDecorator('status_id', {
initialValue:status_id,
rules: [{
required: true, message: '请选择完成状态'
}],
})(
<Select >
{ this.renderSelect(issue_chosen && issue_chosen.issue_status) }
</Select>
)}
</Form.Item>
<Form.Item
label="分类"
>
{getFieldDecorator('tracker_id', {
initialValue:tracker_id,
rules: [{
required: true, message: '请选择分类'
}],
})(
<Select>
{ this.renderSelect(issue_chosen && issue_chosen.tracker) }
</Select>
)}
</Form.Item>
<Form.Item
label="指派成员"
>
{getFieldDecorator('assigned_to_id', {
initialValue: assigned_to_id ? assigned_to_id : "",
})(
<Select>
<Option value={''}>未指派成员</Option>
{ this.renderSelect(issue_chosen && issue_chosen.assign_user) }
</Select>
)}
</Form.Item>
<Form.Item
label="优先度"
>
{getFieldDecorator('priority_id', {
initialValue:priority_id,
rules: [{
required: true, message: '请选择优先度'
}],
})(
<Select>
{ this.renderSelect(issue_chosen && issue_chosen.priority) }
</Select>
)}
</Form.Item>
<Form.Item
label="完成度"
>
{getFieldDecorator('done_ratio', {
initialValue:done_ratio,
rules: [{
required: true, message: '请选择完成度'
}],
})(
<Select value={done_ratio}>
{ this.renderSelect(issue_chosen && issue_chosen.done_ratio) }
</Select>
)}
</Form.Item>
</div>
</div>
</div>
</Form>
</div>
<Modal
onCancel={this.handleCancel}
visible={this.state.isShow}
width="400px"
footer={
[]
}
bodyStyle={{textAlign:'center'}}
>
<img class="list_img" src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/>
</Modal>
</div>
)
}
}
const UpdateMergeForm = Form.create({ name: 'UpdateMergeForm' })(UpdateMerge);
export default UpdateMergeForm;

@ -0,0 +1,13 @@
.mergediv{
height: 65px;
width: 100%;
padding: 15px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
border: 1px solid #EEEEEE;
flex-wrap: wrap;
text-align: center;
border-radius:4px;
margin-left: 15px;
}

@ -77,7 +77,6 @@ class merge extends Component{
}
}).then((result)=>{
if(result){
this.setState({
data:result.data,
issues:result.data.issues,
@ -198,9 +197,20 @@ class merge extends Component{
render(){
const { issue_chosen , issues , limit , page , search_count , data , assigned_to_id , author_id , isSpin,openselect,closeselect } = this.state;
const { issue_chosen , issues , limit , page , search_count , data , isSpin,openselect,closeselect } = this.state;
const { projectsId } = this.props.match.params;
const menu = (
<Menu onClick={this.arrayList}>
<Menu.Item key={'created_at'} value="desc">到期日从近到远</Menu.Item>
<Menu.Item key={'created_at'} value="asc">到期日从远到近</Menu.Item>
<Menu.Item key={'issues_count'} value="desc">完成度从低到高</Menu.Item>
<Menu.Item key={'issues_count'} value="asc">完成度从高到低</Menu.Item>
<Menu.Item key={'issues_count'} value="asc">工单从多到少</Menu.Item>
<Menu.Item key={'issues_count'} value="asc">工单从少到多</Menu.Item>
</Menu>
)
const Paginations = (
<React.Fragment>
{
@ -215,7 +225,7 @@ class merge extends Component{
<div className="main">
<div className="topWrapper">
<Nav {...this.props} {...this.state}/>
<Link to={`/projects/${projectsId}/orders/new`} className="topWrapper_btn">创建合并请求</Link>
<Link to={`/projects/${projectsId}/merge/new`} className="topWrapper_btn">创建合并请求</Link>
</div>
<div className="topWrapper" style={{borderBottom:"none"}}>
<p className="topWrapper_type">
@ -224,7 +234,7 @@ class merge extends Component{
{/* <span onClick={this.openorder} className={author_id ? "active":""}>{data && data.open_count}</span>
<span onClick={this.closeorder} className={author_id ? "active":""}>{data && data.close_count}个已关闭</span> */}
</p>
<div className="target-detail-search">
<div>
<Search
placeholder="搜索"
enterButton
@ -245,22 +255,22 @@ class merge extends Component{
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.issue_type,'所有类型','issue_type')} trigger={['click']} placement="bottomCenter">
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.issue_version,'里程碑','issue_version')} trigger={['click']} placement="bottomCenter">
<span>里程碑筛选<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.tracker,'所有分类','tracker_id')} trigger={['click']} placement="bottomCenter">
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.assign_user,'指派人','assigned_to_id')} trigger={['click']} placement="bottomCenter">
<span>指派人筛选<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.assign_user,'发布人','author_id')} trigger={['click']} placement="bottomCenter">
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.issue_type,'类型','issue_type')} trigger={['click']} placement="bottomCenter">
<span>类型筛选<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.assign_user,'指派人','assigned_to_id')} trigger={['click']} placement="bottomCenter">
<Dropdown className="topWrapperSelect" overlay={menu} trigger={['click']} placement="bottomCenter">
<span>排序<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>

@ -0,0 +1,199 @@
import React , { Component } from "react";
import { Form , Input , Select,Divider,Button,Checkbox,Dropdown,Menu} from 'antd';
import {Link} from 'react-router-dom';
import UploadComponent from '../Upload/Index';
import '../Order/order.css';
import './version.css';
import axios from 'axios';
const Option = Select.Option;
const TextArea = Input.TextArea;
class NewVersion extends Component{
constructor(props){
super(props);
this.state={
branch_name:"",
issue_tag_ids:"",
fixed_version_id:"",
issue_chosen:undefined,
fileList:undefined,
ischeck:undefined,
branches:undefined,
pull:undefined,
tag_name:'',
}
}
componentDidMount=()=>{
this.InitData();
this.getSelectList();
}
InitData=()=>{
this.props.form.setFieldsValue({
...this.state
});
}
getSelectList=()=>{
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/pull_requests/new.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
branches:result.data.branches,
pull:result.data.branches[0]
})
}
}).catch((error)=>{
console.log(error);
})
}
renderSelect=(list)=>{
if(list && list.length >0){
return(
list.map((item,key)=>{
return(
<Option key={key+1} value={item.id+""}>{item.name}</Option>
)
})
)
}
}
// 创建
handleSubmit=(draft)=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
const { projectsId } = this.props.match.params;
const { pull,tag_name,ischeck } = this.state;
const url = `/projects/${projectsId}/version_releases.json`;
// if(values.issue_type==="普通"){
// values.issue_type="1"
// }
axios.post(url,{
...values,
tag_name:tag_name,
draft:draft,
prerelease:ischeck,
target_commitish:pull
}).then(result=>{
if(result){
this.props.history.push(`/projects/${projectsId}/version`);
}
}).catch(error=>{
console.log(error);
})
}
})
}
// 获取上传后的文件id数组
UploadFunc=(fileList)=>{
this.setState({
fileList
})
}
RedieonChange=(e)=>{
this.setState({
ischeck:e.target.checked
})
}
Preservation=()=>{
alert(this.state.ischeck)
}
renderMenu =(array,id)=>{
return(
<Menu>
{
array && array.length > 0 && array.map((item,key)=>{
return(
<Menu.Item key={item} onClick={()=>this.getOption(item)}>{item}</Menu.Item>
)
})
}
</Menu>
)
}
getOption=(name)=>{
this.setState({
pull:name
})
}
changmodelname=(e)=>{
this.setState({
tag_name:e.target.value
})
}
render(){
const { getFieldDecorator } = this.props.form;
const { current_user } = this.props;
const {branches,pull,tag_name} = this.state;
return(
<div className="main">
<Form>
<h1 style={{marginLeft:15,marginTop:20}}>发布新版</h1>
<h5 style={{marginLeft:15}}>版本发布组织项目的版本</h5>
<Divider/>
<div style={{display:'flex'}}>
<Input placeholder="标签名称" style={{width:180,marginLeft:15}} value={tag_name} onChange={this.changmodelname}/>
<div style={{marginLeft:20,marginRight:20}}>@ </div>
<Dropdown overlay={this.renderMenu(branches &&branches,'pull')} trigger={['click']} placement="bottomCenter">
<Button style={{width:180}}>{pull}</Button>
</Dropdown>
</div>
<div style={{display:'flex'}}>
<div className="versionmilepostleft">
<h1>标题</h1>
<div>
<Form.Item>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入标题'
}],
})(
<Input placeholder="标题"/>
)}
</Form.Item>
</div>
<h1>内容</h1>
<Form.Item>
{getFieldDecorator('body', {
rules: [{
required: true, message: '请输入描述内容'
}],
})(
<TextArea placeholder="添加一个可选的扩展描述。。。" style={{height:"300px"}}/>
)}
</Form.Item>
<UploadComponent load={this.UploadFunc} style={{width:80,marginLeft:15}}></UploadComponent>
</div>
</div>
<Divider/>
<div className="fr">
<Checkbox onChange={this.RedieonChange}>标记为预行版</Checkbox>
<p>标记此版本不适合生产使用</p>
</div>
<div className="clearfix mt15" style={{marginTop:5}} >
<a className='topWrapper_btn_close fr' onClick={()=>this.handleSubmit(true)} style={{marginLeft:15}} >保存草稿</a> <a className='topWrapper_btn fr' onClick={()=>this.handleSubmit(false)} style={{marginRight:15}}></a>
</div>
</Form>
</div>
)
}
}
const WrappedNewVersionForm = Form.create({ name: 'NewVersionForm' })(NewVersion);
export default WrappedNewVersionForm;

@ -0,0 +1,218 @@
import React , { Component } from "react";
import { Form , Input , Select,Divider,Button,Checkbox,Dropdown,Menu} from 'antd';
import {Link} from 'react-router-dom';
import UploadComponent from '../Upload/Index';
import '../Order/order.css';
import './version.css';
import axios from 'axios';
const Option = Select.Option;
const TextArea = Input.TextArea;
class NewVersion extends Component{
constructor(props){
super(props);
this.state={
branch_name:"",
issue_tag_ids:"",
fixed_version_id:"",
issue_chosen:undefined,
fileList:undefined,
ischeck:undefined,
pull:undefined,
tag_name:'',
data:undefined
}
}
componentDidMount=()=>{
this.InitData();
this.getSelectList();
}
InitData=()=>{
this.props.form.setFieldsValue({
...this.state
});
}
getSelectList=()=>{
const { projectsId,versionId} = this.props.match.params;
const url = `/projects/${projectsId}/version_releases/${versionId}/edit.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
data:result.data,
pull:result.data.target_commitish
})
}
}).catch((error)=>{
console.log(error);
})
}
renderSelect=(list)=>{
if(list && list.length >0){
return(
list.map((item,key)=>{
return(
<Option key={key+1} value={item.id+""}>{item.name}</Option>
)
})
)
}
}
//delete
deleteversion=()=>{
const { projectsId , versionId} = this.props.match.params;
const url = `/projects/${projectsId}/version_releases/${versionId}.json`;
axios.delete(url,{ data: {
project_id: projectsId,
id:versionId
}
}).then((result)=>{
if(result){
this.props.history.push(`/projects/${projectsId}/orders`);
}
}).catch((error)=>{
console.log(error);
})
}
// 创建
handleSubmit=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
const { projectsId} = this.props.match.params;
const { pull,tag_name,ischeck } = this.state;
const url = `/projects/${projectsId}/version_releases/.json`;
// if(values.issue_type==="普通"){
// values.issue_type="1"
// }
axios.post(url,{
...values,
tag_name:tag_name,
draft:false,
prerelease:ischeck,
target_commitish:pull
}).then(result=>{
if(result){
this.props.history.push(`/projects/${projectsId}/version`);
}
}).catch(error=>{
console.log(error);
})
}
})
}
// 获取上传后的文件id数组
UploadFunc=(fileList)=>{
this.setState({
fileList
})
}
RedieonChange=(e)=>{
this.setState({
ischeck:e.target.checked
})
}
Preservation=()=>{
alert(this.state.ischeck)
}
renderMenu =(array,id)=>{
return(
<Menu>
{
array && array.length > 0 && array.map((item,key)=>{
return(
<Menu.Item key={item} onClick={()=>this.getOption(item)}>{item}</Menu.Item>
)
})
}
</Menu>
)
}
getOption=(name)=>{
this.setState({
pull:name
})
}
changmodelname=(e)=>{
this.setState({
tag_name:e.target.value
})
}
render(){
const { getFieldDecorator } = this.props.form;
const { current_user,projectsId} = this.props;
const {data,pull,tag_name} = this.state;
return(
<div className="main">
<Form>
<h1 style={{marginLeft:15,marginTop:20}}>发布新版</h1>
<h5 style={{marginLeft:15}}>版本发布组织项目的版本</h5>
<Divider/>
<div style={{display:'flex'}}>
{data.tag_name}@{pull}
</div>
<div style={{display:'flex'}}>
<div className="versionmilepostleft">
<h1>标题</h1>
<div>
<Form.Item>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入标题'
}],
initialValue: data.name
})(
<Input placeholder="标题"/>
)}
</Form.Item>
</div>
<h1>内容</h1>
<Form.Item>
{getFieldDecorator('body', {
rules: [{
required: true, message: '请输入描述内容'
}],
initialValue: data.body
})(
<TextArea placeholder="添加一个可选的扩展描述。。。" style={{height:"300px"}}/>
)}
</Form.Item>
<UploadComponent load={this.UploadFunc} style={{width:80,marginLeft:15}}></UploadComponent>
</div>
</div>
<Divider/>
<div className="fr">
<Checkbox onChange={this.RedieonChange}>标记为预行版</Checkbox>
<p>标记此版本不适合生产使用</p>
</div>
<div className="clearfix mt15" style={{marginTop:5}} >
<a className='topWrapper_btn_delete fr' onClick={this.deleteversion} style={{marginLeft:15}}>删除发布</a>
<a className='topWrapper_btn fr' onClick={this.handleSubmit} style={{marginRight:15}}>编辑发布信息</a>
<Link to={`/projects/${projectsId}/version`} className='topWrapper_btn fr'>取消</Link>
</div>
</Form>
</div>
)
}
}
const WrappedNewVersionForm = Form.create({ name: 'NewVersionForm' })(NewVersion);
export default WrappedNewVersionForm;

@ -0,0 +1,24 @@
.versionmilepostleft{
padding: 15px;
margin-right: 50px;
width: 80%;
}
.topWrapper_btn_close {
background: #504b4b;
color: #FFFFFF!important;
padding:0px 12px;
text-align: center;
height: 32px;
line-height: 32px;
border-radius: 4px;
}
.topWrapper_btn_delete {
background: #da1010;
color: #FFFFFF!important;
padding:0px 12px;
text-align: center;
height: 32px;
line-height: 32px;
border-radius: 4px;
}

@ -169,7 +169,7 @@ class version extends Component{
<div className="main">
<div className="topWrapper">
<h1>版本发布</h1>
<Link to={`/projects/${projectsId}/orders/new`} className="topWrapper_btn">发布新版</Link>
<Link to={`/projects/${projectsId}/version/new`} className="topWrapper_btn">发布新版</Link>
</div>
<div>
1

Loading…
Cancel
Save