538 lines
19 KiB
JavaScript
538 lines
19 KiB
JavaScript
import React , { useEffect , useState , forwardRef , useRef } from 'react';
|
||
import { Spin , Form , InputNumber, message } from 'antd';
|
||
import { getImageUrl } from 'educoder';
|
||
import { Link } from 'react-router-dom';
|
||
import { Box , LongWidth } from '../../Component/layout';
|
||
import RenderHtml from "../../../components/render-html";
|
||
import DropMenu from '../Component/dropMenu';
|
||
import NewPanel from '../Component/newPanel';
|
||
import Attachments from "../../Upload/attachment";
|
||
import DelBox from '../Component/delBox';
|
||
import Date from '../Component/date';
|
||
import moment from 'moment';
|
||
import Copy from '../Component/copy';
|
||
import axios from 'axios';
|
||
import CommentList from '../Component/comments/list';
|
||
import Claims from '../../claims/claims';
|
||
import ChooseMenu from '../Component/chooseMenu';
|
||
|
||
function Details(props){
|
||
const owner = props.match.params.owner;
|
||
const projectsId = props.match.params.projectsId;
|
||
const index = props.match.params.index;
|
||
|
||
const [ details , setDetails ] = useState(undefined);
|
||
const [ statusList , setStatusList ] = useState([]);
|
||
const [ prioritiesList , setPrioritiesList ] = useState([]);
|
||
const [ chargeList , setChargeList ] = useState([]);
|
||
const [ charge , setCharge ] = useState(undefined);
|
||
const [ millstoneList , setMillstoneList ] = useState([]);
|
||
const [ millstone , setMillstone ] = useState(undefined);
|
||
const [ tagList , setTagList ] = useState(undefined);
|
||
const [ tag , setTag ] = useState(undefined);
|
||
const [ branchList , setBranchList ] = useState(undefined);
|
||
const [ branch , setBranch ] = useState(undefined);
|
||
const [ desc , setDesc ] = useState(undefined);
|
||
|
||
const [ orderId , setOrderId ] = useState(undefined);
|
||
|
||
const [ delVisible , setDelVisible] = useState(false);
|
||
const [ edit , setEdit] = useState(false);
|
||
const [ copy , setCopy] = useState(false);
|
||
|
||
const [ start_date, setStartDate ] = useState("");
|
||
const [ due_date, setDueDate ] = useState("");
|
||
const [ commentReload, setCommentReload] = useState(undefined);
|
||
const [ editFlag , setEditFlag ] = useState(false);
|
||
const [ amountEditFlag , setAmountEditFlag ] = useState(false);
|
||
|
||
const [ assigner_choose , setAssigner_choose ] = useState([]);
|
||
const [ prioritie_choose , setPrioritie_choose ] = useState([]);
|
||
const [ status_choose , setStatus_choose ] = useState([]);
|
||
const [ tag_choose , setTag_choose ] = useState([]);
|
||
const [ millstone_choose , setMillstone_choose ] = useState([]);
|
||
const [ branch_choose , setBranch_choose ] = useState([]);
|
||
const [ rewardAmount , setRewardAmount ] = useState(undefined);
|
||
const [ rewardFlag , setRewardFlag ] = useState(false);
|
||
|
||
const pathname = props.history.location.pathname;
|
||
const permission = props && props.projectDetail && props.projectDetail.permission;
|
||
let colors = ["#1abcb1","#28be6c","#e67e22","#db3d1d"];
|
||
|
||
const {projectDetail , open_blockchain ,current_user, showNpsModal } = props;
|
||
useEffect(()=>{
|
||
if(pathname === `/${owner}/${projectsId}/issues/${index}/copy`){
|
||
setEdit(true);
|
||
setCopy(true);
|
||
}else{
|
||
setEdit(false);
|
||
setCopy(false);
|
||
}
|
||
},[pathname])
|
||
|
||
useEffect(()=>{
|
||
if(projectDetail && details){
|
||
const { author, name} = projectDetail;
|
||
document.title = `${details.subject}-任务-${author.name}/${name}`;
|
||
}
|
||
},[details,projectDetail])
|
||
|
||
useEffect(()=>{
|
||
if(index){
|
||
Init();
|
||
}
|
||
},[index])
|
||
|
||
function Init(){
|
||
const url = `/v1/${owner}/${projectsId}/issues/${index}`;
|
||
axios.get(url).then(result=>{
|
||
if(result && result.data){
|
||
let data = result.data;
|
||
setDetails(data);
|
||
let per = data && !data.user_permission;
|
||
setEditFlag(per);
|
||
|
||
setDesc(data && data.description);
|
||
|
||
const aut = current_user && data.author && (data.author.login === current_user.login);
|
||
const con = data.pull_fixed === false && aut;
|
||
setAmountEditFlag(con);
|
||
|
||
setAssigner_choose(data.assigners);
|
||
if(data.priority && data.priority.id){
|
||
setPrioritie_choose([{...data.priority,color:colors[data.priority.id-1]}]);
|
||
}else{
|
||
setPrioritie_choose([]);
|
||
}
|
||
setStatus_choose(data.status && data.status.id ? [data.status]:[]);
|
||
setTag_choose(data.tags);
|
||
setMillstone_choose(data.milestone && data.milestone.id ? [data.milestone]:[]);
|
||
setBranch_choose(data.branch_name ? [{name:data.branch_name}] : []);
|
||
setRewardAmount(data.blockchain_token_num);
|
||
|
||
data.start_date && setStartDate(moment(data.start_date).format('YYYY-MM-DD'));
|
||
data.due_date && setDueDate(moment(data.due_date).format('YYYY-MM-DD'));
|
||
|
||
setOrderId(data.id);
|
||
}
|
||
}).catch(error=>{
|
||
console.log(error);
|
||
})
|
||
}
|
||
|
||
|
||
function statusTag(name){
|
||
switch (name) {
|
||
case "低":
|
||
return "status low";
|
||
case "正常":
|
||
return "status normals";
|
||
case "高":
|
||
return "status hight";
|
||
default:
|
||
return "status urgent";
|
||
}
|
||
}
|
||
// 获取状态列表
|
||
useEffect(()=>{
|
||
getStatus();
|
||
},[])
|
||
function getStatus(){
|
||
const url = `/v1/${owner}/${projectsId}/issue_statues`;
|
||
axios.get(url).then(result=>{
|
||
if(result && result.data){
|
||
setStatusList(result.data.statues);
|
||
}
|
||
})
|
||
}
|
||
// 获取优先级列表
|
||
useEffect(()=>{
|
||
getPriorities();
|
||
},[])
|
||
|
||
function getPriorities(){
|
||
const url = `/v1/${owner}/${projectsId}/issue_priorities`;
|
||
axios.get(url).then(result=>{
|
||
if(result && result.data){
|
||
let priorities = result.data.priorities;
|
||
let array = addColorForPriorities(priorities);
|
||
setPrioritiesList(array);
|
||
}
|
||
})
|
||
}
|
||
|
||
function addColorForPriorities(list){
|
||
let array =[];
|
||
if(list && list.length>0){
|
||
array = list.map((i,k)=>{
|
||
let arr = {...i,color:colors[k]}
|
||
return arr;
|
||
})
|
||
}
|
||
return array;
|
||
}
|
||
|
||
// 获取负责人列表
|
||
useEffect(()=>{
|
||
getCharge();
|
||
},[charge])
|
||
|
||
function getCharge(){
|
||
const url = `/v1/${owner}/${projectsId}/collaborators`;
|
||
axios.get(url,{params:{keyword:charge,only_name:true}}).then(result=>{
|
||
if(result && result.data){
|
||
setChargeList(result.data.collaborators);
|
||
}
|
||
})
|
||
}
|
||
// 获取里程碑列表
|
||
useEffect(()=>{
|
||
getMillstone();
|
||
},[millstone])
|
||
|
||
function getMillstone(){
|
||
const url = `/v1/${owner}/${projectsId}/milestones`;
|
||
axios.get(url,{params:{keyword:millstone,only_name:true}}).then(result=>{
|
||
if(result && result.data){
|
||
setMillstoneList(result.data.milestones);
|
||
}
|
||
})
|
||
}
|
||
// 获取标记列表
|
||
useEffect(()=>{
|
||
getSign();
|
||
},[tag])
|
||
function getSign(){
|
||
const url = `/v1/${owner}/${projectsId}/issue_tags`;
|
||
axios.get(url,{params:{keyword:tag,only_name:true}}).then(result=>{
|
||
if(result && result.data){
|
||
setTagList(result.data.issue_tags);
|
||
}
|
||
})
|
||
}
|
||
// 获取标记列表
|
||
useEffect(()=>{
|
||
getBranch(branch);
|
||
},[branch])
|
||
function getBranch(branch){
|
||
if(branch){
|
||
let b = [...branchList];
|
||
let l = b.filter(i=>i.name.indexOf(branch)>-1);
|
||
setBranchList(l);
|
||
return ;
|
||
}
|
||
const url = `/${owner}/${projectsId}/branches.json`;
|
||
axios.get(url,{params:{keyword:tag}}).then(result=>{
|
||
if(result && result.data){
|
||
setBranchList(result.data);
|
||
}
|
||
})
|
||
}
|
||
|
||
// 可单个编辑保存右侧的项(!copy:非复制状态下)
|
||
function saveForeach(c,s,p,t,m,b,sDate,eDate,rewardAmount){
|
||
if(sDate && due_date){
|
||
if(sDate > due_date){
|
||
setStartDate(start_date);
|
||
return props.showNotification("开始日期不能晚于结束日期!");
|
||
}
|
||
}
|
||
if(eDate && start_date){
|
||
if(eDate < start_date){
|
||
setDueDate(due_date);
|
||
return props.showNotification("结束日期不能早于开始日期!");
|
||
}
|
||
}
|
||
if(!copy){
|
||
const url = `/v1/${owner}/${projectsId}/issues/${index}`;
|
||
axios.patch(url,{
|
||
branch_name: b ? b.join(",") :undefined,
|
||
status_id: s ? s.join(",") : undefined,
|
||
priority_id: p ? p.join(",") :undefined,
|
||
milestone_id: m ? m.join(",") :undefined,
|
||
issue_tag_ids: t?t:undefined,
|
||
assigner_ids: c?c:undefined,
|
||
start_date:sDate,
|
||
due_date:eDate,
|
||
blockchain_token_num:rewardAmount
|
||
}).then(result=>{
|
||
if(result){
|
||
Init();
|
||
// 更新操作日志
|
||
setCommentReload(Math.random());
|
||
}
|
||
}).catch(error=>{})
|
||
}
|
||
}
|
||
|
||
function deleteFunc(){
|
||
const url = `/v1/${owner}/${projectsId}/issues/${index}`;
|
||
axios.delete(url).then(result=>{
|
||
if(result){
|
||
props.showNotification("任务删除成功!");
|
||
props.history.push(`/${owner}/${projectsId}/issues`);
|
||
}
|
||
}).catch(error=>{})
|
||
}
|
||
|
||
// 编辑保存
|
||
function createFunc(values,fileList,receivers_login,description){
|
||
let params ={
|
||
subject: values.subject,
|
||
attachment_ids: fileList,
|
||
receivers_login: receivers_login,
|
||
description: description
|
||
}
|
||
if(!copy){
|
||
// 调用编辑保存接口
|
||
const url = `/v1/${owner}/${projectsId}/issues/${index}`;
|
||
axios.patch(url,{
|
||
...params
|
||
}).then(result=>{
|
||
if(result){
|
||
window.scrollTo(0,0);
|
||
props.showNotification("任务更新成功!");
|
||
Init();
|
||
setEdit(false);
|
||
// 刷新操作记录
|
||
setCommentReload(Math.random());
|
||
showNpsModal("submitIssue", 1);
|
||
}
|
||
}).catch(error=>{})
|
||
}else{
|
||
// 调用新建保存接口
|
||
const url = `/v1/${owner}/${projectsId}/issues`;
|
||
let b = branch_choose && branch_choose.length>0 ? branch_choose.map(i=>{return i.name}) :undefined;
|
||
let t = tag_choose && tag_choose.length>0 ? tag_choose.map(i=>{return i.id}) :undefined;
|
||
let a = assigner_choose && assigner_choose.length>0 ? assigner_choose.map(i=>{return i.id}) :undefined;
|
||
let m = millstone_choose && millstone_choose.length>0 ? millstone_choose.map(i=>{return i.id}) :undefined;
|
||
let p = prioritie_choose && prioritie_choose.length>0 ? prioritie_choose.map(i=>{return i.id}) :undefined;
|
||
let s = status_choose && status_choose.length>0 ? status_choose.map(i=>{return i.id}) :undefined;
|
||
axios.post(url,{
|
||
...params,
|
||
branch_name: b && b.join(","),
|
||
status_id: s && s.join(","),
|
||
priority_id: p && p.join(","),
|
||
milestone_id: m && m.join(","),
|
||
issue_tag_ids: t,
|
||
assigner_ids: a,
|
||
start_date,
|
||
due_date
|
||
}).then(result=>{
|
||
if(result && result.data && result.data.project_issues_index){
|
||
window.scrollTo(0,0);
|
||
props.showNotification("任务复制成功!");
|
||
props.history.push(`/${owner}/${projectsId}/issues/${result.data.project_issues_index}`);
|
||
showNpsModal("createIssue", 1);
|
||
}
|
||
}).catch(error=>{})
|
||
}
|
||
}
|
||
|
||
// 取消编辑或复制
|
||
function onCancel(){
|
||
if(copy){
|
||
props.history.push(`/${owner}/${projectsId}/issues/${index}`);
|
||
}else{
|
||
setEdit(false);
|
||
window.scrollTo(0,0);
|
||
}
|
||
}
|
||
|
||
function refreshFunc(){
|
||
// 更新操作日志
|
||
setCommentReload(Math.random());
|
||
}
|
||
|
||
|
||
// 悬赏金额 失去焦点保存数据
|
||
function amountBlur(e){
|
||
if(!editFlag){
|
||
setRewardFlag(false);
|
||
const value = e.target.value;
|
||
if(value<0){
|
||
message.info("请输入大于0的正整数");
|
||
setRewardAmount(rewardAmount);
|
||
return;
|
||
}
|
||
setRewardAmount(e.target.value);
|
||
if((value && value >= 0) || !value){
|
||
saveForeach(undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,value);
|
||
}
|
||
}
|
||
}
|
||
function changeAmount(value){
|
||
if(amountEditFlag){
|
||
setRewardAmount(value);
|
||
}else{
|
||
setRewardAmount(rewardAmount);
|
||
}
|
||
}
|
||
return(
|
||
details ?
|
||
<Box>
|
||
<LongWidth>
|
||
<DelBox
|
||
visible={delVisible}
|
||
onCancel={()=>setDelVisible(false)}
|
||
onSuccess={deleteFunc}
|
||
content={<div style={{paddingTop:"3px"}}><p className="font-15 mb20">您确定要删除当前任务?</p></div>}
|
||
/>
|
||
{
|
||
edit ?
|
||
<div style={{paddingTop:"25px"}} >
|
||
<NewPanel
|
||
{...props}
|
||
onCancel={onCancel}
|
||
title={details.subject}
|
||
desc={edit ? desc : undefined}
|
||
files={copy ? undefined : details.attachments}
|
||
createFunc={createFunc}
|
||
owner = {owner} projectsId = {projectsId}
|
||
/>
|
||
</div>
|
||
:
|
||
<div>
|
||
<div className="editpanel">
|
||
<div className="detailbanner">
|
||
<div className="detailtitle">
|
||
<div className="mb12">
|
||
{details.priority && <span className={statusTag(details.priority.name)}>{ details.priority.name }</span> }
|
||
<p className="name">{details.subject}</p>
|
||
</div>
|
||
<div>
|
||
<div className="ilog mt5">
|
||
<Copy value={`/${owner}/${projectsId}/issues/${index}`}><span className="number">#{details.project_issues_index}</span></Copy>
|
||
</div>
|
||
{
|
||
details.author &&
|
||
<div>
|
||
{ details.author.login ?
|
||
<Link to={`/${details.author.login}`} className="author"><img src={details.author.image_url} alt="" />{details.author.name}</Link>
|
||
:
|
||
<span className="author color-grey-6"><img src={details.author.image_url} alt="" />{details.author.name}</span>
|
||
}
|
||
<span className="ml10" style={{color:"#898d9d"}}>添加于{details.created_at}</span>
|
||
</div>
|
||
}
|
||
</div>
|
||
</div>
|
||
{
|
||
details.user_permission &&
|
||
<ul className="detailoperate">
|
||
<li><a className="color-blue" onClick={()=>setEdit(true)}><i className="iconfont icon-a-bianji12 font-12 mr5"></i>编辑</a></li>
|
||
<li><Link to={`/${owner}/${projectsId}/issues/${index}/copy`} className="color-blue ml20"><i className="iconfont icon-a-fuzhi2 font-12 mr5"></i>复制</Link></li>
|
||
<li><a className="color-red ml20" onClick={()=>setDelVisible(true)}><i className="iconfont icon-fuzhi-shanchu font-12 mr5"></i>删除</a></li>
|
||
</ul>
|
||
}
|
||
</div>
|
||
<div class="descPanel">
|
||
{desc ?
|
||
<RenderHtml owner={owner} projectsId={projectsId} className="break_word_comments imageLayerParent" value={desc} url={props.history.location} />
|
||
:
|
||
<span className="color-grey-9 ml3 mr3">暂无描述</span>
|
||
}
|
||
{details.attachments && details.attachments.length > 0 ?
|
||
<Attachments
|
||
attachments={details.attachments}
|
||
showNotification={props.showNotification}
|
||
/>
|
||
: ""
|
||
}
|
||
</div>
|
||
</div>
|
||
<div id="commentList">
|
||
<CommentList {...props} issueInfo={details} reload = {commentReload} reloadComment = {()=>{setCommentReload(Math.random())}}/>
|
||
</div>
|
||
</div>
|
||
}
|
||
</LongWidth>
|
||
<div className="shortwidth mt25">
|
||
{orderId && <div className="claimpart"><Claims issue_id={orderId} {...props} refreshFunc={refreshFunc}/></div>}
|
||
<ChooseMenu
|
||
placeholder="负责人"
|
||
menus={chargeList}
|
||
searchFunc={(value)=>{setCharge(value)}}
|
||
headImg
|
||
selectValueList={assigner_choose}
|
||
editFlag={editFlag}
|
||
chooseFunc={(list)=>{setAssigner_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(l);}}
|
||
double={5}
|
||
removeFlag={!editFlag}
|
||
/>
|
||
<DropMenu
|
||
placeholder="状态"
|
||
menus={statusList}
|
||
selectValueList={status_choose}
|
||
mustFlag
|
||
editFlag={editFlag}
|
||
chooseFunc={(list)=>{setStatus_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,l);}}
|
||
/>
|
||
<DropMenu
|
||
placeholder="优先级"
|
||
menus={prioritiesList}
|
||
selectValueList={prioritie_choose}
|
||
colorFlag="1"
|
||
mustFlag
|
||
editFlag={editFlag}
|
||
chooseFunc={(list)=>{setPrioritie_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,undefined,l);}}
|
||
/>
|
||
<ChooseMenu
|
||
placeholder="标记"
|
||
menus={tagList}
|
||
searchFunc={(value)=>{setTag(value)}}
|
||
selectValueList={tag_choose}
|
||
chooseFunc={(list)=>{setTag_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,undefined,undefined,l);}}
|
||
double={3}
|
||
colorFlag="2"
|
||
removeFlag={!editFlag}
|
||
editFlag={editFlag}
|
||
onAdd={permission && permission !== "Reporter" ? ()=>{getSign();} :false}
|
||
owner={owner}
|
||
projectsId={projectsId}
|
||
/>
|
||
{/* <ChooseMenu
|
||
placeholder="里程碑"
|
||
menus={millstoneList}
|
||
searchFunc={(value)=>{setMillstone(value)}}
|
||
selectValueList={millstone_choose}
|
||
editFlag={editFlag}
|
||
auto
|
||
chooseFunc={(list)=>{setMillstone_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,undefined,undefined,undefined,l);}}
|
||
/> */}
|
||
<ChooseMenu
|
||
placeholder="关联分支"
|
||
menus={branchList}
|
||
auto
|
||
searchFunc={(value)=>{setBranch(value)}}
|
||
selectValueList={branch_choose}
|
||
editFlag={editFlag}
|
||
chooseFunc={(list)=>{setBranch_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,undefined,undefined,undefined,undefined,l);}}
|
||
/>
|
||
{
|
||
open_blockchain &&
|
||
<li style={{paddingBottom:"0px"}}>
|
||
<span>
|
||
悬赏金额
|
||
{/* {!editFlag && <a onClick={editReward}><i className="iconfont icon-a-bianji12 font-13" style={{color:"#898d9d"}}></i></a> } */}
|
||
</span>
|
||
<InputNumber
|
||
onBlur={amountBlur}
|
||
placeholder="请输入悬赏金额"
|
||
style={{width:"100%",color:rewardAmount?"#333":"#acb0bf"}}
|
||
value={rewardAmount}
|
||
onChange={changeAmount}
|
||
className="borderNo mt5"
|
||
disabled={!amountEditFlag}
|
||
/>
|
||
</li>
|
||
}
|
||
<Date name="开始日期" today={start_date} setDate={(date)=>{saveForeach(undefined,undefined,undefined,undefined,undefined,undefined,date)}} editFlag={editFlag}/>
|
||
<Date name="结束日期" today={due_date} setDate={(date)=>{saveForeach(undefined,undefined,undefined,undefined,undefined,undefined,undefined,date)}} editFlag={editFlag}/>
|
||
</div>
|
||
</Box>
|
||
:
|
||
<div style={{width:"100%",display:"flex",alignItems:"center",justifyContent:'center',height:"400px"}}><Spin /></div>
|
||
)
|
||
}
|
||
export default Form.create()(forwardRef(Details)); |