forked from Gitlink/forgeplus-react
462 lines
16 KiB
JavaScript
462 lines
16 KiB
JavaScript
import React , { useRef , useState , useEffect } from 'react';
|
||
import { Dropdown , Menu , Icon , Input , Checkbox , Pagination, Button , Tooltip ,Spin , DatePicker } from 'antd';
|
||
import bj from '../Img/biaoji.png';
|
||
import issueEmp from '../Img/issue-big.png';
|
||
import { Link } from "react-router-dom";
|
||
import AllMenus from '../Component/allMenus';
|
||
import CheckProfile from '../../Component/ProfileModal/Profile';
|
||
import Datas from '../Component/datas';
|
||
import DelBox from '../Component/delBox';
|
||
import axios from 'axios';
|
||
import cookie from 'react-cookies';
|
||
import emp from '../Img/emp.png';
|
||
import moment from 'moment';
|
||
|
||
const { RangePicker } = DatePicker;
|
||
|
||
const { Search } = Input;
|
||
const defaultLimit = 15;
|
||
|
||
function List(props){
|
||
const [ visible , setVisible ] = useState(false);
|
||
const [ issueList , setIssueList ] = useState(undefined);
|
||
const [ closedCount , setClosedCount ] = useState(0);
|
||
const [ openedCount , setOpenedCount ] = useState(0);
|
||
|
||
const[ aboutMe , setAboutMe ] = useState("all");
|
||
const[ value , setValue ] = useState("");
|
||
const[ keyword , setKeyword ] = useState(undefined);
|
||
|
||
const [ category , setCategory] = useState("opened");
|
||
const [ begin_date , setBegin] = useState(undefined);
|
||
const [ end_date , setEnd] = useState(undefined);
|
||
|
||
const [ allValue , setAllValue ] = useState([]);
|
||
const [ allIds , setAllIds ] = useState([]);
|
||
const [ checkAll , setCheckAll ] = useState(false);
|
||
|
||
const [ names , setNames ] = useState(undefined);
|
||
const [ updateIds , setUpdateIds ] = useState(undefined);
|
||
const [ updateChooseIds , setUpdateChooseIds ] = useState(undefined);
|
||
|
||
const [ page , setPage ] = useState(1);
|
||
const [ limit , setLimit ] = useState(15);
|
||
const [ total , setTotal ] = useState(undefined);
|
||
const [ issueTotal , setIssueTotal ] = useState(0);
|
||
|
||
const [ clearFlag , setClearFlag ] = useState(false);
|
||
const [ has_created_issues , setHas_created_issues] = useState(false);
|
||
|
||
const menuRef = useRef(null);
|
||
const owner = props.match.params.owner;
|
||
const projectsId = props.match.params.projectsId;
|
||
const permission = props && props.projectDetail && props.projectDetail.permission;
|
||
const { projectDetail , current_user , open_blockchain} = props;
|
||
|
||
useEffect(()=>{
|
||
if(projectDetail){
|
||
const { author, name } = projectDetail;
|
||
document.title = `疑修-${author.name}/${name}`;
|
||
}
|
||
},[projectDetail])
|
||
|
||
useEffect(()=>{
|
||
const datas = cookie.load('issuestates');
|
||
let states = datas === "undefined" ? undefined : datas;
|
||
console.log(states);
|
||
if(states){
|
||
setAboutMe(states.participant_category);
|
||
setCategory(states.category);
|
||
setPage(states.page);
|
||
setLimit(states.limit || defaultLimit);
|
||
setUpdateIds({...states});
|
||
setNames(states.names);
|
||
setBegin(states.begin_date);
|
||
setEnd(states.end_date);
|
||
// if(states.participant_category ==="all" && states.category === "opened" && states.page === 1 && states.limit===defaultLimit)
|
||
// Init({...states},states.page,states.names);
|
||
}else{
|
||
Init();
|
||
}
|
||
},[])
|
||
|
||
useEffect(()=>{
|
||
let v = allValue && allValue > 0;
|
||
if((updateIds && !v && (updateIds.author_id || updateIds.issue_priorities_id || updateIds.issue_tag_ids || updateIds.milestone_id || updateIds.sort_by || updateIds.status_id ||updateIds.assigner_id)) || value || end_date || begin_date){
|
||
setClearFlag(true);
|
||
}else{
|
||
setClearFlag(false);
|
||
}
|
||
},[updateIds,value,allValue,begin_date,end_date])
|
||
// 自定义一个初始不更新的hook
|
||
const useUpdateEffect = (fn, inputs) => {
|
||
const didMountRef = useRef(false);
|
||
useEffect(() => {
|
||
if (didMountRef.current) fn();
|
||
else didMountRef.current = true;
|
||
}, inputs);
|
||
};
|
||
|
||
// 定义处理函数
|
||
function handleAllDisabled(){
|
||
Init(updateIds,page,names);
|
||
}
|
||
|
||
// 使用自定义hook
|
||
useUpdateEffect(handleAllDisabled, [aboutMe,keyword,category,limit,end_date,updateIds]);
|
||
|
||
|
||
function getDirection(id){
|
||
if(!id) return undefined;
|
||
if(id === "1" || id === "3" || id === "5"|| id === "7"){
|
||
return "desc"
|
||
}else{
|
||
return "asc"
|
||
}
|
||
}
|
||
function getBy(id){
|
||
if(!id) return undefined;
|
||
if(id === "1" || id === "2"){
|
||
return "issues.created_on"
|
||
}else if(id === "3" || id === "4"){
|
||
return "issues.updated_on"
|
||
}else if(id === "5" || id === "6"){
|
||
return "issue_priorities.position"
|
||
}else{
|
||
return "issues.blockchain_token_num"
|
||
}
|
||
}
|
||
|
||
// 获取issue列表数据
|
||
function Init(params,p,names){
|
||
setTotal(undefined);
|
||
const datas = cookie.load('issuestates');
|
||
let states = datas === "undefined" ? undefined : datas;
|
||
if(states){
|
||
cookie.remove('issuestates');
|
||
}
|
||
const url = `/v1/${owner}/${projectsId}/issues`;
|
||
axios.get(url,{
|
||
params:{
|
||
...params,
|
||
page:p || 1,
|
||
keyword,
|
||
participant_category:aboutMe,
|
||
category,
|
||
limit,
|
||
begin_date,end_date,
|
||
sort_direction:getDirection(params && params.sort_by),
|
||
sort_by:getBy(params && params.sort_by),names:undefined
|
||
}
|
||
}).then(result=>{
|
||
if(result){
|
||
setIssueList(result.data.issues);
|
||
setTotal(result.data.total_count);
|
||
setClosedCount(result.data.closed_count);
|
||
setOpenedCount(result.data.opened_count);
|
||
const ids = result.data.issues.length>0 ? result.data.issues.map(i=>{return i.id}) : [];
|
||
setAllIds(ids);
|
||
setIssueTotal(result.data.total_issues_count);
|
||
setHas_created_issues(result.data.has_created_issues);
|
||
|
||
const d = {...params,keyword,participant_category:aboutMe,category,limit,page:p || 1,
|
||
sort_direction:getDirection(params && params.sort_by),begin_date,end_date,
|
||
sort_by:getBy(params && params.sort_by),names:names};
|
||
|
||
let inFifteenMinutes = new Date(new Date().getTime() + 24 * 3600 * 1000);
|
||
cookie.save('issuestates', {...d},{ expires: inFifteenMinutes,path:`/` });
|
||
}
|
||
}).then(error=>{})
|
||
}
|
||
|
||
// 第一个下拉搜索
|
||
const menu = (
|
||
<Menu selectedKeys={[`${aboutMe}`]} onClick={chooseAboutMe}>
|
||
<Menu.Item key={"all"}>全部</Menu.Item>
|
||
<Menu.Item key={"aboutme"}><Tooltip title="指我创建的、我负责的和@我的疑修">与我相关</Tooltip></Menu.Item>
|
||
<Menu.Item key={"assignedme"}>我负责的</Menu.Item>
|
||
<Menu.Item key={"authoredme"}>我创建的</Menu.Item>
|
||
<Menu.Item key={"atme"}>@我的</Menu.Item>
|
||
</Menu>
|
||
)
|
||
function chooseAboutMe(e){
|
||
setPage(1);
|
||
// setCategory("opened");
|
||
setAboutMe(e.key);
|
||
}
|
||
|
||
//清除筛选条件
|
||
function clearCondition(){
|
||
setKeyword(undefined);
|
||
setAboutMe("all");
|
||
setCategory("opened");
|
||
setUpdateIds(undefined);
|
||
setAllValue([]);
|
||
setPage(1);
|
||
setValue(undefined);
|
||
setNames(undefined);
|
||
setEnd(undefined);
|
||
setBegin(undefined);
|
||
// if(!value){
|
||
// Init();
|
||
// }
|
||
// 清除下拉选项
|
||
menuRef.current && menuRef.current.clearChoose();
|
||
}
|
||
|
||
// 全选所有issue
|
||
function chooseAll(e){
|
||
setCheckAll(e.target.checked);
|
||
// 清除下拉选项
|
||
menuRef.current && menuRef.current.clearChoose();
|
||
if(e.target.checked){
|
||
setAllValue(allIds);
|
||
}else{
|
||
setAllValue([]);
|
||
}
|
||
}
|
||
|
||
// 选择列表里的issue
|
||
function checkIssues(value){
|
||
// 清除下拉选项
|
||
menuRef.current && menuRef.current.clearChoose();
|
||
setAllValue(value);
|
||
if(value.length === allIds.length){
|
||
setCheckAll(true);
|
||
}else{
|
||
setCheckAll(false);
|
||
}
|
||
}
|
||
|
||
// 取消
|
||
function cancelUpdate(){
|
||
setAllValue([]);
|
||
setCheckAll(false);
|
||
// 清除下拉选项
|
||
menuRef.current && menuRef.current.clearChoose();
|
||
}
|
||
// 确认修改 allValue updateIds
|
||
function sureUpdate(){
|
||
const url = `/v1/${owner}/${projectsId}/issues/batch_update`;
|
||
axios.patch(url,{
|
||
assigner_ids: updateChooseIds && updateChooseIds.assigner_id && updateChooseIds.assigner_id.split(","),
|
||
ids: allValue,
|
||
issue_tag_ids: updateChooseIds && updateChooseIds.issue_tag_ids && updateChooseIds.issue_tag_ids.split(","),
|
||
milestone_id: updateChooseIds && updateChooseIds.milestone_id,
|
||
priority_id: updateChooseIds && updateChooseIds.issue_priorities_id,
|
||
status_id: updateChooseIds && updateChooseIds.status_id
|
||
}).then(result=>{
|
||
if(result){
|
||
setUpdateIds(undefined);
|
||
setAllValue([]);
|
||
setTotal(undefined);
|
||
Init();
|
||
cancelUpdate();
|
||
}
|
||
}).catch(error=>{})
|
||
}
|
||
|
||
// 切换页码
|
||
function changepage(p){
|
||
setPage(p);
|
||
Init(updateIds,p,names);
|
||
if (document) { // 可以排除不需要置顶的页面
|
||
if (document.documentElement || document.body) {
|
||
document.documentElement.scrollTop = document.body.scrollTop = 0; // 切换路由时手动置顶
|
||
}
|
||
}
|
||
}
|
||
|
||
// 删除issue相关 func
|
||
function onSuccess(){
|
||
const url = `/v1/${owner}/${projectsId}/issues/batch_destroy`;
|
||
axios.delete(url,{
|
||
params:{ids:allValue}
|
||
}).then(result=>{
|
||
if(result){
|
||
setUpdateIds(undefined);
|
||
setAllValue([]);
|
||
setVisible(false);
|
||
setCheckAll(false);
|
||
props.showNotification("疑修删除成功!");
|
||
Init();
|
||
}
|
||
}).catch(error=>{})
|
||
}
|
||
|
||
function chooseFunc(ids,n){
|
||
setNames(n);
|
||
setPage(1);
|
||
if(allValue && allValue.length>0){
|
||
// 将ids保存下来以便修改
|
||
// setUpdateIds(ids);
|
||
setUpdateChooseIds(ids);
|
||
}else{
|
||
if(ids.status_id === "5"){
|
||
setCategory("closed");
|
||
}else{
|
||
setCategory("opened");
|
||
}
|
||
setUpdateIds(ids);
|
||
setTotal(undefined);
|
||
// Init(ids,1,n);
|
||
}
|
||
}
|
||
|
||
function chageLimit(c,p){
|
||
setPage(1);
|
||
setLimit(p);
|
||
}
|
||
function changeCategory(value){
|
||
if(value !== category){
|
||
let ids = {...updateIds};
|
||
let ns = {...names};
|
||
if(value === "closed"){
|
||
ns = {...ns,status_name:"关闭"}
|
||
ids = {...ids,status_id:'5'};
|
||
setNames(ns)
|
||
setUpdateIds(ids);
|
||
}else{
|
||
ns = {...ns,status_name:undefined}
|
||
ids = {...ids,status_id:undefined};
|
||
setNames(ns)
|
||
setUpdateIds(ids);
|
||
}
|
||
setCategory(value);
|
||
setPage(1);
|
||
setTotal(undefined);
|
||
}
|
||
}
|
||
|
||
function changeSearchValueFunc(e){
|
||
setValue(e.target.value);
|
||
if(e.target.value===""){
|
||
setKeyword(undefined);
|
||
}
|
||
}
|
||
|
||
// 选择搜索时间
|
||
function changeBeginTime(data, value){
|
||
setPage(1);
|
||
setBegin(value[0] || '');
|
||
setEnd(value[1] || '');
|
||
}
|
||
return(
|
||
<div>
|
||
<DelBox visible={visible} onCancel={()=>setVisible(false)} onSuccess={onSuccess}/>
|
||
<div className="pageheader">
|
||
<div>
|
||
{
|
||
(current_user && current_user.login) &&
|
||
<Dropdown overlay={menu} trigger={['click']} placement="bottomLeft" arrow={{pointAtCenter: true}}>
|
||
<span className="dorpdownButton mr20">
|
||
<span>{aboutMe === "all" ? "全部":aboutMe === "aboutme"?"与我相关":aboutMe === "assignedme"?"我负责的":aboutMe === "authoredme"?"我创建的":"@我的"}</span>
|
||
<Icon type="caret-down" className="ml5 color-grey-6" />
|
||
</span>
|
||
</Dropdown>
|
||
}
|
||
<Search
|
||
placeholder="输入关键字搜索疑修"
|
||
value={value}
|
||
onChange={changeSearchValueFunc}
|
||
onSearch={()=>setKeyword(value)}
|
||
style={{ width: 354 , height : 32 }}
|
||
allowClear
|
||
/>
|
||
{
|
||
clearFlag &&
|
||
<a className="color-blue ml25" onClick={clearCondition} style={{ display: "flex" , alignItems: "center"}}>
|
||
<i className="iconfont icon-roundclose font-16 mr5"></i>清除筛选条件</a>
|
||
}
|
||
</div>
|
||
<div>
|
||
<RangePicker value={[begin_date ? moment(begin_date, 'YYYY-MM-DD') : "",end_date ? moment(end_date, 'YYYY-MM-DD') : ""]} onChange={changeBeginTime} style={{width:240,marginRight:20}}/>
|
||
{
|
||
permission && permission !== "Reporter" &&
|
||
<Link to={`/${owner}/${projectsId}/issues/sign`} className="dorpdownButton"><img src={bj} alt="" className="mr5" />标记管理</Link>
|
||
}
|
||
<CheckProfile {...props} sureFunc={()=>{props.history.push(`/${owner}/${projectsId}/issues/new`)}} checklogin className="operateButton ml20">创建疑修</CheckProfile>
|
||
</div>
|
||
</div>
|
||
<div className="lists">
|
||
<div className="listheader">
|
||
<div style={{display:"flex"}}>
|
||
<Checkbox value="all" style={{marginRight: "16px",display: (permission && permission !== "Reporter") ?"block":"none"}} checked={checkAll} onChange={chooseAll}></Checkbox>
|
||
{
|
||
allValue && allValue.length>0 ?
|
||
<span>选择{allValue.length}个issue</span>
|
||
:
|
||
<ul className="statusul">
|
||
<li className={category === "all" ?"active":""} onClick={()=>{changeCategory("all")}}>全部<span>{issueTotal}</span></li>
|
||
<li className={category === "opened" ?"active":""} onClick={()=>{changeCategory("opened")}}>开启中<span>{openedCount}</span></li>
|
||
<li className={category === "closed" ?"active":""} onClick={()=>{changeCategory("closed")}}>已关闭<span>{closedCount}</span></li>
|
||
</ul>
|
||
}
|
||
</div>
|
||
<div className="menusul">
|
||
<AllMenus
|
||
ref={menuRef}
|
||
update={allValue && allValue.length>0}
|
||
owner={owner}
|
||
projectsId={projectsId}
|
||
chooseFunc={chooseFunc}
|
||
defaultNames={names}
|
||
defaultIds={allValue && allValue.length>0 ? undefined : updateIds}
|
||
open_blockchain={open_blockchain}
|
||
/>
|
||
{
|
||
allValue && allValue.length>0 ?
|
||
<div>
|
||
<Button type="primary" ghost onClick={sureUpdate}>确定</Button>
|
||
<Button type="danger" ghost className="ml10" onClick={()=>setVisible(true)}>删除</Button>
|
||
<Button ghost className="ml10 mr10" onClick={cancelUpdate}>取消</Button>
|
||
</div>
|
||
:""
|
||
}
|
||
</div>
|
||
</div>
|
||
{
|
||
total === 0 &&
|
||
(!has_created_issues ?
|
||
<div className="listempty">
|
||
<img src={issueEmp} alt="" width="68px" />
|
||
<p className="font-22 mt5 mb10">欢迎使用疑修(Issue)</p>
|
||
<p className="font-15">疑修用于记录与跟踪待办事项、项目bug、功能需求等。在使用之前,请您先<CheckProfile {...props} checklogin sureFunc={()=>{props.history.push(`/${owner}/${projectsId}/issues/new`)}} className="color-blue">创建一个疑修</CheckProfile></p>
|
||
</div>
|
||
:
|
||
<div className="dataempty"><img src={emp} alt="" /></div>
|
||
)
|
||
}
|
||
{
|
||
total > 0 &&
|
||
<React.Fragment>
|
||
<Checkbox.Group name="issues" onChange={checkIssues} value={allValue} style={{ width: "100%"}}>
|
||
<div className="listdatas">
|
||
{issueList.map((item,key)=>{
|
||
return(
|
||
<Datas
|
||
key={key}
|
||
checkbox={(permission && permission !== "Reporter") && <Checkbox value={item.id} key={item.id} style={{marginRight: "16px"}}></Checkbox> }
|
||
item={item}
|
||
owner={owner}
|
||
projectsId={projectsId}
|
||
/>
|
||
)
|
||
})
|
||
}
|
||
</div>
|
||
</Checkbox.Group>
|
||
{
|
||
total > defaultLimit &&
|
||
<div className="pt25 pb30" style={{textAlign:"right"}}>
|
||
<Pagination total={total} onShowSizeChange={chageLimit} current={page} pageSize={limit} onChange={changepage} showSizeChanger pageSizeOptions={[15,30,40,50]} showQuickJumper />
|
||
</div>
|
||
}
|
||
</React.Fragment>
|
||
}
|
||
{total === undefined && <div style={{height:344,display:"flex",alignItems:"center",justifyContent:"center"}}><Spin /></div> }
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
export default List; |