save-jiekou

This commit is contained in:
caishi 2023-02-17 14:46:13 +08:00
parent 834cbaea6c
commit 232f3e7dca
11 changed files with 771 additions and 233 deletions

View File

@ -1,13 +1,20 @@
import React , { useState } from 'react';
import { Form , Modal , Input, Button } from 'antd';
import ColorCard from './colorCard';
import axios from 'axios';
function AddTagsBox({visible,onCancel,onSuccess , form}){
function AddTagsBox({visible,onCancel, onSuccess , form ,owner , projectsId}){
const { getFieldDecorator , getFieldsValue } = form;
const [ colors , setColors ] = useState(undefined);
function saveFunc(){
const { desc , name } = getFieldsValue();
const url = `/v1/${owner}/${projectsId}/issue_tags`;
axios.post(url,{
name,description:desc,color:colors ? colors.hex:"#F17013"
}).then(result=>{
result && onSuccess();
}).catch(error=>{})
}
function getColor(colors){

View File

@ -0,0 +1,176 @@
import React,{ useState , useEffect , forwardRef ,useImperativeHandle , useRef } from 'react';
import Menus from './menus';
import axios from 'axios';
const array =[
{id:1,name:"最新创建"},
{id:2,name:"最早创建"},
{id:3,name:"最新更新"},
{id:4,name:"最早更新"}
]
function AllMenus({owner,projectsId,chooseFunc,update},ref){
//
const [ authorList , setAuthorList ] = useState(undefined);
const [ author , setAuthor ] = useState(undefined);
const [ tagList , setTagList ] = useState(undefined);
const [ tag , setTag ] = useState(undefined);
const [ millstoneList , setMillstoneList ] = useState(undefined);
const [ millstone , setMillstone ] = useState(undefined);
const [ chargeList , setChargeList ] = useState(undefined);
const [ charge , setCharge ] = useState(undefined);
const [ statusList , setStatusList ] = useState(undefined);
const [ prioritiesList , setPrioritiesList ] = useState(undefined);
const [ ids , setIds ] = useState({author_id:undefined,issue_priorities_id:undefined,issue_tag_ids:undefined,milestone_id:undefined,sort_by:undefined,status_id:undefined,assigner_id:undefined});
const [ names , setNames ] = useState({author_name:undefined,issue_priorities_name:undefined,issue_tag_name:undefined,milestone_name:undefined,sortby_name:undefined,status_name:undefined,assigner_name:undefined});
useImperativeHandle(ref, () => ({
clearChoose: () => {
// Ids\namesundefined
setIds({author_id:undefined,issue_tag_ids:undefined,issue_priorities_id:undefined,milestone_id:undefined,sort_by:undefined,status_id:undefined,assigner_id:undefined});
setNames({author_name:undefined,issue_tag_name:undefined,issue_priorities_name:undefined,milestone_name:undefined,sortby_name:undefined,status_name:undefined,assigner_name:undefined});
}
}))
//
useEffect(()=>{
getSendPerson();
},[author])
function getSendPerson(){
const url = `/v1/${owner}/${projectsId}/issue_authors`;
axios.get(url,{params:{keyword:author,only_name:true}}).then(result=>{
if(result && result.data){
setAuthorList(result.data.authors);
}
})
}
//
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(()=>{
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(()=>{
getCharge();
},[charge])
function getCharge(){
const url = `/v1/${owner}/${projectsId}/issue_assigners`;
axios.get(url,{params:{keyword:charge,only_name:true}}).then(result=>{
if(result && result.data){
setChargeList(result.data.assigners);
}
})
}
//
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(()=>{
getStatus();
},[])
function getStatus(){
const url = `/v1/${owner}/${projectsId}/issue_statues`;
axios.get(url).then(result=>{
if(result && result.data){
setStatusList(result.data.statues);
}
})
}
function choose(id,name){
let copy = {...ids,author_id:id};
let copyname = { ...names,author_name:name}
setIds(copy);setNames(copyname);
chooseFunc(copy);
}
return(
<ul className="dropboxul">
{ !update && <Menus
update={update}
id={ids && ids.author_id}
name={(names && names.author_name) || "发布人" } size={"large"} imgControl
lists={authorList} searchFunc={(value)=>setAuthor(value)}
chooseFunc={(id,name)=>choose(id,name,'author_name')}
/>
}
{update && <Menus
update={update}
id={ids && ids.issue_priorities_id}
name={(names && names.issue_priorities_name) || "优先级" } size={"small"}
lists={prioritiesList}
chooseFunc={(id,name)=>{let copy = {...ids,issue_priorities_id:id};let copyname = { ...names,issue_priorities_name:name};setNames(copyname);setIds(copy);chooseFunc(copy)}}
/>
}
<Menus
update={update}
id={ids && ids.issue_tag_ids}
name={(names && names.issue_tag_name) || "标记" } size={"large"}
lists={tagList} searchFunc={(value)=>setTag(value)}
chooseFunc={(id,name)=>{let copy = {...ids,issue_tag_ids:id};let copyname = { ...names,issue_tag_name:name};setNames(copyname);setIds(copy);chooseFunc(copy)}}
/>
<Menus
update={update}
id={ids && ids.milestone_id}
name={(names && names.milestone_name) || "里程碑" } size={"large"}
lists={millstoneList} searchFunc={(value)=>setMillstone(value)}
chooseFunc={(id,name)=>{let copy = {...ids,milestone_id:id};let copyname = { ...names,milestone_name:name};setNames(copyname);setIds(copy);chooseFunc(copy)}}
/>
<Menus
update={update}
id={ids && ids.assigner_id}
name={(names && names.assigner_name) || "负责人" } size={"large"} imgControl
lists={chargeList} searchFunc={(value)=>setCharge(value)}
chooseFunc={(id,name)=>{let copy = {...ids,assigner_id:id};let copyname = { ...names,assigner_name:name};setNames(copyname);setIds(copy);chooseFunc(copy)}}
/>
<Menus
update={update}
id={ids && ids.status_id}
name={(names && names.status_name) || "状态" } size={"small"}
lists={statusList}
chooseFunc={(id,name)=>{let copy = {...ids,status_id:id};let copyname = { ...names,status_name:name};setNames(copyname);setIds(copy);chooseFunc(copy)}}
/>
{ !update && <Menus
id={ids && ids.sort_by}
name={(names && names.sortby_name) ||"排序"} size={"small"}
lists={array}
chooseFunc={(id,name)=>{let copy = {...ids,sort_by:id};let copyname = { ...names,sortby_name:name};setNames(copyname);setIds(copy);chooseFunc(copy)}}
/>
}
</ul>
)
}
export default forwardRef(AllMenus);

View File

@ -6,39 +6,67 @@ import { Link } from "react-router-dom";
// issue
function Datas({checkbox ,item , projectsId,owner}){
function statusTag(name){
switch (name) {
case "低":
return "status low";
case "正常":
return "status normal";
case "高":
return "status hight";
default:
return "status urgent";
}
}
return(
<div className="listdatas">
<div>
<div className="issuedetail">
{checkbox}
<div className="ilog">
<span className="status normal">{item.priority_name}</span>
<span className={statusTag(item.priority_name)}>{item.priority_name}</span>
{item.project_issues_index && <span className="number"><Tooltip title="点击复制链接" placement="bottom">#{item.project_issues_index}</Tooltip></span>}
</div>
<div style={{marginTop:"-2px"}}>
<div className="idetails mt2">
<img src={issue} alt="" width="16px" className="mr5" />
<Link to={`/${owner}/${projectsId}/issues/${item.project_issues_index}`}>{item.subject}</Link>
<span style={{color: "#ee955a"}} className="ml5"><i className="iconfont icon-biaoji mr3 font-12"></i>invalid</span>
{
item.tags && item.tags.length>0?
item.tags.map((i,k)=>{
return(
<span style={{color: i.color}} className="ml8"><i className="iconfont icon-biaoji font-12"></i>{i.name}</span>
)
})
:""
}
</div>
<div className="infos">
<img src={`${getImageUrl(item.author && item.author.image_url)}`} alt="" />
<span className="mr20">{item.author && item.author.name}</span>
<Link to={`/${item.author && item.author.login}`}><img src={`${getImageUrl(item.author && item.author.image_url)}`} alt="" /></Link>
<span className="mr20"><Link to={`/${item.author && item.author.login}`}>{item.author && item.author.name}</Link></span>
<span className="mr25">{item.created_at} 发布</span>
<span className="mr50">{item.updated_at}更新</span>
{item.milestone_name && <span><i className="iconfont icon-lichengbeiicon1 font-12 mr2"></i>{item.milestone_name}</span> }
{item.milestone_name && <span><i className="iconfont icon-lichengbeiicon1 font-12 mr3"></i>{item.milestone_name}</span> }
</div>
</div>
</div>
<div className="issuecondition">
<div className="principal">
<img style={{right:`${5*(20-7)}px`,zIndex:1}} src={"https://testforgeplus.trustie.net/images/avatars/User/36480?t=1672730523"} alt="" />
<img style={{right:`${4*(20-7)}px`,zIndex:2}} src={"https://testforgeplus.trustie.net/images/avatars/User/36480?t=1672730523"} alt="" />
<img style={{right:`${3*(20-7)}px`,zIndex:3}} src={"https://testforgeplus.trustie.net/images/avatars/User/36480?t=1672730523"} alt="" />
<img style={{right:`${2*(20-7)}px`,zIndex:4}} src={"https://testforgeplus.trustie.net/images/avatars/User/36480?t=1672730523"} alt="" />
<img style={{right:`${20-7}px`,zIndex:5}} src={"https://testforgeplus.trustie.net/images/avatars/User/36480?t=1672730523"} alt="" />
<span>...</span>
</div>
{
item.assigners && item.assigners.length > 0 ?
<div className="principal">
{
item.assigners.map((i,k)=>{
return(
k<5 && <Link to={`/${i.login}`} style={{right:`${(item.assigners.length-k-1)*(20-7)}px`,zIndex:k+1}}><img src={getImageUrl(i.image_url)} alt="" /></Link>
)
})
}
{/* <span>...</span> */}
</div>
:""
}
<div>{item.status_name}</div>
<div className="commentnum"><i className="iconfont icon-a-xiaoxi1 mr5 font-15"></i>{item.comment_journals_count}</div>
</div>

View File

@ -0,0 +1,140 @@
import React,{useRef,useEffect, useState , forwardRef } from 'react';
import { Dropdown , Calendar , Select, Radio, Col, Row } from 'antd';
import { findDOMNode } from 'react-dom';
import moment from 'moment';
const { Group , Button } = Radio;
function Date({name , today , setDate},ref){
const [ visible , setVisible ] = useState(false);
const [ time , setTime ] = useState();
useEffect(()=>{
if(today){
setTime(today);
}
},[today])
const refFa = useRef(null);
const refBox = useRef(null);
useEffect(() => {
document.addEventListener('click', clickMe , false);
}, [])
const clickMe = ({ target }) => {
//
const faComponent = findDOMNode(refFa.current);
const boxComponent = findDOMNode(refBox.current);
if (faComponent && boxComponent) {
const isChild = faComponent.contains(target);
const isBox = boxComponent.contains(target);
if(!isChild && !isBox){
setVisible(false);
}
}
}
function onSelect(t){
setTime(moment(t).format('YYYY-MM-DD'));
setDate(moment(t).format('YYYY-MM-DD'));
setVisible(false);
}
const overlay=(
<div ref={refFa} style={{ width: 280, border: '1px solid #d9d9d9', borderRadius: 4 ,backgroundColor:"#fff",marginTop:"-10px"}}>
<Calendar
fullscreen={false}
headerRender={({ value, type, onChange, onTypeChange }) => {
const start = 0;
const end = 12;
const monthOptions = [];
const current = value.clone();
const localeData = value.localeData();
const months = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.monthsShort(current));
}
for (let index = start; index < end; index++) {
monthOptions.push(
<Select.Option className="month-item" key={`${index}`}>
{months[index]}
</Select.Option>,
);
}
const month = value.month();
const year = value.year();
const options = [];
for (let i = year - 10; i < year + 10; i += 1) {
options.push(
<Select.Option key={i} value={i} className="year-item">
{i}
</Select.Option>,
);
}
return (
<div style={{ padding: 10 }}>
<Row type="flex" justify="space-between">
<Col>
<Group size="small" onChange={e => onTypeChange(e.target.value)} value={type}>
<Button value="month">日期</Button>
<Button value="year">月份</Button>
</Group>
</Col>
<Col>
<Select
size="small"
dropdownMatchSelectWidth={false}
className="my-year-select"
style={{ width: 80 }}
onChange={newYear => {
const now = value.clone().year(newYear);
onChange(now);
}}
value={String(year)}
>
{options}
</Select>
</Col>
<Col>
<Select
size="small"
dropdownMatchSelectWidth={false}
value={String(month)}
onChange={selectedMonth => {
const newValue = value.clone();
newValue.month(parseInt(selectedMonth, 10));
onChange(newValue);
}}
>
{monthOptions}
</Select>
</Col>
</Row>
</div>
);
}}
onSelect={onSelect}
/>
</div>
)
return(
<Dropdown
placement={"bottomLeft"}
overlay={overlay}
visible={visible}
trigger={['click']}
>
<li>
<span>
{name}
<a ref={refBox} onClick={()=>setVisible(visible ? false : true)}><i className="iconfont icon-riqi font-14" style={{color:"#898d9d"}}></i></a>
</span>
<p className={time ? "operatevalue color-grey-3 task-hide" : "operatevalue task-hide"}>{time || "未设置"}</p>
</li>
</Dropdown>
)
}
export default forwardRef(Date);

View File

@ -1,16 +1,16 @@
import React,{useState, useEffect, useRef, useImperativeHandle,forwardRef} from 'react';
import { Dropdown ,Icon } from 'antd';
import { Dropdown } from 'antd';
import { findDOMNode } from 'react-dom';
function Drop({overlay,value},ref){
function Drop({overlay , children , placement, overlayClassName},ref){
const [ visible , setVisible ] = useState(false);
const refFa = useRef(null);
const refBox = useRef(null);
useImperativeHandle(ref, () => ({
clearVisible: (value) => {
clearVisible: (v) => {
// dropmenuchoose0
setVisible(value);
setVisible(v);
}
}))
@ -32,14 +32,14 @@ function Drop({overlay,value},ref){
}
return(
<Dropdown
placement={"bottomRight"}
placement={placement}
visible={visible}
overlay={<div ref={refFa}>{overlay}</div>}
trigger={['click']}
overlayClassName={overlayClassName}
>
<li ref={refBox} onClick={()=>setVisible(visible ? false : true)}>
<span className="task-hide">{value}</span>
<Icon type="caret-down" className="ml5 color-grey-6" />
{children}
</li>
</Dropdown>
)

View File

@ -1,13 +1,23 @@
import React ,{ useState , useEffect , useRef } from 'react';
import { Dropdown , Menu , Input } from 'antd';
import { Dropdown , Menu , Input, message } from 'antd';
import { findDOMNode } from 'react-dom';
import { getImageUrl } from 'educoder';
const { Search } = Input;
function EditMenus({name,list,value , onAdd , searchFlag}){
// name
// list[]
// value[]
// onAdd
// searchFlag
// editFlag
// double
// onChange:id
function EditMenus({ name , emptyName='未设置',list,value , onAdd , searchFlag , editFlag , searchFunc ,double , onChange , imgFlag}){
const [ menus , setMenus ] = useState([]);
const [ searchValue , setSearchValue ]= useState(undefined);
const [ showValue , setShowValue ] = useState(undefined);
const [ valueId , setValueId ] = useState([]);
const [ visible , setVisible ] = useState(false);
const refFa = useRef(null);
@ -15,7 +25,14 @@ function EditMenus({name,list,value , onAdd , searchFlag}){
useEffect(()=>{
setMenus(list);
setShowValue(value);
if(value && value.length>0 && list && list.length>0){
let n = value.map(item=>{
let n = list.filter(j=>j.id.toString() === item);
return n.length>0 && n[0].name;
});
setValueId(value);
setShowValue(n.join(","));
}
},[list,value])
useEffect(() => {
@ -35,48 +52,106 @@ function EditMenus({name,list,value , onAdd , searchFlag}){
}
}
function chooseMenu(e){
function chooseMenu(i){
setVisible(false);
setShowValue(e.item.props.children)
let l = valueId;
let idStr = i && i.id ? i.id.toString() :i.name;
// idname
if(double){
if(l.indexOf(idStr)>=0){
l = l.filter(k=>k.toString() !== idStr);
}else{
if(valueId.length > double){
message.info(`最多只能添加${double}${name}`);
return;
}
l.push(idStr);
}
setValueId(l);
console.log(l);
let nameList = i && i.id ? getByid(l) : getByName(l);
setShowValue(nameList.length >0 ? nameList.join(",") : undefined);
onChange(l);
}else{
if(l.indexOf(idStr)>=0){
setValueId([]);
onChange([]);
setShowValue(undefined);
}else{
setValueId([`${i.id || i.name}`]);
onChange([`${i.id || i.name}`]);
setShowValue(i.name);
}
}
}
function getByid(l){
return l.length>0 ? l.map(item=>{
let n = list.filter(j=>j.id.toString() === item);
return n.length>0 && n[0].name;
}) :"";
}
function getByName(l){
return l.length>0 ? l.map(item=>{
let n = list.filter(j=>j.name === item);
return n.length>0 && n[0].name;
}) :"";
}
//
function changeSearchvalue(e){
setSearchValue(e.target.value);
searchFunc(e.target.value);
}
return(
<li>
<span>{name}<a><i className="iconfont icon-a-bianji12 font-13" style={{color:"#898d9d"}}></i></a></span>
<Dropdown visible={visible} overlayClassName={"overlayStyle"} placement="bottomLeft" trigger={['click']}
<span>
{name}
{!editFlag && <a ref={refBox} onClick={()=>setVisible(visible ? false : true)}><i className="iconfont icon-a-bianji12 font-13" style={{color:"#898d9d"}}></i></a>}
</span>
<Dropdown
visible={visible}
overlayClassName={"overlayStyle"}
placement="bottomLeft"
trigger={['click']}
overlay={
<div className="branch-tagBox" ref={refFa}>
{ searchFlag &&
<div className="searchbox">
<Search placeholder={`搜索${name}`} value={searchValue} onChange={changeSearchvalue} style={{marginRight:"18px"}}/>
<Search
placeholder={`搜索${name}`}
value={searchValue}
onChange={changeSearchvalue}
style={{marginRight:"18px"}}
/>
</div>
}
{
menus && menus.length >0?
<Menu>
<Menu className="piecemenu" selectedKeys={valueId}>
{
menus.map((i,k)=>{
return(
<Menu.Item key={i.id} onClick={chooseMenu}>{i.name}</Menu.Item>
<Menu.Item key={i.id || i.name} onClick={()=>chooseMenu(i)}>
{ imgFlag && <img src={getImageUrl(i.image_url)} alt="" width="22px" className="mr5 radius"/>}
{i.color && <span style={{backgroundColor:i.color}} className="colorpiece"></span>}
{i.name}
</Menu.Item>
)
})
}
</Menu>
:
<div className="menusEmpty">
<p>{searchValue ? <span>创建新{showValue}{searchValue}</span>: `暂无${name}`}</p>
<p>{searchValue ? <span>暂无{name}{searchValue}</span>: `暂无${name}`}</p>
{ name === "标记" && <a className="color-blue font-15" onClick={()=>{setVisible(false);onAdd()}}><i className="iconfont icon-a-bianji12 font-14 mr5"></i>标记管理</a>}
</div>
}
</div>
}>
<p ref={refBox} onClick={()=>setVisible(visible ? false : true)} className={showValue?"operatevalue color-grey-3":"operatevalue"}>{showValue || "未设置"}</p>
<p className={showValue?"operatevalue color-grey-3 task-hide":"operatevalue task-hide"}>{showValue || emptyName}</p>
</Dropdown>
</li>
)

View File

@ -1,178 +1,54 @@
import React ,{ useImperativeHandle ,forwardRef , useState , useEffect , useRef } from 'react';
import { Input , Menu } from 'antd';
import React ,{ useState , useRef } from 'react';
import { Input , Menu , Icon } from 'antd';
import { getImageUrl } from 'educoder';
import Drop from './drop';
import axios from 'axios';
const { Search } = Input;
// id:
// name
// updateName
// chooseid
// menu
// lists
// imgControl:
// size:small120px,large:260px;
const menus=[
{
id:1,
name:"发布人",
choose:0,
imgControl:true,
size:"large",
menu:[{id:1,name:"111",image_url:'https://testforgeplus.trustie.net/images/avatars/User/36480?t=1672730523'},{id:2,name:"222",image_url:''},{id:3,name:"333",image_url:''},{id:4,name:"4444",image_url:''}]
},
{
id:7,
updateName:"更换优先级",
choose:0,
menu:[{id:1,name:"紧急"},{id:2,name:"正常"},{id:3,name:"低"},{id:4,name:"高"}]
},
{
id:2,
name:"标记",
updateName:"更换标记",
choose:0,
size:"large",
menu:[{id:1,name:"red"},{id:2,name:"blue"},{id:3,name:"orange"},{id:4,name:"yellow"}]
},
{
id:3,
name:"里程碑",
updateName:"更换里程碑",
choose:0,
size:"large",
menu:[{id:1,name:"11-11"},{id:2,name:"22-22"},{id:3,name:"33-33"},{id:4,name:"44-44"}]
},
{
id:4,
name:"负责人",
updateName:"更换负责人",
choose:0,
size:"large",
menu:[{id:1,name:"you",img:''},{id:2,name:"she",img:''},{id:3,name:"he",img:''},{id:4,name:"they",img:''}]
},
{
id:5,
name:"状态",
updateName:"更换状态",
choose:0,
size:"small",
menu:[{id:1,name:"新增"},{id:2,name:"正在解决"},{id:3,name:"已解决"},{id:4,name:"反馈"},{id:5,name:"关闭"},{id:6,name:"拒绝"}]
},
{
id:6,
name:"排序",
choose:0,
size:"small",
menu:[{id:1,name:"最新创建"},{id:2,name:"最早创建"},{id:3,name:"最近更新"},{id:4,name:"最早更新"},{id:5,name:"高优先级"},{id:6,name:"低优先级"}]
}
]
function Menus({update,owner,projectsId},ref){
const [ dropmenu , setDropMenu ] = useState(menus);
// chooseValue: id
// search:
// chooseFunc:
// update:
function Menus({name, id , lists , size , imgControl , searchFunc , chooseFunc , update },ref){
const dropRef = useRef(null);
useEffect(()=>{
getSendPerson();
getSign();
},[])
//
function getSendPerson(){
const url = `/v1/${owner}/${projectsId}/issue_authors`;
axios.get(url).then(result=>{
if(result && result.data){
MenusControl(1,result.data.authors);
}
})
}
//
function getSign(){
const url = `/v1/${owner}/${projectsId}/issue_tags`;
axios.get(url).then(result=>{
if(result && result.data){
MenusControl(2,result.data.issue_tags);
}
})
}
function MenusControl(num,data){
let list = [...dropmenu];
let todolist = [];
todolist = list.map((i,k)=>i.id === num ? {...i,menu:data} : i);
setDropMenu(todolist);
}
useImperativeHandle(ref, () => ({
clearChoose: () => {
// dropmenuchoose0
changeMenusValue(0);
}
}))
useEffect(()=>{
if(update){
}
},[update])
// menus
function changeMenusValue(value,id){
let todoList = [...dropmenu];
let list = [];
if(id){
list = todoList.map((i,k)=>id===i.id ? {...i,choose:value} : i);
}else{
list = todoList.map((i,k)=>id ? i : {...i,choose:value});
}
setDropMenu(list);
chooseFunc(id,value);
dropRef.current && dropRef.current.clearVisible(false);
//
}
function menu(item){
if(item.menu && item.menu.length>0){
return <div className={`overlaydrop ${item.size}`}>
{ item.size !== "small" &&
<div className="pb10"><Search placeholder={`搜索${item.name}`} /></div>
}
<Menu selectedKeys={[`${item.choose}`]}>
{
item.menu.map((i,j)=>{
return <Menu.Item key={i.id}>
{item.imgControl && <img src={getImageUrl(i.image_url)} alt=""/>}
<span onClick={()=>changeMenusValue(i.id,item.id)}>{i.name}</span>
</Menu.Item>
})
}
</Menu>
</div>
function menu(data){
return <div className={`overlaydrop ${size}`}>
{ size !== "small" &&
<div className="pb10"><Search placeholder={`搜索${name}`} allowClear onChange={(e)=>searchFunc(e.target.value)}/></div>
}
else{
return "";
}
{
data && data.length>0 ?
<Menu selectedKeys={[`${id}`]}>
{
data.map((i,j)=>{
return <Menu.Item key={i.id}>
{imgControl && <img src={getImageUrl(i.image_url)} alt=""/>}
<span onClick={()=>changeMenusValue(i.name,i.id)}>{i.name}</span>
</Menu.Item>
})
}
</Menu>
:
<div className="pl15">暂无{id ? <span>'{name}'</span>: name}</div>
}
</div>
}
return(
dropmenu && dropmenu.length >0 ?
<ul className="dropboxul">
{
dropmenu.map((item,i)=>{
let ichoose = item.choose !== 0 && item.menu.filter(k=>k.id === item.choose);
return(
((!update && item.name) || (update && item.updateName)) &&
<Drop
ref={dropRef}
overlay={menu(item)}
value={item.choose !== 0 ? (ichoose.length>0 && ichoose[0].name):(update ? item.updateName : item.name)}
/>
)
})
}
</ul>
:<div></div>
<Drop ref={dropRef} overlay={menu(lists)} placement={"bottomRight"} >
<span className="task-hide">{(update && !id) ? `更换${name}` : name }</span>
<Icon type="caret-down" className="ml5 color-grey-6" />
</Drop>
)
}
export default forwardRef(Menus);
export default Menus;

View File

@ -4,7 +4,7 @@ import bj from '../Img/biaoji.png';
import issueEmp from '../Img/issue-big.png';
import create from '../Img/create.png';
import { Link } from "react-router-dom";
import Menus from '../Component/menus';
import AllMenus from '../Component/allMenus';
import Datas from '../Component/datas';
import DelBox from '../Component/delBox';
import axios from 'axios';
@ -27,8 +27,11 @@ function List(props){
const [ allIds , setAllIds ] = useState([]);
const [ checkAll , setCheckAll ] = useState(false);
const [ updateIds , setUpdateIds ] = useState([]);
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(undefined);
const menuRef = useRef(null);
const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId;
@ -38,13 +41,16 @@ function List(props){
Init();
},[aboutMe,keyword,category])
// issue
function Init(){
function Init(params){
setTotal(undefined);
const url = `/v1/${owner}/${projectsId}/issues`;
axios.get(url,{
params:{
participant_category:aboutMe,
keyword,category
keyword,category,
...params,
sort_direction:(params && params.sort_by) ? ((params.sort_by === 1 || params.sort_by === 3) ? "desc" : "asc") :undefined,
sort_by:(params && params.sort_by) ? ((params.sort_by === 1 || params.sort_by === 2) ? "created_on" : "updated_on") : undefined
}
}).then(result=>{
if(result){
@ -77,8 +83,10 @@ function List(props){
function clearCondition(){
setKeyword(undefined);
setAboutMe("aboutme");
Init();
//
menuRef.current && menuRef.current.clearChoose();
}
// issue
@ -105,6 +113,25 @@ function List(props){
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: [updateIds && updateIds.assigner_id],
ids: allValue,
issue_tag_ids: [updateIds && updateIds.issue_tag_ids],
milestone_id: updateIds && updateIds.milestone_id,
priority_id: updateIds && updateIds.issue_priorities_id,
status_id: updateIds && updateIds.status_id
}).then(result=>{
if(result){
Init();
cancelUpdate();
}
}).catch(error=>{})
}
//
@ -114,7 +141,25 @@ function List(props){
// issue func
function onSuccess(){
const url = `/v1/${owner}/${projectsId}/issues/batch_destroy`;
axios.delete(url,{
params:{ids:allValue}
}).then(result=>{
if(result){
setVisible(false);
props.showNotification("疑修删除成功!");
Init();
}
}).catch(error=>{})
}
function chooseFunc(ids){
if(allValue && allValue.length>0){
// ids便
setUpdateIds(ids);
}else{
Init(ids);
}
}
return(
@ -158,16 +203,17 @@ function List(props){
}
</div>
<div className="menusul">
<Menus
<AllMenus
ref={menuRef}
update={allValue && allValue.length>0}
owner={owner}
projectsId={projectsId}
update={allValue && allValue.length>0}
chooseFunc={chooseFunc}
/>
{
allValue && allValue.length>0 ?
<div>
<Button type="primary" ghost>确定</Button>
<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>
@ -191,7 +237,7 @@ function List(props){
issueList.map((item,key)=>{
return(
<Datas
checkbox={ <Checkbox value={0} key={0} style={{marginRight: "16px"}}></Checkbox> }
checkbox={ <Checkbox value={item.id} key={item.id} style={{marginRight: "16px"}}></Checkbox> }
item={item}
owner={owner}
projectsId={projectsId}

View File

@ -1,5 +1,5 @@
import React , { useEffect , useState } from 'react';
import { Button, Input , Dropdown , Menu } from 'antd';
import React , { useEffect , useState , forwardRef } from 'react';
import { Button, Input , Form } from 'antd';
import { Box , LongWidth } from '../../Component/layout';
import MDEditor from "../../../modules/tpm/challengesnew/tpm-md-editor";
import Upload from "../../Upload/Index";
@ -7,18 +7,131 @@ import Attachments from "../../Upload/attachment";
import UploadImg from '../Img/UploadImg.png';
import EditMenus from '../Component/editMenus';
import AddTagsBox from '../Component/addTagsBox';
import Date from '../Component/date';
import axios from 'axios';
import moment from 'moment';
const menus = {
milestones:[{id:1,name:"里程碑1"},{id:2,name:"里程碑22"}],
issue_tags:[{id:1,name:"标记1"},{id:2,name:"标记22"}]
}
function New(props){
const [ content , setContent ] = useState("");
const [ description , setDescription ] = useState("");
const [ visible , setVisible ] = useState(false);
const [ fileList , setFileList] = useState(undefined);
const [ attachments , setAttachments ] = useState([]);
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 [ charegeId , setCharegeId ] = useState([]);
const [ statusId , setStatusId ] = useState([`1`]);
const [ prioritiesId , setPrioritiesId ] = useState([`2`]);
const [ tagId , setTagId ] = useState([]);
const [ millstoneId , setMillstoneId ] = useState([]);
const [ branchId , setBranchId ] = useState([]);
const [ start_date, setStartDate ] = useState(moment().format('YYYY-MM-DD'));
const [ due_date, setDueDate ] = useState("");
const [ receivers_login , setReceiversLogin ] = useState(undefined);
const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId;
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
//
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){
setPrioritiesList(result.data.priorities);
}
})
}
//
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);
}
})
}
function onContentChange(value){
setContent(value);
setDescription(value);
}
function UploadFunc(fileList){
setFileList(fileList);
@ -26,26 +139,72 @@ function New(props){
//
function onSuccess(){
//
getSign();
setVisible(false);
}
//
function createFunc(){
validateFields((error,values)=>{
if (!error) {
const { subject } = values;
const url = `/v1/${owner}/${projectsId}/issues`;
axios.post(url,{
description,subject,
branch_name:branchId.join(","),
status_id:statusId.join(","),
priority_id:prioritiesId.join(","),
milestone_id:millstoneId.join(","),
issue_tag_ids:tagId,
assigner_ids:charegeId,
attachment_ids:fileList,
start_date,due_date,receivers_login
}).then(result=>{
if(result && result.data && result.data.project_issues_index){
props.showNotification("任务创建成功!");
props.history.push(`/${owner}/${projectsId}/issues/${result.data.project_issues_index}`);
}
}).catch(error=>{})
}
})
}
function changeAtWhoLoginList(loginList){
let list = new Set(receivers_login);
loginList.map(item => list.add(item));
setReceiversLogin(Array.from(list));
};
return(
<div>
<AddTagsBox visible={visible} onCancel={()=>setVisible(false)} onSuccess={onSuccess} />
<AddTagsBox
owner={owner}
projectsId={projectsId}
visible={visible}
onCancel={()=>setVisible(false)} onSuccess={onSuccess}
/>
<p className="font-20 color-grey-3 mt20 mb15">新建疑修</p>
<Box>
<LongWidth>
<Input placeholder="标题"/>
<Form className="explain">
<Form.Item>
{getFieldDecorator("subject",{
rules:[{required:true,message:"请输入疑修标题"}]
})(
<Input placeholder="标题" maxLength={100}/>
)}
</Form.Item>
</Form>
<MDEditor
placeholder={"请输入描述信息"}
height={392}
mdID={"order-new-description"}
initValue={content}
initValue={description}
onChange={onContentChange}
className="mt20"
changeAtWhoLoginList = {changeAtWhoLoginList}
></MDEditor>
<div className="pb20">
<Upload
@ -72,19 +231,22 @@ function New(props){
}
</div>
<div style={{display:"flex"}}>
<Button type="primary" className="operateButton" style={{width:"100px"}}>创建</Button>
<Button type="primary" className="operateButton" style={{width:"100px"}} onClick={createFunc}>创建</Button>
<Button className="ml30" style={{width:"100px"}}>取消</Button>
</div>
</LongWidth>
<div className="shortwidth">
<EditMenus name="负责人" list={menus.issue_tags} searchFlag/>
<EditMenus name="状态" list={menus.issue_tags} searchFlag/>
<EditMenus name="优先级" list={[]}/>
<EditMenus name="标记" list={[]} onAdd={()=>setVisible(true)} searchFlag/>
<EditMenus name="里程碑" list={menus.milestones} searchFlag/>
<EditMenus name="负责人" imgFlag onChange={(ids)=>setCharegeId(ids)} list={chargeList} searchFlag searchFunc={(value)=>setCharge(value)} double={5}/>
<EditMenus name="状态" onChange={(ids)=>setStatusId(ids)} list={statusList} editFlag value={statusId}/>
<EditMenus name="优先级" onChange={(ids)=>setPrioritiesId(ids)} list={prioritiesList} value={prioritiesId}/>
<EditMenus name="标记" onChange={(ids)=>setTagId(ids)} list={tagList} onAdd={()=>setVisible(true)} searchFlag double={3} searchFunc={(value)=>setTag(value)}/>
<EditMenus name="里程碑" emptyName="未关联" onChange={(ids)=>setMillstoneId(ids)} list={millstoneList} searchFlag searchFunc={(value)=>setMillstone(value)}/>
<EditMenus name="关联分支" emptyName="未关联" onChange={(ids)=>setBranchId(ids)} list={branchList} searchFlag searchFunc={(value)=>setBranch(value)}/>
<Date name="开始日期" today={start_date} setDate={(date)=>setStartDate(date)}/>
<Date name="结束日期" today={due_date} setDate={(date)=>setDueDate(date)}/>
</div>
</Box>
</div>
)
}
export default New;
export default Form.create()(forwardRef(New));

View File

@ -201,7 +201,7 @@
align-items: center;
color: #898d9d;
margin-top: 12px;
&>img{
img{
height: 22px;
width: 22px;
margin-right: 4px;
@ -214,14 +214,22 @@
color: #40424a;
.principal{
position: relative;
height: 30px;
height: 20px;
&:hover{
a{
position:initial;
}
}
a{
position: absolute;
right: 0px;
bottom: 0px;
transition: 0.6s;
}
img,span{
width: 20px;
height: 20px;
border-radius: 50%;
position: absolute;
right: 0px;
bottom: 4px;
}
span{
background-color:#ced5ef;
@ -395,7 +403,6 @@
line-height: 20px;
color: #acb0bf;
margin-top: 10px;
cursor: pointer;
}
}
}
@ -445,15 +452,28 @@
border-top: 1px solid rgba(172, 176, 191, 0.17);
}
}
.piecemenu{
li{
display: flex;
align-items: center;
}
}
.colorpiece{
display: block;
width: 22px;
height: 15px;
margin-right: 9px;
border-radius:2px;
}
.overlayStyle{
background-color:#ffffff;
border-radius:6px;
box-shadow:0px 0px 10px rgba(24, 54, 181, 0.17);
.searchbox{
padding:18px 20px 0px 16px;
padding:12px 20px 0px 16px;
}
.ant-menu{
padding:0px 20px 10px 16px;
padding:12px 16px 10px 16px;
max-height: 338px;
overflow-y: auto;
li{
@ -513,6 +533,12 @@
align-items: center;
}
}
// 新建页面
.explain{
.ant-form-explain{
position: absolute;
}
}
// 评论相关
.addcomments{

View File

@ -70,10 +70,12 @@ class Index extends Component {
fileIdList = (fileList) => {
let array = [];
fileList && fileList.length > 0 && fileList.map((item) => {
return array.push(item.response && (item.response.id || (item.response.data && item.response.data.id)));
})
array && this.props.load && this.props.load(array);
if(fileList && fileList.length > 0){
fileList.map((item) => {
return item.response && item.status==="done" && array.push((item.response.id || (item.response.data && item.response.data.id)));
})
array && array.length>0 && this.props.load(array);
}
}
checkFile=(str)=>{