forgeplus-react/src/forge/Issues/Pages/list.jsx

474 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
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();
}
// 标签列表页点击跳转issue列表页并筛选
if (props.location.state && props.location.state.issue) {
chooseTagFunc(props.location.state.issue)
}
},[])
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 || aboutMe !=="all"){
setClearFlag(true);
}else{
setClearFlag(false);
}
},[updateIds,value,allValue,begin_date,end_date,aboutMe])
// 自定义一个初始不更新的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`;
const { assigner_id ,issue_tag_ids , milestone_id ,issue_priorities_id , status_id } = updateChooseIds;
let assigner = assigner_id ? assigner_id === "-1" ? [] : assigner_id.split(",") : undefined;
let issueTag = issue_tag_ids ? issue_tag_ids === "-1" ? [] : issue_tag_ids.split(",") : undefined;
let milestone = milestone_id ? milestone_id === "-1" ? "" : milestone_id : undefined;
axios.patch(url,{
assigner_ids: assigner ,
ids: allValue,
issue_tag_ids: issueTag,
milestone_id: milestone,
priority_id: issue_priorities_id,
status_id: 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] || '');
}
function chooseTagFunc(taginfo){
menuRef.current && menuRef.current.setChooseTag(taginfo);
}
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">欢迎使用任务</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}
chooseTagFunc={chooseTagFunc}
/>
)
})
}
</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;