Merge remote-tracking branch 'upstream/gitlink_ssr_head' into gitlink_ssr_head

This commit is contained in:
黄心宇 2026-01-21 16:09:23 +08:00
commit 428fcd720c
36 changed files with 1297 additions and 974 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
src: url('iconfont.woff2?t=1757896728868') format('woff2'),
url('iconfont.woff?t=1757896728868') format('woff'),
url('iconfont.ttf?t=1757896728868') format('truetype');
src: url('iconfont.woff2?t=1768876676007') format('woff2'),
url('iconfont.woff?t=1768876676007') format('woff'),
url('iconfont.ttf?t=1768876676007') format('truetype');
}
.iconfont {
@ -13,6 +13,122 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-zhuangtai:before {
content: "\e9c5";
}
.icon-fuzhi-shanchu1:before {
content: "\e9c6";
}
.icon-mobanguanli:before {
content: "\e9c7";
}
.icon-svg_jiantou1:before {
content: "\e9c3";
}
.icon-zuojiantou1:before {
content: "\e9c4";
}
.icon-jiantou4:before {
content: "\e9c2";
}
.icon-hezuohuoban:before {
content: "\e9bf";
}
.icon-xiangmugongxian:before {
content: "\e9c1";
}
.icon-sijiaoxing:before {
content: "\e9c0";
}
.icon-a-zu15512:before {
content: "\e9be";
}
.icon-wendangbangong-01:before {
content: "\e9bd";
}
.icon-wendangsousuo:before {
content: "\e9b7";
}
.icon-jieyakelu:before {
content: "\e9b0";
}
.icon-tuxingtuxiang1:before {
content: "\e9b6";
}
.icon-xiazaigongju:before {
content: "\e9bc";
}
.icon-shipinchuli:before {
content: "\e9b2";
}
.icon-liulanqi:before {
content: "\e9b8";
}
.icon-shejiaoliaotian:before {
content: "\e9b9";
}
.icon-shurufa:before {
content: "\e9ba";
}
.icon-quanbuleibie:before {
content: "\e9bb";
}
.icon-tuxingtuxiang:before {
content: "\e9af";
}
.icon-xitonggongju:before {
content: "\e9b1";
}
.icon-wendangbangong:before {
content: "\e9b3";
}
.icon-zhuomiankongzhi:before {
content: "\e9b4";
}
.icon-Npm:before {
content: "\e9ad";
}
.icon-Maven:before {
content: "\e9ac";
}
.icon-Python:before {
content: "\e9ae";
}
.icon-a-xiazai3:before {
content: "\e9ab";
}
.icon-xiala4:before {
content: "\e9a9";
}
.icon-tufaxingzhongdasuanlixuqiuyingjixiangying:before {
content: "\e9a0";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,209 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "46593376",
"name": "状态",
"font_class": "zhuangtai",
"unicode": "e9c5",
"unicode_decimal": 59845
},
{
"icon_id": "46593375",
"name": "复制-删除",
"font_class": "fuzhi-shanchu1",
"unicode": "e9c6",
"unicode_decimal": 59846
},
{
"icon_id": "46593374",
"name": "模版管理",
"font_class": "mobanguanli",
"unicode": "e9c7",
"unicode_decimal": 59847
},
{
"icon_id": "46370299",
"name": "svg_箭头1",
"font_class": "svg_jiantou1",
"unicode": "e9c3",
"unicode_decimal": 59843
},
{
"icon_id": "46370300",
"name": "左箭头",
"font_class": "zuojiantou1",
"unicode": "e9c4",
"unicode_decimal": 59844
},
{
"icon_id": "46329189",
"name": "箭头",
"font_class": "jiantou4",
"unicode": "e9c2",
"unicode_decimal": 59842
},
{
"icon_id": "46248622",
"name": "合作伙伴",
"font_class": "hezuohuoban",
"unicode": "e9bf",
"unicode_decimal": 59839
},
{
"icon_id": "46248621",
"name": "项目贡献",
"font_class": "xiangmugongxian",
"unicode": "e9c1",
"unicode_decimal": 59841
},
{
"icon_id": "46245203",
"name": "四角星",
"font_class": "sijiaoxing",
"unicode": "e9c0",
"unicode_decimal": 59840
},
{
"icon_id": "46244977",
"name": "组 15512",
"font_class": "a-zu15512",
"unicode": "e9be",
"unicode_decimal": 59838
},
{
"icon_id": "46034062",
"name": "文档办公-01",
"font_class": "wendangbangong-01",
"unicode": "e9bd",
"unicode_decimal": 59837
},
{
"icon_id": "46033728",
"name": "文档搜索",
"font_class": "wendangsousuo",
"unicode": "e9b7",
"unicode_decimal": 59831
},
{
"icon_id": "46033639",
"name": "解压刻录",
"font_class": "jieyakelu",
"unicode": "e9b0",
"unicode_decimal": 59824
},
{
"icon_id": "46033573",
"name": "图形图像",
"font_class": "tuxingtuxiang1",
"unicode": "e9b6",
"unicode_decimal": 59830
},
{
"icon_id": "46033572",
"name": "下载工具",
"font_class": "xiazaigongju",
"unicode": "e9bc",
"unicode_decimal": 59836
},
{
"icon_id": "46033597",
"name": "视频处理",
"font_class": "shipinchuli",
"unicode": "e9b2",
"unicode_decimal": 59826
},
{
"icon_id": "46033165",
"name": "浏览器",
"font_class": "liulanqi",
"unicode": "e9b8",
"unicode_decimal": 59832
},
{
"icon_id": "46033154",
"name": "社交聊天",
"font_class": "shejiaoliaotian",
"unicode": "e9b9",
"unicode_decimal": 59833
},
{
"icon_id": "46033153",
"name": "输入法",
"font_class": "shurufa",
"unicode": "e9ba",
"unicode_decimal": 59834
},
{
"icon_id": "46032783",
"name": "全部类别",
"font_class": "quanbuleibie",
"unicode": "e9bb",
"unicode_decimal": 59835
},
{
"icon_id": "46032622",
"name": "图形图像",
"font_class": "tuxingtuxiang",
"unicode": "e9af",
"unicode_decimal": 59823
},
{
"icon_id": "46032621",
"name": "系统工具",
"font_class": "xitonggongju",
"unicode": "e9b1",
"unicode_decimal": 59825
},
{
"icon_id": "46032619",
"name": "文档办公",
"font_class": "wendangbangong",
"unicode": "e9b3",
"unicode_decimal": 59827
},
{
"icon_id": "46032616",
"name": "桌面控制",
"font_class": "zhuomiankongzhi",
"unicode": "e9b4",
"unicode_decimal": 59828
},
{
"icon_id": "46032217",
"name": "Npm",
"font_class": "Npm",
"unicode": "e9ad",
"unicode_decimal": 59821
},
{
"icon_id": "46032121",
"name": "Maven",
"font_class": "Maven",
"unicode": "e9ac",
"unicode_decimal": 59820
},
{
"icon_id": "46032118",
"name": "Python",
"font_class": "Python",
"unicode": "e9ae",
"unicode_decimal": 59822
},
{
"icon_id": "46031753",
"name": "下载 (3)",
"font_class": "a-xiazai3",
"unicode": "e9ab",
"unicode_decimal": 59819
},
{
"icon_id": "46031290",
"name": "下拉",
"font_class": "xiala4",
"unicode": "e9a9",
"unicode_decimal": 59817
},
{
"icon_id": "45509718",
"name": "突发性重大算力需求应急响应",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -32,7 +32,7 @@ export function initAxiosInterceptors(props) {
// 判断网络是否连接
initOnlineOfflineListener();
// var proxy = "https://testforgeplus.trustie.net";
var proxy = "https://testforgeplus.trustie.net";
// var proxy = "http://172.20.32.201:4000";
// var proxy = "https://www.gitlink.org.cn";
@ -45,18 +45,18 @@ export function initAxiosInterceptors(props) {
requestProxy(config);
let url = `/api${config.url}`;
// if (window.location.port === "3007") {
// config.url = `${proxy}${url}`;
// if (config.url.indexOf('?') === -1) {
// config.url = `${config.url}`;
// } else {
// config.url = `${config.url}`;
// }
// } else {
// config.url = url;
// }
if (window.location.port === "3007") {
config.url = `${proxy}${url}?debug=admin`;
if (config.url.indexOf('?') === -1) {
config.url = `${config.url}`;
} else {
config.url = `${config.url}`;
}
} else {
config.url = url;
}
config.withCredentials = false;
config.url = url;
// config.url = url;
return config;
},
err => {

View File

@ -1,5 +1,5 @@
.aboutPanels{
max-width: 1200px;
max-width: 1400px;
margin:0px auto;
.aboutContent{
border-radius: 2px;

View File

@ -18,7 +18,7 @@
padding-bottom: 20px!important;
}
.contentBox{
width: 1200px;
width: 1400px;
margin:0px auto;
}
.pageDIV{

View File

@ -1,6 +1,6 @@
.dataset{
margin:0px auto;
width: 1200px;
width: 1400px;
padding:25px 0px;
.mnistData{
background: #FAFCFF;

View File

@ -1,6 +1,6 @@
.cardList {
margin: 30px auto;
width: 1200px;
width: 1400px;
padding-bottom: 50px;
display: flex;
flex-direction: column;

View File

@ -1,7 +1,7 @@
.opsPanel
{
margin:20px auto;
width: 1200px;
width: 1400px;
min-height: 500px;
padding: 0;
// 开始激活页面

View File

@ -3,6 +3,7 @@ import { findDOMNode } from 'react-dom';
import { Dropdown , Menu , Input , Button, Form , Tooltip } from 'antd';
import { getImageUrl } from 'educoder';
import AddTagsBox from './addTagsBox';
import "../index.scss";
const { Search } = Input;
/**
@ -39,9 +40,13 @@ function ChooseMenu({
const [ valuesId , setValuesId ] = useState([]);
const [ count , setCount ] = useState(double);
const [ content , setContent ] = useState(false);
const [ filterMenus, setFilterMenus ] = useState([]);
const [ saveList , setSaveList ] = useState(undefined);
useEffect(()=>{
setFilterMenus(menus);
},[menus])
const refFa = useRef(null);
const refBox = useRef(null);
@ -81,7 +86,7 @@ function ChooseMenu({
}
if(!visible){
setSearchValue(undefined);
searchFunc(undefined);
// searchFunc && searchFunc(undefined);
}
},[selectValueList,visible])
@ -95,7 +100,13 @@ function ChooseMenu({
//
function changeSearchvalue(e){
setSearchValue(e.target.value);
searchFunc(e.target.value);
// searchFunc(e.target.value);
if(!e.target.value){
setFilterMenus(menus);
return
}
let filter = menus && menus.length>0 ? menus.filter(i=>i.name.indexOf(e.target.value)>-1):[];
setFilterMenus(filter);
}
function renderNames(nameArrs){
return <React.Fragment>
@ -119,7 +130,7 @@ function ChooseMenu({
<span className={"task-hide"}>{i.name}</span>
}
{ !colorFlag && removeFlag && <a className="removeicon" onClick={()=>removeValueFunc(i.id)}><i className="iconfont icon-shanchu8 font-14"></i></a>}
{ colorFlag && removeFlag && <a className="removeicon" onClick={()=>removeValueFunc(i.id)} style={{display:'block',right:"19px",position:"absolute"}}><i className="iconfont icon-guanbi font-12 color-white"></i></a>}
{ colorFlag && removeFlag && <a className="removeicon" onClick={()=>removeValueFunc(i.id)} style={{display:'block',right:"4px",position:"absolute"}}><i className="iconfont icon-guanbi font-12 color-white"></i></a>}
</p>
)
})
@ -196,7 +207,7 @@ function ChooseMenu({
onAdd();
}
return(
<li>
<li className='dropliComponent'>
<span>
{placeholder}
{
@ -238,10 +249,10 @@ function ChooseMenu({
</div>
}
{
menus && menus.length >0?
filterMenus && filterMenus.length >0?
<Menu className={auto && "piecemenu"} selectedKeys={valuesId}>
{
menus.map((i,k)=>{
filterMenus.map((i,k)=>{
return(
<Menu.Item key={i.id || i.name} className={colorFlag ?"colorli":"commonli"} style={{backgroundColor:colorFlag?`${i.color || "#000"}`:"#f4f6fe"}} onClick={()=>chooseMenu(i)}>
{

View File

@ -124,7 +124,9 @@ function IssueCommentList(props){
{/* 评论/操作日志 展示列表 */}
<Spin spinning={spin}>
<div className={`issueCommentsBox ${category === 'comment' && !spin && 'justComment'}`}>
{journals && (journals.length > 0 && journals.map(item=>{return item.is_journal_detail ? (!item.closeAndSpan || item.id === item.start || open === item.start) ? <div key={item.id} className='operationLog'>
{journals && (journals.length > 0 &&
journals.map(item=>{return item.is_journal_detail ? (!item.closeAndSpan || item.id === item.start || open === item.start) ?
<div key={item.id} className='operationLog'>
{/* 操作日志 */}
<div className='operationCommentBor'></div>
<div className='flexCenter font-14' style={{width: '100%'}}>

View File

@ -136,7 +136,7 @@ function Date({name , today , setDate , editFlag},ref){
visible={visible}
trigger={['click']}
>
<li>
<li className='dropliComponent'>
<span>
{name}
{!editFlag && <a ref={refBox} onClick={()=>setVisible(visible ? false : true)}><i className="iconfont icon-riqi font-14" style={{color:"#898d9d"}}></i></a> }

View File

@ -40,6 +40,7 @@ function DropMenu({
const refFa = useRef(null);
const refBox = useRef(null);
// id
useEffect(()=>{
if(selectValueList && selectValueList.length > 0 ){
@ -80,7 +81,7 @@ function DropMenu({
}
function chooseMenu(i){
let list = selectValueList;
let list = selectValueList||[];
let re = [];
re = list && list.length > 0 ? list:[];
let filter = [];
@ -131,7 +132,7 @@ function DropMenu({
nameArrs && nameArrs.length>0?
nameArrs.map((i,k)=>{
return(
<p style={{display:"flex",alignItems:"center"}} className={removeFlag?"removeFlag":''}>
<p style={{display:"flex",alignItems:"center",maxWidth:"100%"}} className={removeFlag?"removeFlag":''}>
{i.image_url && <img src={getImageUrl(i.image_url)} alt="" width="28px" height="28px" style={{borderRadius:"50%",marginTop:"5px"}} className="mr5"/>}
{
colorFlag ?
@ -153,7 +154,7 @@ function DropMenu({
</React.Fragment>
}
return(
<li>
<li className='dropliComponent'>
<span>
{placeholder}
{!editFlag &&

View File

@ -62,7 +62,7 @@ function Menus({className,name, ids , lists , size , imgControl , searchFunc , c
function menu(data){
return <div className={`overlaydrop ${size}`}>
{ size !== "small" &&
<div className="pb10"><Search placeholder={`搜索${name}`} onChange={(e)=>searchFunc(e.target.value)}/></div>
<div className="pb10"><Search placeholder={`回车搜索${name}`} onPressEnter={(e)=>searchFunc(e.target.value)}/></div>
}
{
data && data.length>0 ?
@ -86,7 +86,7 @@ function Menus({className,name, ids , lists , size , imgControl , searchFunc , c
<li className={className || ""}>
<Drop className={className} ref={dropRef} overlay={menu(lists)} placement={"bottomRight"} idname="root">
<span className="task-hide">{showValue || (update ? `更换${name}` : name) }</span>
<Icon type="caret-down" className="color-grey-6" />
<Icon type="caret-down" className="color-grey-8" />
</Drop>
</li>
)

View File

@ -13,7 +13,7 @@
}
.pagebox{
width: 1200px;
width: 1400px;
margin:0px auto;
}
// 删除issue弹框
@ -448,69 +448,69 @@
.shortwidth{
width: 330px;
padding-left: 50px;
&>li{
border-bottom: 1px solid rgba(172, 176, 191, 0.17);
padding-bottom: 8px;
margin-bottom: 22px!important;
&>span{
font-size: 15px;
position: relative;
color: #40424a;
display: flex;
width: 100%;
}
li.dropliComponent{
border-bottom: 1px solid rgba(172, 176, 191, 0.17);
padding-bottom: 8px;
margin-bottom: 22px!important;
&>span{
font-size: 15px;
position: relative;
color: #40424a;
display: flex;
width: 100%;
height: 20px;
line-height: 20px;
font-weight: 600;
a{
position: absolute;
right: 0px;
}
}
.operatevalue{
line-height: 30px;
color: #acb0bf;
margin-top: 10px;
display: flex;
flex-wrap: wrap;
.colorsborder{
padding: 0px 8px;
height: 20px;
line-height: 18px;
border-radius: 4px;
text-align: center;
border:1px solid ;
font-size: 13px;
}
.colorsquare{
padding: 0px 8px;
height: 20px;
line-height: 20px;
font-weight: 600;
a{
position: absolute;
right: 0px;
border-radius: 4px;
text-align: center;
color: #fff;
font-size: 13px;
}
&>p{
margin-top: 5px!important;
position: relative;
margin-right: 15px;
&.removeFlag>span{
max-width: 230px;
}
.removeicon{
display: none;
}
}
.operatevalue{
line-height: 30px;
color: #acb0bf;
margin-top: 10px;
display: flex;
flex-wrap: wrap;
.colorsborder{
padding: 0px 8px;
height: 20px;
line-height: 18px;
border-radius: 4px;
text-align: center;
border:1px solid ;
font-size: 13px;
}
.colorsquare{
padding: 0px 8px;
height: 20px;
line-height: 20px;
border-radius: 4px;
text-align: center;
color: #fff;
font-size: 13px;
}
&>p{
margin-top: 5px!important;
position: relative;
padding-right: 15px;
&.removeFlag>span{
max-width: 230px;
}
.removeicon{
display: none;
}
}
.removeFlag:hover{
border-radius:2px;
.removeicon{
display: block;
}
}
&>p:first-child{
margin-top: 0px;
.removeFlag:hover{
border-radius:2px;
.removeicon{
display: block;
}
}
&>p:first-child{
margin-top: 0px;
}
}
}
.addTags_form{

View File

@ -931,6 +931,11 @@ class Detail extends Component {
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/date"
render={
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/MergeSubmit"
render={
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)

View File

@ -119,7 +119,7 @@
}
// coderDepot
.Panels{
max-width: 1200px;
max-width: 1400px;
margin: 0 auto;
.panelmenu{
padding-top:20px;
@ -511,7 +511,7 @@
}
}
.coderSubPage{
width: 1200px;
width: 1400px;
margin:0px auto;
}
.griditemAnchor{

View File

@ -6,7 +6,7 @@
background-color: #050d34;
}
.ProjectListIndex{
width: 1200px;
width: 1400px;
margin:20px auto;
display: flex;
align-items: flex-start;
@ -246,7 +246,7 @@
li{
text-align: center;
padding:0px;
margin-right: 30px;
margin-right: 25px;
display: flex;
& > a{
position: relative;

View File

@ -332,7 +332,7 @@
}
.releaseIndex{
margin: 30px auto;
width: 1200px;
width: 1400px;
}
.emptyPanel{
width: 100%;

View File

@ -111,7 +111,7 @@
}
.mergeBox{
margin:0px auto;
width: 1200px;
width: 1400px;
}
.linetype{
width:30px;

View File

@ -31,8 +31,8 @@ class MergeItem extends Component {
if (issue_tags && issue_tags.length > 0) {
return issue_tags.map((item, key) => {
return (
<span className="issue-tag-show" style={{ color: item.color }}>
{item.name}
<span style={{ color: item.color }}>
{item.name}{key<issue_tags.length-1 && ","}
</span>
);
});
@ -166,17 +166,15 @@ class MergeItem extends Component {
onMouseMove={() => this.onMouseMove(item.id)}
onMouseOut={() => this.onMouseOut()}
>
{item.attached_issues && item.attached_issues.length>0 && open_blockchain &&
<li>
{
item.attached_issues.map((i,k)=>{
return(
<Link to={`/${owner}/${projectsId}/issues/${i.project_issues_index}`} className="issueIndex">#{i.project_issues_index}</Link>
)
})
}
</li>
}
<li>
{
item.attached_issues && item.attached_issues.length>0 ? item.attached_issues.map((i,k)=>{
return(
<Link to={`/${owner}/${projectsId}/issues/${i.project_issues_index}`} className="issueIndex">#{i.project_issues_index}</Link>
)
}) :"--"
}
</li>
<li>{item.priority}</li>
<li>{this.set_issue_tags(item.issue_tags)}</li>
<li>

View File

@ -6,6 +6,7 @@ import axios from 'axios';
import Commits from './Commits';
import Comments from '../comments/comments';
import Files from './Files';
import OperateDate from './components/operateDate';
import '../Order/order.scss';
import './merge.css';
@ -72,6 +73,8 @@ class MergeFooter extends Component {
} else if (pathname.indexOf('files') > -1) {
activeKey = '3';
this.getFile(owner, projectsId, mergeId);
}else if (pathname.indexOf('date') > -1) {
activeKey = '4';
}
if (isTabChange && activeKey === '1') {
this.refreshComment();
@ -235,6 +238,15 @@ class MergeFooter extends Component {
</div>
</TabPane>
)}
<TabPane
tab={
<Link to={`/${owner}/${projectsId}/pulls/${mergeId}/date`}>
<span className="font-16">操作日志</span>
</Link>
}
key="4">
<OperateDate {...this.props}/>
</TabPane>
</Tabs>
</Spin>
</div>

View File

@ -475,12 +475,12 @@ class MessageCount extends Component {
</span>
<Tooltip placement="bottom" title={data.issue && data.issue.created_at}><span className="color-grey-8 ml5">{data.pr_time}</span></Tooltip>
{
open_blockchain && data.attached_issues && data.attached_issues.length>0 ?
data.attached_issues && data.attached_issues.length>0 ?
<span className="color-grey-8 ml25">关联issue:
{
data.attached_issues.map((i,k)=>{
return(
<Link className="issueIndex ml5" to={`/${owner}/${projectsId}/issues/${i.project_issues_index}`}>#{i.project_issues_index}</Link>
<Link className="issueIndex ml5" style={{float:"unset"}} to={`/${owner}/${projectsId}/issues/${i.project_issues_index}`}>#{i.project_issues_index}</Link>
)
})
}
@ -528,7 +528,7 @@ class MessageCount extends Component {
{
pr_status === 2 && permission && <Button type="primary" ghost onClick={this.restartFunc}>重新开启</Button>
}
{operate && (
{(userLogin && projectDetail && (pr_status === 0 || pr_status === 1) && permission) && (
<Button
type="green"
ghost
@ -546,7 +546,6 @@ class MessageCount extends Component {
onClick={this.codeReview}
>
代码评审
<div className='newBtnImg'></div>
</Button>
)}
{cancelOperate && (

View File

@ -75,7 +75,6 @@ class UpdateMerge extends Component {
<div className="merge-header width100 inline-block">
<div className="width45 pull-left">
<div className="color-grey-3 mb10 fwb">源分支 : </div>
<Input.Group compact className="display-flex">
<Button className="merge-header-button flex1 maxW50 hide-1 task-hide" disabled>
{data.is_original ? `${data.fork_project_user_name}/${data.fork_project_identifier}` : `${data.project_author}/${data.project_name}`}

View File

@ -0,0 +1,69 @@
import React , { useState ,useEffect} from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import { getImageUrl , timeAgo } from 'educoder';
import "../../Issues/Component/comments/list.scss";
function OperateDate(props){
// issueorder_idpullissue
const { order_id , match } = props;
const { mergeId, owner , projectsId } = match.params;
const [journals , setJournals ] =useState([])
const journalsIcon ={
'issue': 'icon-chuangjianqianbao',
'branch_name': 'icon-fenzhi3',
'assigner': 'icon-chengyuan2',
'status_id': 'icon-xiugaibaobiaomoban',
'fixed_version_id': 'icon-lichengbeiicon2',
'due_date': 'icon-riqi',
'issue_tag': 'icon-biaoji2',
'description': 'icon-xiugaibaobiaomoban',
'subject': 'icon-xiugaibaobiaomoban',
'start_date': 'icon-riqi',
'priority_id': 'icon-youxian',
'attachment': 'icon-xiugaibaobiaomoban'
}
useEffect(()=>{
if(order_id && mergeId){
getDate();
}
},[order_id,mergeId])
function getDate(){
const url = `/v1/${owner}/${projectsId}/issues/${order_id}/journals`;
axios.get(url,{
params:{
category:"operate",
page:1,
limit:50
}
}).then(response=>{
if(response){
setJournals(response.data.journals);
}
}).catch(error=>{})
}
return(
<div className='issueCommentsBox'>
{ journals.map(item=>{
return <div key={item.id} className='operationLog'>
{/* 操作日志 */}
<div className='operationCommentBor'></div>
<div className='flexCenter font-14' style={{width: '100%'}}>
<div className='flexCenter opBox'>
<span className='iconBackBox mr10'><i className={`iconfont font-12 ${journalsIcon[item.operate_category] || "icon-bianji7"}`}></i></span>
<div className='task-hide operationWords' style={{maxWidth: item.closeAndSpan && item.id === item.start? '550px' : '700px'}}>
<Link to={`/${item.user.login}`}><img src={getImageUrl(item.user.image_url)} alt="" className='commentUserImg mr5'/></Link>
<Link to={`/${item.user.login}`}>{item.user.name}&nbsp;</Link>
{(item.user.name.length + item.operate_content.length) > 62 ? <Tooltip title={<div><span>{item.user.name} </span><span dangerouslySetInnerHTML={{__html:item.operate_content}}></span></div>}><span dangerouslySetInnerHTML={{__html:item.operate_content}}></span></Tooltip> : <span dangerouslySetInnerHTML={{__html:item.operate_content}}></span>}
</div>
<span className='ml15 timeAgo font-14' style={{marginTop:"-2px"}}>{timeAgo(item.created_at)}</span>
</div>
</div>
</div>}
)}
</div>
)
}
export default OperateDate;

View File

@ -1,4 +1,4 @@
import React, { Component } from "react";
import React, { useEffect, useState } from "react";
import { Input, Dropdown, Menu, Icon, Pagination, Spin } from "antd";
import "./merge.css";
import "../Order/order.scss";
@ -7,6 +7,7 @@ import NoneData from "./no_data";
import MergeItem from "./MergeItem";
import './Index.scss';
import { turnbar } from "educoder";
import Menus from '../Issues/Component/menus';
import axios from "axios";
import CheckProfile from '../Component/ProfileModal/Profile';
@ -25,99 +26,63 @@ const { Search } = Input;
* search_count:列表总条数
* issue_type:搜索条件
*/
class merge extends Component {
constructor(props) {
super(props);
this.state = {
issue_chosen: undefined,
data: undefined,
issues: undefined,
isSpin: false,
search: undefined,
author_id: undefined,
assigned_to_id: undefined,
// limit: 15,
// page: 1,
search_count: undefined,
issue_type: undefined,
status_type: "1",
//设置选择高亮
openselect: 1,
closeselect: undefined,
issue_tag_ids: "标记",
fixed_version_ids: "里程碑",
assigned_to_ids: "审查人员",
paix: "排序",
priority_ids: "优先级",
has_created_pull_requests:false,
select_params: {
status_type: "1", //开启中和关闭中,默认为开启中的
assigned_to_id: undefined, // 指派人
fixed_version_id: undefined,
priority_id: undefined,
order_name: undefined,
order_type: undefined,
search: undefined,
page: 1,
limit: 15,
},
disable_pr_vew:false //访问pr的权限
};
}
function merge(props){
const [ tag , setTag ] = useState("");
const [ tagList , setTagList ] = useState([]);
const [ millstoneList , setMillstoneList ] = useState(undefined);
const [ millstone , setMillstone ] = useState(undefined);
const [ prioritiesList , setPrioritiesList ] = useState(undefined);
const [ chargeList , setChargeList ] = useState(undefined);
const [ charge , setCharge ] = useState(undefined);
const [ data , setData ] = useState(undefined)
const [ issues , setIssues ] = useState([])
const [ isSpin , setIsSpin ] = useState(false)
const [ search , setSearch ] = useState(undefined)
const limit = 15;
const [ page , setPage ] = useState(1)
const [ total , setTotal ] = useState(0)
const [ status_type , setStatus_type ] = useState("1")//1:开启11已合并2已拒绝
const [ order , setOrder ] = useState({order_name:undefined,order_type:undefined})
const [ assigned , setAssigned ] = useState({})
const [ priority , setPriority ] = useState({})
const [ fixed_version , setFixedVersion ] = useState({})
const [ issue_tag , setIssueTag ] = useState({})
componentDidMount = () => {
this.getSelectList();
this.getIssueList();
};
componentDidUpdate(){
this.updateDocumentTitle();
}
const { projectsId , owner } = props.match.params;
const { project , projectDetail , defaultBranch } = props;
const open_blockchain = project && project.open_blockchain;
useEffect(()=>{
setPage(1);
getIssueList(search,1);
},[status_type,assigned,priority,fixed_version,issue_tag,order])
// 更新网页标题
updateDocumentTitle(){
const {projectDetail} = this.props;
useEffect(()=>{
if(projectDetail){
const { author, name} = projectDetail;
document.title = `合并请求-${author.name}/${name}`;
}
}
},[projectDetail])
getSelectList = () => {
const { projectsId,owner } = this.props.match.params;
const url = `/${owner}/${projectsId}/issues/index_chosen.json`;
axios
.get(url)
.then((result) => {
if (result) {
this.setState({
issue_chosen: result.data.issue_chosen,
});
}
})
.catch((error) => {
console.log(error);
});
};
// 获取列表数据
getIssueList = () => {
const { select_params } = this.state;
const { projectsId , owner } = this.props.match.params;
const getIssueList = (searchvalue,page) => {
const url = `/${owner}/${projectsId}/pulls.json`;
axios.get(url, {
params: select_params,
params: {
limit,
page,
search:searchvalue,status_type,
order_name:order.order_name,order_type:order.order_type,
priority_id:priority.id,assigned_to_id:assigned.id,fixed_version_id:fixed_version.id,issue_tag_id:issue_tag.id
},
}).then((result) => {
if (result) {
this.setState({
data: result.data,
issues: result.data.issues,
search_count: result.data.search_count,
isSpin: false,
has_created_pull_requests:result.data.has_created_pull_requests,
disable_pr_vew:result.data.disable_pr_vew
});
setTotal(result.data.search_count);
setData(result.data);
setIssues(result.data.issues)
setIsSpin(false)
}
})
.catch((error) => {
@ -125,335 +90,404 @@ class merge extends Component {
});
};
getMenu = (e, id, name) => {
this.setState({
isSpin: true,
});
let key_name = e.key.split("-");
if (key_name[0] === "created_on") {
if (e.item.props.value === "desc") {
this.setState({
paix: "最新创建",
});
} else {
this.setState({
paix: "最早创建",
});
}
this.state.select_params.order_name = e.key;
} else if (key_name[0] === "updated_on") {
if (e.item.props.value === "desc") {
this.setState({
paix: "最新更新",
});
} else {
this.setState({
paix: "最早更新",
});
}
}
this.state.select_params.order_name = key_name[0];
this.state.select_params.order_type = e.item.props.value;
this.state.select_params.page = 1;
this.getIssueList();
};
// getMenu = (e, id, name) => {
// this.setState({
// isSpin: true,
// });
// let key_name = e.key.split("-");
// if (key_name[0] === "created_on") {
// if (e.item.props.value === "desc") {
// this.setState({
// paix: "最新创建",
// });
// } else {
// this.setState({
// paix: "最早创建",
// });
// }
// this.state.select_params.order_name = e.key;
// } else if (key_name[0] === "updated_on") {
// if (e.item.props.value === "desc") {
// this.setState({
// paix: "最新更新",
// });
// } else {
// this.setState({
// paix: "最早更新",
// });
// }
// }
// this.state.select_params.order_name = key_name[0];
// this.state.select_params.order_type = e.item.props.value;
// this.state.select_params.page = 1;
// this.getIssueList();
// };
getOption = (e, id, name) => {
this.setState({
isSpin: true,
});
let option_id = e.key === "all" ? undefined : e.key;
this.setState({
["${id}s"]: name,
});
this.state.select_params[`${id}`] = option_id;
this.state.select_params.page = 1;
this.state[`${id}s`] = name;
this.getIssueList();
};
// getOption = (e, id, name) => {
// this.setState({
// isSpin: true,
// });
// let option_id = e.key === "all" ? undefined : e.key;
// this.setState({
// ["${id}s"]: name,
// });
// this.state.select_params[`${id}`] = option_id;
// this.state.select_params.page = 1;
// this.state[`${id}s`] = name;
// this.getIssueList();
// };
renderMenu = (array, name, id) => {
return (
<Menu className="orderCondition">
<Menu.Item key={"all"} onClick={(e) => this.getOption(e, id, name)}>
{name}
</Menu.Item>
{array && array.length > 0 && array.map((item, key) => {
return (
((!item.permission) || (item.permission && item.permission !== "Reporter")) &&
<Menu.Item key={item.id} onClick={(e) => this.getOption(e, id, item.name)}>
{item.name}
</Menu.Item>
);
})}
</Menu>
);
};
// renderMenu = (array, name, id) => {
// return (
// <Menu className="orderCondition">
// <Menu.Item key={"all"} onClick={(e) => this.getOption(e, id, name)}>
// {name}
// </Menu.Item>
// {array && array.length > 0 && array.map((item, key) => {
// return (
// ((!item.permission) || (item.permission && item.permission !== "Reporter")) &&
// <Menu.Item key={item.id} onClick={(e) => this.getOption(e, id, item.name)}>
// {item.name}
// </Menu.Item>
// );
// })}
// </Menu>
// );
// };
// 翻页
ChangePage = (page) => {
this.setState({
isSpin: true,
});
this.state.select_params.page = page;
this.getIssueList();
const ChangePage = (page) => {
setIsSpin(true);
setPage(page);
getIssueList(search,1);
};
// 搜索
searchFunc = (value) => {
this.setState({
search: value,
isSpin: true,
});
this.state.select_params.search = value;
this.state.select_params.page = 1;
this.getIssueList();
const searchFunc = (value) => {
setIsSpin(true);
setSearch(value);
setPage(1);
getIssueList(value,1);
};
openorder = (type) => {
this.setState({
isSpin: true,
});
this.setState({
status_type: type,
issue_tag_ids: "标记",
fixed_version_ids: "里程碑",
assigned_to_ids: "审查人员",
paix: "排序",
priority_ids: "优先级",
});
this.state.select_params.status_type = type;
this.state.select_params.page=1;
this.state.select_params.limit=15;
this.getIssueList();
const openorder = (type) => {
setIsSpin(true);
setStatus_type(type);
setPage(1);
clearFunc();
};
checkOperation() {
const { defaultBranch,projectDetail } = this.props;
const { projectsId,owner } = this.props.match.params;
const clearFunc=()=>{
setAssigned({});
setPriority({});
setFixedVersion({});
setIssueTag({});
setOrder({});
}
function checkOperation() {
let branch = turnbar(defaultBranch) || "master";
if (projectDetail && projectDetail.fork_info) {
this.props.history.push(`/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}/compare/${branch}...${owner + '/' + projectsId +':' + branch}`)
props.history.push(`/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}/compare/${branch}...${owner + '/' + projectsId +':' + branch}`)
} else {
this.props.history.push(`/${owner}/${projectsId}/compare/${branch}...${branch}`);
props.history.push(`/${owner}/${projectsId}/compare/${branch}...${branch}`);
}
}
render() {
const { projectsId , owner } = this.props.match.params;
const { project } = this.props;
const open_blockchain = project && project.open_blockchain;
const {
issue_chosen,
issues,
limit,
page,
search_count,
data,
isSpin,
status_type,
select_params,has_created_pull_requests,disable_pr_vew
} = this.state;
const menu = (
<Menu onClick={(e) => this.getMenu(e)}>
<Menu.Item key={"created_on-desc"} value="desc">
最新创建
</Menu.Item>
<Menu.Item key={"created_on-asc"} value="asc">
最早创建
</Menu.Item>
<Menu.Item key={"updated_on-desc"} value="desc">
最新更新
</Menu.Item>
<Menu.Item key={"updated_on-asc"} value="asc">
最早更新
</Menu.Item>
</Menu>
);
return (
<div className="mt30 mergeBox">
<div className="topWrapper">
<Search
placeholder="输入关键字搜索合并请求"
style={{ width: 354 , height : 32 }}
onSearch={this.searchFunc}
/>
{
data && data.user_admin_or_developer &&
<CheckProfile {...this.props} className="operateButton ml10" sureFunc={() => this.checkOperation()}>
+&nbsp;新建合并请求
</CheckProfile>
}
</div>
<div className="f-wrap-between screenWrap">
<div className="df">
<ul className="searchBanner">
<li
className={!status_type ? "active" : ""}
onClick={() => this.openorder(undefined)}
>
<label>搜索结果</label>
<span>{data && data.search_count}</span>
</li>
<li
className={status_type === "1" ? "active" : ""}
onClick={() => this.openorder("1")}
>
<i className="iconfont icon-hebingqingqiu1 font-14 mr3 i_open"></i>
<label>开启的</label>
<span>{data && data.open_count}</span>
</li>
<li
className={status_type === "11" ? "active" : ""}
onClick={() => this.openorder("11")}
>
<i className="iconfont icon-hebingqingqiu1 font-14 mr3 i_merged"></i>
<label>已合并</label>
<span>{data && data.merged_issues_size}</span>
</li>
<li
className={status_type === "2" ? "active" : ""}
onClick={() => this.openorder("2")}
>
<i className="iconfont icon-hebingqingqiu1 font-14 mr3 i_closed"></i>
<label>已拒绝</label>
<span>{data && data.close_count}</span>
</li>
</ul>
</div>
<ul className="topWrapper_select">
{ open_blockchain && <li>关联疑修</li> }
<li>
<Dropdown
className="topWrapperSelect"
overlay={this.renderMenu(
issue_chosen && issue_chosen.priority,
"优先级",
"priority_id"
)}
trigger={["click"]}
placement="bottomCenter"
>
<span>
{this.state.priority_ids}
<Icon type="caret-down" className="ml5" />
</span>
</Dropdown>
</li>
<li>
<Dropdown
className="topWrapperSelect"
overlay={this.renderMenu(
issue_chosen && issue_chosen.issue_tag,
"标记",
"issue_tag_id"
)}
trigger={["click"]}
placement="bottomCenter"
>
<span>
{this.state.issue_tag_ids}
<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"
>
<span>
{this.state.assigned_to_ids}
<Icon type="caret-down" className="ml5" />
</span>
</Dropdown>
</li>
// 获取标记列表
useEffect(()=>{
getSign();
},[tag])
<li>
<Dropdown
className="topWrapperSelect"
overlay={this.renderMenu(
issue_chosen && issue_chosen.issue_version,
"里程碑",
"fixed_version_id"
)}
trigger={["click"]}
placement="bottomCenter"
>
<span>
{this.state.fixed_version_ids}
<Icon type="caret-down" className="ml5" />
</span>
</Dropdown>
</li>
function getSign(){
const url = `/v1/${owner}/${projectsId}/issue_tags`;
axios.get(url,{params:{keyword:tag,only_name:true}}).then(result=>{
if(result && result.data){
let list = [{id:-1,name:"无标记"}];
list = [...list,...result.data.issue_tags];
setTagList(list);
}
})
}
// 获取里程碑列表
useEffect(()=>{
getMillstone();
},[millstone])
<li>
<Dropdown
className="topWrapperSelect"
overlay={menu}
trigger={["click"]}
placement="bottomCenter"
>
<span>
{this.state.paix}
<Icon type="caret-down" className="ml5" />
</span>
</Dropdown>
function getMillstone(){
const url = `/v1/${owner}/${projectsId}/milestones`;
axios.get(url,{params:{keyword:millstone,only_name:true}}).then(result=>{
if(result && result.data){
let list = [{id:-1,name:"无里程碑"}];
list = [...list,...result.data.milestones];
setMillstoneList(list);
}
})
}
// 获取优先级列表
useEffect(()=>{
getPriorities();
},[])
function getPriorities(){
const url = `/v1/${owner}/${projectsId}/issue_priorities`;
axios.get(url).then(result=>{
if(result && result.data){
setPrioritiesList(result.data.priorities);
}
})
}
// 获取负责人列表
useEffect(()=>{
getCharge();
},[charge])
function getCharge(){
let list = [{id:-1,name:"未指派负责人"}];
const url = `/v1/${owner}/${projectsId}/collaborators`;
axios.get(url,{params:{keyword:charge,only_name:true}}).then(result=>{
if(result && result.data){
list = [...list,...result.data.collaborators];
setChargeList(list);
}
})
}
const orderList=[
{order_name:"created_on",order_type:"desc",name:"最新创建",id:"1"},
{order_name:"created_on",order_type:"asc",name:"最早创建",id:"2"},
{order_name:"updated_on",order_type:"desc",name:"最新更新",id:"3"},
{order_name:"updated_on",order_type:"asc",name:"最早更新",id:"4"}
]
return (
<div className="mt30 mergeBox">
<div className="topWrapper">
<Search
value={search}
onChange={(e)=>{setSearch(e.target.value)}}
placeholder="输入关键字搜索合并请求"
style={{ width: 354 , height : 32 }}
onSearch={searchFunc}
allowClear
/>
{
(search || fixed_version.id || assigned.id || issue_tag.id || priority.id) &&
<a class="color-blue ml25" onClick={()=>{clearFunc();setSearch(undefined)}} style={{display:"flex",alignItems:"center",marginRight:"auto"}}>
<i class="iconfont icon-roundclose font-16 mr5"></i>
</a>
}
{
data && data.user_admin_or_developer &&
<CheckProfile {...props} className="operateButton ml10" sureFunc={checkOperation}>
+&nbsp;新建合并请求
</CheckProfile>
}
</div>
<div className="f-wrap-between screenWrap">
<div className="df">
<ul className="searchBanner">
<li
className={!status_type ? "active" : ""}
onClick={() => openorder(undefined)}
>
<label>搜索结果</label>
<span>{total}</span>
</li>
<li
className={status_type === "1" ? "active" : ""}
onClick={() => openorder("1")}
>
<i className="iconfont icon-hebingqingqiu1 font-14 mr3 i_open"></i>
<label>开启的</label>
<span>{data && data.open_count}</span>
</li>
<li
className={status_type === "11" ? "active" : ""}
onClick={() => openorder("11")}
>
<i className="iconfont icon-hebingqingqiu1 font-14 mr3 i_merged"></i>
<label>已合并</label>
<span>{data && data.merged_issues_size}</span>
</li>
<li
className={status_type === "2" ? "active" : ""}
onClick={() => openorder("2")}
>
<i className="iconfont icon-hebingqingqiu1 font-14 mr3 i_closed"></i>
<label>已拒绝</label>
<span>{data && data.close_count}</span>
</li>
</ul>
</div>
<div className="topWrapper_select">
<li>关联疑修</li>
<Menus
ids={priority.id}
name={"优先级" } size={"small"}
lists={prioritiesList}
names={priority.name}
chooseFunc={(id,name)=>{setPriority({id:id.join(","),name});}}
/>
<Menus
ids={issue_tag.id}
name={"标记"}
size={"large"}
double
names={issue_tag.name}
lists={tagList}
searchFunc={(value)=>setTag(value)}
chooseFunc={(id,name)=>{setIssueTag({id:id.join(","),name});}}
/>
<Menus
ids={assigned.id}
name={"审查人员"}
size={"large"}
imgControl
names={assigned.name}
lists={chargeList}
searchFunc={(value)=>setCharge(value)}
chooseFunc={(id,name)=>{setAssigned({id:id.join(","),name});}}
/>
<Menus
ids={fixed_version.id}
name={"里程碑"} size={"large"}
names={fixed_version.name}
lists={millstoneList}
searchFunc={(value)=>setMillstone(value)}
chooseFunc={(id,name)=>{setFixedVersion({id:id.join(","),name});}}
/>
<Menus
ids={order.id}
name={"排序"} size={"small"}
names={order.name}
lists={orderList}
chooseFunc={(id)=>{let filter=orderList.filter(i=>String(i.id)===id.join(","));setOrder(filter && filter.length>0 ? filter[0]:{});}}
/>
{/* <li>
<Dropdown
className="topWrapperSelect"
overlay={this.renderMenu(
issue_chosen && issue_chosen.priority,
"优先级",
"priority_id"
)}
trigger={["click"]}
placement="bottomCenter"
>
<span>
{this.state.priority_ids}
<Icon type="caret-down" className="ml5" />
</span>
</Dropdown>
</li>
<li>
<Dropdown
className="topWrapperSelect"
overlay={this.renderMenu(
issue_chosen && issue_chosen.issue_tag,
"标记",
"issue_tag_id"
)}
trigger={["click"]}
placement="bottomCenter"
>
<span>
{this.state.issue_tag_ids}
<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"
>
<span>
{this.state.assigned_to_ids}
<Icon type="caret-down" className="ml5" />
</span>
</Dropdown>
</li>
<li>
<Dropdown
className="topWrapperSelect"
overlay={this.renderMenu(
issue_chosen && issue_chosen.issue_version,
"里程碑",
"fixed_version_id"
)}
trigger={["click"]}
placement="bottomCenter"
>
<span>
{this.state.fixed_version_ids}
<Icon type="caret-down" className="ml5" />
</span>
</Dropdown>
</li>
<li>
<Dropdown
className="topWrapperSelect"
overlay={menu}
trigger={["click"]}
placement="bottomCenter"
>
<span>
{this.state.paix}
<Icon type="caret-down" className="ml5" />
</span>
</Dropdown>
</li> */}
</div>
</div>
{ data &&
<div style={{minHeight:"470px",paddingBottom:"50px"}}>
<Spin spinning={isSpin}>
{data && data.search_count && data.search_count > 0 ? (
{total > 0 ? (
<div className="mergeData">
<MergeItem
{...props}
issues={issues}
search_count={search_count}
page={select_params.page}
limit={select_params.limit}
project_name={data.project_name}
project_author_name={data.project_author_name}
{...this.props}
{...this.state}
user_admin_or_developer={data && data.user_admin_or_developer}
open_blockchain={open_blockchain}
disable_pr_vew={disable_pr_vew}
disable_pr_vew={data.disable_pr_vew}
></MergeItem>
</div>
):""}
{search_count > select_params.limit ? (
{total > limit ? (
<div className="mt30 edu-txt-center">
<Pagination
simple
current={select_params.page}
total={search_count}
pageSize={select_params.limit}
onChange={this.ChangePage}
current={page}
total={total}
pageSize={limit}
onChange={ChangePage}
></Pagination>
</div>
) : (
""
)}
{ data && data.issues && data.issues.length === 0 ?
{ issues && issues.length === 0 ?
<div style={{border:"1px solid rgba(42, 97, 255, 0.23)",borderTop:" none",borderRadius: "0px 0px 2px 2px;"}}>
<NoneData _html="暂时还没有相关数据!"
user_admin_or_developer={data.user_admin_or_developer}
has_created_pull_requests={has_created_pull_requests}
projectsId={projectsId} owner={owner}
defaultBranch={this.props && turnbar(this.props.defaultBranch) }/>
has_created_pull_requests={data.has_created_pull_requests}
projectsId={projectsId}
owner={owner}
defaultBranch={props && turnbar(props.defaultBranch) }/>
</div>
:""
}
</Spin>
</div>
</div>
);
}
}
</div>
);
}
export default merge;

View File

@ -1,456 +0,0 @@
import React, { Component } from "react";
import { Button, Form, Menu, Input, Select, Tag, Checkbox, Spin } from "antd";
import axios from "axios";
import "../Order/order.scss";
import "./merge.css";
import MDEditor from "../../modules/tpm/challengesnew/tpm-md-editor";
const Option = Select.Option;
class MergeForm extends Component {
constructor(props) {
super(props);
this.state = {
desc: undefined,
issue_tag_ids: undefined,
fixed_version_id: undefined,
assigned_to_id: undefined,
titledata: undefined,
isSpin: false,
mergedata: undefined,
priority_id: undefined,
title: undefined,
members: undefined,
issue_tags: undefined,
issue_versions: undefined,
issue_priories: undefined,
atWhoLoginList:undefined,
issue_lists:undefined,
issue_id:undefined,
disable_pr_vew:false//是否有权限访问pr
};
}
componentDidMount = () => {
// this.check_is_login();
this.get_default_selects();
this.set_defatul();
this.getIssueList();
};
componentDidUpdate=(prevPros)=>{
const { projectsId ,owner } = this.props.match.params;
const pId = prevPros.match.params.projectsId;
const oId = prevPros.match.params.owner;
if(pId !== projectsId || oId !== owner ){
// console.log("切换了项目分支···········");
this.get_default_selects();
}
if(prevPros && this.props && !this.props.checkIfLogin()){
this.props.history.push("/403")
return
}
}
getIssueList=()=>{
const { projectsId ,owner } = this.props.match.params;
const url = `/v1/${owner}/${projectsId}/issues`;
axios.get(url,{
params:{
only_name:true
}
}).then(result=>{
if(result && result.data){
this.setState({
issue_lists:result.data.issues
})
}
})
}
get_default_selects = () => {
const { projectsId ,owner } = this.props.match.params;
this.setState({ isSpin: true });
axios
.get(`/${owner}/${projectsId}/pulls/create_merge_infos.json`)
.then((result) => {
if (result) {
this.setState({
members: result.data.members,
issue_tags: result.data.issue_tags,
issue_versions: result.data.issue_versions,
issue_priories: result.data.issue_priories,
disable_pr_vew:result.data.disable_pr_vew
});
}
this.setState({ isSpin: false });
})
.catch((error) => {
this.setState({ isSpin: false });
console.log(error);
});
};
set_defatul = () => {
const { data, merge_type } = this.props;
if (data && merge_type === "edit") {
this.setState({
desc: data.body,
issue_tag_ids: data.issue_tag_ids ? data.issue_tag_ids[0] : undefined,
fixed_version_id: data.fixed_version_id ? String(data.fixed_version_id) : undefined,
assigned_to_id: data.assigned_to_id ? String(data.assigned_to_id) : undefined,
priority_id: data.priority_id ? String(data.priority_id) :undefined,
issue_id:data.attached_issues && data.attached_issues.length>0 ? String(data.attached_issues[0].id) :undefined,
title: data.title,
},()=>{
this.InitData();
});
}
};
InitData = () => {
console.log(this.state.issue_id);
this.props.form.setFieldsValue({
...this.state,
});
};
onPanelChange = (time, mode) => {
this.setState({
value: time,
});
};
onSelect = (time) => {
this.setState({
value: time,
selectedValue: time,
});
};
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 || item.subject}
</Option>
);
});
}
};
//创建合并请求
handleSubmit = () => {
this.setState({
isSpin: true,
});
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
const { projectsId, mergeId , owner } = this.props.match.params;
const { merge, pull, merge_type, data , commits_count , files_count } = this.props;
if (values.issue_tag_ids && values.issue_tag_ids.length > 0) {
values.issue_tag_ids = [parseInt(values.issue_tag_ids)];
} else {
values.issue_tag_ids = [];
}
const { desc , atWhoLoginList , disable_pr_vew } = this.state;
if (merge_type === "new") {
let url = `/${owner}/${projectsId}/pulls.json`;
axios.post(url, {
...values,
body: desc,
head: pull,
base: merge,
is_original: data && data.is_original,
fork_project_id: data && data.fork_project_id,
merge_user_login: data && data.merge_user_login,
merge_project_identifier:data && data.merge_project_identifier,
files_count,
commits_count,
receivers_login:atWhoLoginList,
attached_issue_ids:values.issue_id ? [values.issue_id] :undefined
})
.then((result) => {
if (result) {
this.setState({
isSpin: false,
});
const { pull_request_number } = result.data;
this.props.history.push({pathname: disable_pr_vew ? `/${owner}/${projectsId}/pulls`:`/${owner}/${projectsId}/pulls/${pull_request_number}`, query:{showNps: true}});
const { getDetail } = this.props;
getDetail && getDetail();
} else {
this.setState({
isSpin: false,
});
}
})
.catch((error) => {
this.setState({
isSpin: false,
});
});
} else {
let url = `/${owner}/${projectsId}/pulls/${mergeId}.json`;
axios
.put(url, {
...values,
body: desc,
head: pull,
base: merge,
receivers_login:atWhoLoginList,
attached_issue_ids:values.issue_id ? [values.issue_id] :undefined
})
.then((result) => {
if (result) {
this.setState({
isSpin: false,
});
// , query:{showNps: true}
this.props.history.push({pathname: `/${owner}/${projectsId}/pulls/${mergeId}`});
} else {
this.setState({
isSpin: false,
});
}
})
.catch((error) => {
this.setState({
isSpin: false,
});
console.log(error);
});
}
} else {
this.setState({
isSpin: false,
});
}
});
};
onContentChange = (value) => {
this.setState({
desc: value,
});
};
//合并请求中at谁列表存储login
changeAtWhoLoginList = (loginList) =>{
this.setState({
atWhoLoginList:loginList,
});
};
render() {
const { merge_type , project } = this.props;
const open_blockchain = project && project.open_blockchain;
const { getFieldDecorator } = this.props.form;
const { projectsId, mergeId ,owner } = this.props.match.params;
const {
issue_tag_ids,
fixed_version_id,
assigned_to_id,
priority_id,
desc,
isSpin,
title,
members,
issue_tags,
issue_versions,
issue_priories,
issue_lists,
issue_id
} = this.state;
return (
<div>
<Spin spinning={isSpin}>
<div className="mb20">
<span className="font-16 fwb mr10 ver-middle">
{merge_type === "new" ? "新建" : "编辑"}合并请求:
</span>
<Tag color="#28BD6C" className="ver-middle">
可合并的
</Tag>
</div>
<Form>
<div className="width100 inline-block">
<div className="width70 pull-left">
<Form.Item>
{getFieldDecorator("title", {
rules: [
{
required: true,
message: "请填写请求标题",
},
],
initialValue: title,
})(<Input placeholder="标题" maxLength={200} />)}
</Form.Item>
<div style={{position:"relative"}}>
<MDEditor
placeholder={"请输入合并请求的描述..."}
height={450}
mdID={"merge-new-description"}
initValue={desc}
onChange={this.onContentChange}
isCanAtme = {true}
changeAtWhoLoginList = {this.changeAtWhoLoginList}
owner = {owner}
projectsId = {projectsId}
></MDEditor>
</div>
<p className="clearfix mt20">
<Button
type="primary"
loading={isSpin}
onClick={this.handleSubmit}
>
<span className="plr10">
{merge_type === "new" ? "创建" : "提交"}
</span>
</Button>
<Button
type="default"
className="ml30"
onClick={()=>{
this.props.history.push(merge_type === "new" ? `/${owner}/${projectsId}/pulls` : `/${owner}/${projectsId}/pulls/${mergeId}`)
}}
>
<span className="plr10">取消</span>
</Button>
</p>
</div>
<div className="width30 pull-left">
<div className="pl30">
<Form.Item>
{getFieldDecorator("assigned_to_id", {
initialValue: assigned_to_id,
})(
<Select
placeholder="未选择审查人员"
showSearch
className="searchIcon"
suffixIcon={<i className="iconfont icon-sousuo1"></i>}
optionFilterProp="children"
filterOption={(input, option) =>
option.props.value && option.props.children && option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
<Option key={0} value={""}>未选择审查人员</Option>
{this.renderSelect(members)}
</Select>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator("fixed_version_id", {
initialValue: fixed_version_id,
})(
<Select
placeholder={
issue_versions && issue_versions.length > 0? "未选择里程碑": "请添加里程碑"
}
showSearch
className="searchIcon"
suffixIcon={<i className="iconfont icon-sousuo1"></i>}
optionFilterProp="children"
filterOption={(input, option) =>
option.props.value && option.props.children && option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
<Option key={0} value={""}>{issue_versions && issue_versions.length > 0? "未选择里程碑": "请添加里程碑"}</Option>
{this.renderSelect(issue_versions)}
</Select>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator("issue_tag_ids", {
initialValue: issue_tag_ids,
})(
<Select
placeholder={
issue_tags && issue_tags.length > 0 ? "未选择标记" : "请在仓库设置里添加标记"
}
showSearch
className="searchIcon"
suffixIcon={<i className="iconfont icon-sousuo1"></i>}
optionFilterProp="children"
filterOption={(input, option) =>
option.props.value && option.props.children && option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
<Option key={0} value={""}>{issue_tags && issue_tags.length > 0 ? "未选择标记" : "请在仓库设置里添加标记"}</Option>
{this.renderSelect(issue_tags)}
</Select>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator("priority_id", {
initialValue: priority_id,
})(
<Select placeholder="优先级" showSearch>
{this.renderSelect(issue_priories)}
</Select>
)}
</Form.Item>
<Form.Item style={{display:open_blockchain ? "block" :"none"}}>
{getFieldDecorator("issue_id", {
initialValue: issue_id,
})(
<Select
placeholder={"关联疑修"}
showSearch
className="searchIcon"
suffixIcon={<i className="iconfont icon-sousuo1"></i>}
optionFilterProp="children"
filterOption={(input, option) =>
option.props.value && option.props.children && option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
<Option key={0} value={""}>{issue_lists && issue_lists.length > 0 ? "未选择疑修" : "当前仓库还没有疑修"}</Option>
{this.renderSelect(issue_lists)}
</Select>
)}
</Form.Item>
{/* <Form.Item label="">
{getFieldDecorator("checkbox-group")(
<Checkbox.Group>
<div>
<Checkbox value="A">必须审查代码</Checkbox>
</div>
<div>
<Checkbox value="B">合并后删除提交分支</Checkbox>
</div>
<div>
<Checkbox value="C">合并后关闭提到的任务</Checkbox>
</div>
</Checkbox.Group>
)}
</Form.Item> */}
</div>
</div>
</div>
</Form>
</Spin>
</div>
);
}
}
const WrappedNewMerge = Form.create({ name: "NewMergeForm" })(MergeForm);
export default WrappedNewMerge;

View File

@ -0,0 +1,335 @@
import React, { useEffect, useState } from "react";
import { Button, Form, Menu, Input, Select, Tag, Spin } from "antd";
import axios from "axios";
import ChooseMenu from '../Issues/Component/chooseMenu';
import DropMenu from '../Issues/Component/dropMenu';
import "../Order/order.scss";
import "./merge.css";
import MDEditor from "../../modules/tpm/challengesnew/tpm-md-editor";
const Option = Select.Option;
function MergeForm(props){
const [ desc , setDesc ] = useState(undefined);
const [issue_tag_ids , setIssueTagIds] = useState(undefined);
const [fixed_version_id , setFixedVersionId] = useState(undefined);
const [assigned_to_id , setAssignedToId] = useState(undefined);
const [isSpin , setIsSpin ] = useState(false);
const [priority_id, setPriorityId] = useState(undefined);
const [title,setTitle] = useState(undefined);
const [members,setMembers] = useState(undefined);
const [ copymembers,setCopyMembers ] = useState(undefined);
const [ memberSearch , setMemberSearch ] = useState(undefined);
const [issue_tags,setIssueTags] = useState(undefined);
const [copyIssueTags,setCopyIssueTags] = useState(undefined);
const [issue_versions,setIssueVersions] = useState(undefined);
const [copyissueVersions,setCopyissueVersions] = useState(undefined);
const [ versionSearch , setVersionSearch ] = useState(undefined);
const [ tagSearch ,setTagSearch ] = useState(undefined);
const [ issueSearch ,setIssueSearch ] = useState(undefined);
const [issue_priories,setIssuePriories] = useState(undefined);
const [atWhoLoginList,setAtWhoLoginList] = useState(undefined);
const [issue_lists,setIssuelists] = useState(undefined);
const [copyIssueLists,setCopyIssueLists] = useState(undefined);
const [issue_id,setIssueId] = useState(undefined);
const [disable_pr_vew,setDisableprview] = useState(undefined);
const { projectsId, mergeId ,owner } = props.match.params;
const { checkIfLogin , form , merge_type , project ,data , merge , files_count , commits_count ,pull } = props;
const open_blockchain = project && project.open_blockchain;
const permission = props && props.projectDetail && props.projectDetail.permission;
const { getFieldDecorator } = props.form;
useEffect(()=>{
getIssueList();
},[])
useEffect(()=>{
if(!checkIfLogin()){
props.history.push("/403");
return
}
get_default_selects();
},[projectsId,owner])
const getIssueList=()=>{
const url = `/v1/${owner}/${projectsId}/issues`;
axios.get(url,{
params:{
only_name:true
}
}).then(result=>{
if(result && result.data){
let data = result.data.issues;
data = data && data.length>0 ? data.map(i=>{return {id:i.id,name:i.subject}}) :[]
setIssuelists(data);
setCopyIssueLists(data);
}
})
}
//
useEffect(()=>{
if(memberSearch){
let filter = copymembers.filter(i=>i.name.indexOf(memberSearch)>-1);
setMembers(filter);
}else{
setMembers(copymembers)
}
if(versionSearch){
let filter = copyissueVersions.filter(i=>i.name.indexOf(versionSearch)>-1);
setIssueVersions(filter);
}else{
setIssueVersions(copyissueVersions)
}
if(tagSearch){
let filter = copyIssueTags.filter(i=>i.name.indexOf(tagSearch)>-1);
setIssueTags(filter);
}else{
setIssueTags(copyIssueTags)
}
if(issueSearch){
let filter = copyIssueLists.filter(i=>i.name.indexOf(issueSearch)>-1);
setIssuelists(filter);
}else{
setIssuelists(copyIssueLists)
}
},[memberSearch,versionSearch,tagSearch,issueSearch])
function get_default_selects(){
setIsSpin(true);
axios.get(`/${owner}/${projectsId}/pulls/create_merge_infos.json`).then((result) => {
if (result && result.data) {
setIssueTags(result.data.issue_tags);
setCopyIssueTags(result.data.issue_tags);
setIssueVersions(result.data.issue_versions);
setCopyissueVersions(result.data.issue_versions);
setDisableprview(result.data.disable_pr_vew);
let priorities = result.data.issue_priories;
let array =[];
let colors = ["#1abcb1","#28be6c","#e67e22","#db3d1d"];
if(priorities && priorities.length>0){
array = priorities.map((i,k)=>{
let arr = {...i,color:colors[k]}
return arr;
})
}
setIssuePriories(array);
let mem = result.data.members;
mem = mem && mem.length > 0 && mem.map(i=>{return {...i,image_url:i.avatar_url}});
setMembers(mem);
setCopyMembers(mem);
if (data && merge_type === "edit") {
set_defatul(result.data.issue_tags,mem,array,result.data.issue_versions);
}
}
setIsSpin(false);
}).catch((error) => {
setIsSpin(false)
});
};
function set_defatul(tag,member,priority,version){
setDesc(data.body);
setIssueTagIds(tag.filter(i=>data.issue_tag_ids.includes(String(i.id))));
setFixedVersionId(version.filter(i=>String(i.id)===String(data.fixed_version_id)));
setAssignedToId(member.filter(i=>String(i.id)===String(data.assigned_to_id)));
setPriorityId(priority.filter(i=>String(i.id)===String(data.priority_id)));
let issues = data.attached_issues && data.attached_issues.length>0?data.attached_issues.map((i)=>{return {id:i.id,name:i.subject}}):[]
setIssueId(issues);
setTitle(data.title);
form.setFieldsValue({title:data.title})
};
//
const handleSubmit = () => {
setIsSpin(true);
form.validateFieldsAndScroll((err, values) => {
if (!err) {
let params={
priority_id:priority_id ? priority_id.map(i=>i.id).join(",") : "",
issue_tag_ids:issue_tag_ids ? issue_tag_ids.map(i=>i.id) : "",
fixed_version_id:fixed_version_id ? fixed_version_id.map(i=>i.id).join(",") : "",
assigned_to_id:assigned_to_id ? assigned_to_id.map(i=>i.id).join(",") : "",
}
if (merge_type === "new") {
let url = `/${owner}/${projectsId}/pulls.json`;
axios.post(url, {
...values,
...params,
body: desc,
head: pull,
base: merge,
is_original: data && data.is_original,
fork_project_id: data && data.fork_project_id,
merge_user_login: data && data.merge_user_login,
merge_project_identifier:data && data.merge_project_identifier,
files_count,
commits_count,
receivers_login:atWhoLoginList,
attached_issue_ids:issue_id && issue_id.length > 0 ? issue_id.map(i=>i.id) :[]
})
.then((result) => {
if (result) {
setIsSpin(false);
const { pull_request_number } = result.data;
props.history.push({pathname: disable_pr_vew ? `/${owner}/${projectsId}/pulls`:`/${owner}/${projectsId}/pulls/${pull_request_number}`, query:{showNps: true}});
const { getDetail } = props;
getDetail && getDetail();
} else {
setIsSpin(false);
}
}).catch((error) => {
setIsSpin(false);
});
} else {
let url = `/${owner}/${projectsId}/pulls/${mergeId}.json`;
axios
.put(url, {
...values,
...params,
body: desc,
head: pull,
base: merge,
receivers_login:atWhoLoginList,
attached_issue_ids:issue_id && issue_id.length > 0 ? issue_id.map(i=>i.id) :[]
})
.then((result) => {
if (result) {
setIsSpin(false);
props.history.push({pathname: `/${owner}/${projectsId}/pulls/${mergeId}`});
} else {
setIsSpin(false)
}
}).catch((error) => {
setIsSpin(false)
});
}
} else {
setIsSpin(false)
}
});
};
const onContentChange = (value) => {
setDesc(value)
};
//atlogin
const changeAtWhoLoginList = (loginList) =>{
setAtWhoLoginList(loginList)
};
return (
<div>
<Spin spinning={isSpin}>
<div className="mb20">
<span className="font-16 fwb mr10 ver-middle">
{merge_type === "new" ? "新建" : "编辑"}合并请求:
</span>
<Tag color="#28BD6C" className="ver-middle">
可合并的
</Tag>
</div>
<Form>
<div className="width100 inline-block">
<div className="width70 pull-left">
<Form.Item>
{getFieldDecorator("title", {
rules: [
{
required: true,
message: "请填写请求标题",
},
],
initialValue: title,
})(<Input placeholder="标题" maxLength={200} />)}
</Form.Item>
<div style={{position:"relative"}}>
<MDEditor
placeholder={"请输入合并请求的描述..."}
height={450}
mdID={"merge-new-description"}
initValue={desc}
onChange={onContentChange}
isCanAtme = {true}
changeAtWhoLoginList = {changeAtWhoLoginList}
owner = {owner}
projectsId = {projectsId}
></MDEditor>
</div>
<p className="clearfix mt20">
<Button
type="primary"
loading={isSpin}
onClick={handleSubmit}
>
<span className="plr10">
{merge_type === "new" ? "创建" : "提交"}
</span>
</Button>
<Button
type="default"
className="ml30"
onClick={()=>{
props.history.push(merge_type === "new" ? `/${owner}/${projectsId}/pulls` : `/${owner}/${projectsId}/pulls/${mergeId}`)
}}
>
<span className="plr10">取消</span>
</Button>
</p>
</div>
<div className="width30 pull-left">
<div className="pl30">
<ChooseMenu
placeholder="审查人员"
menus={members}
searchFunc={value=>{setMemberSearch(value)}}
headImg
selectValueList={assigned_to_id}
chooseFunc={(list)=>{setAssignedToId(list);}}
removeFlag
/>
<DropMenu
placeholder="里程碑"
menus={issue_versions}
auto
searchFunc={(value)=>{setVersionSearch(value)}}
selectValueList={fixed_version_id}
chooseFunc={(list)=>{setFixedVersionId(list);}}
/>
<ChooseMenu
placeholder="标记"
menus={issue_tags}
searchFunc={(value)=>{setTagSearch(value)}}
selectValueList={issue_tag_ids}
chooseFunc={(list)=>{setIssueTagIds(list);}}
colorFlag="2"
removeFlag
double={3}
onAdd={permission && permission !== "Reporter" ? ()=>{getSign();} :false}
owner={owner}
projectsId={projectsId}
/>
<DropMenu
placeholder="优先级"
menus={issue_priories}
selectValueList={priority_id}
colorFlag="1"
mustFlag
chooseFunc={(list)=>{setPriorityId(list);}}
/>
<DropMenu
placeholder="关联疑修"
menus={issue_lists}
searchFunc={(value)=>{setIssueSearch(value)}}
selectValueList={issue_id}
chooseFunc={(list)=>{setIssueId(list);}}
/>
</div>
</div>
</div>
</Form>
</Spin>
</div>
);
}
export default Form.create({ name: "NewMergeForm" })(MergeForm);

View File

@ -606,7 +606,7 @@ class Index extends Component {
{getFieldDecorator('repository_name', {
rules: [{
required: true, message: '请填写项目标识'
}],
},{pattern: /^(?!.*\.git$).*$/, message: `项目标识不能以.git结尾`}],
})(
<Input placeholder="项目标识请使用与项目相关的英文关键字" maxLength={100} />
)}

View File

@ -172,6 +172,27 @@
display: flex;
flex-wrap: wrap;
align-items: center;
li{
min-width: 88px;
display: flex!important;
justify-content: flex-end;
cursor: default;
margin-left: 12px;
color: #898d9d;
&.minwidth {
min-width: 70px;
}
}
.dropspan{
display: flex;
align-items: center;
cursor: pointer;
}
.dropspan > span {
max-width: 80px;
display: inline-block;
text-align: right;
}
}
.topWrapper .ant-btn.ant-input-search-button {
height: 30px;
@ -187,22 +208,13 @@
.topWrapper_select.wrapperStyle li{
width:90px;
}
.topWrapper_select li {
text-align: center;
cursor: pointer;
color: #666;
width: 86px;
text-align: center;
display: inline-block;
overflow: hidden;
white-space: nowrap;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
}
.topWrapper_select li:active {
background: #f4f4f4;
border-radius: 4px;
.topWrapper_select{
padding-right: 20px;
}
// .topWrapper_select li:active {
// background: #f4f4f4;
// border-radius: 4px;
// }
.no-cursor li {
cursor: default !important;
}

View File

@ -357,8 +357,9 @@ class Setting extends Component {
rules: [
{
required: true,
message: "请输入项目标识",
message: "请输入项目标识",
},
{pattern: /^(?!.*\.git$).*$/, message: `项目标识不能以.git结尾`}
],
})(
<Input placeholder="项目标识请使用与项目相关的英文关键字" maxLength="100" disabled={isWebSiteRepo}/>

View File

@ -56,7 +56,7 @@ ul,ol,dl{
text-align: right;
}
.main{
width: 1200px;
width: 1400px;
padding:20px;
margin:20px auto;
background: #fff;
@ -67,7 +67,7 @@ ul,ol,dl{
border-radius: 2px;
}
.normal{
width: 1200px;
width: 1400px;
margin:0px auto;
}
/* 背景色 */
@ -406,24 +406,6 @@ button.btngrey{
}
}
.newContainer {
.newTab,.newBtn {
position: relative;
}
.newBtnImg {
background-image: url('../Images/newIcon.svg');
background-size: 100% 100%;
width: 29px;
height: 13px;
position: absolute;
right: -14px;
top: -7px;
}
.newTab .newBtnImg {
right: -19px;
}
}
// 操作按钮-蓝色
.operateButton{