This commit is contained in:
caishi 2023-02-21 15:47:38 +08:00
parent b1f8783026
commit 977a266172
17 changed files with 674 additions and 234 deletions

21
package-lock.json generated
View File

@ -15439,6 +15439,27 @@
"object-assign": "^4.1.1"
}
},
"react-copy-to-clipboard": {
"version": "5.1.0",
"resolved": "https://registry.npmmirror.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz",
"integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==",
"requires": {
"copy-to-clipboard": "^3.3.1",
"prop-types": "^15.8.1"
},
"dependencies": {
"prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
}
}
},
"react-countup": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/react-countup/-/react-countup-6.1.0.tgz",

View File

@ -69,6 +69,7 @@
"react-color": "^2.18.0",
"react-content-loader": "^3.1.1",
"react-cookies": "^0.1.1",
"react-copy-to-clipboard": "^5.1.0",
"react-countup": "^6.1.0",
"react-cropper": "^2.1.8",
"react-datepicker": "^2.14.1",

View File

@ -49,7 +49,7 @@
<script src="https://gw.alipayobjects.com/os/lib/react-dom/16.14.0/umd/react-dom.%REACT_URL%.js"></script>
<script src="%PUBLIC_URL%js/jquery-1.8.3.min.js"></script>
<script src="%PUBLIC_URL%js/js_min_all.js"></script>
<script src="%PUBLIC_URL%js/common.js"></script>
<!-- <script src="%PUBLIC_URL%js/common.js"></script> -->
<script src="%PUBLIC_URL%js/codemirror/codemirror.js"></script>
<script src="%PUBLIC_URL%js/editormd/editormd.min.js"></script>
<script src="%PUBLIC_URL%js/codemirror/merge/merge.js"></script>

View File

@ -111,7 +111,7 @@ function AllMenus({owner,projectsId,chooseFunc,update},ref){
}
function choose(id,name){
let copy = {...ids,author_id:id};
let copy = {...ids,author_id:id.join(",")};
let copyname = { ...names,author_name:name}
setIds(copy);setNames(copyname);
chooseFunc(copy);
@ -121,53 +121,61 @@ function AllMenus({owner,projectsId,chooseFunc,update},ref){
<ul className="dropboxul">
{ !update && <Menus
update={update}
id={ids && ids.author_id}
name={(names && names.author_name) || "发布人" } size={"large"} imgControl
ids={ids && ids.author_id}
names={names && names.author_name}
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"}
ids={ids && ids.issue_priorities_id}
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)}}
names={names && names.issue_priorities_name}
chooseFunc={(id,name)=>{let copy = {...ids,issue_priorities_id:id.join(",")};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"}
ids={ids && ids.issue_tag_ids}
name={"标记"} size={"large"}
double
names={names && names.issue_tag_name}
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)}}
chooseFunc={(id,name)=>{let copy = {...ids,issue_tag_ids:id.join(",")};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"}
ids={ids && ids.milestone_id}
name={"里程碑"} size={"large"}
names={names && names.milestone_name}
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)}}
chooseFunc={(id,name)=>{let copy = {...ids,milestone_id:id.join(",")};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
ids={ids && ids.assigner_id}
name={"负责人"} size={"large"} imgControl
names={names && names.assigner_name}
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)}}
chooseFunc={(id,name)=>{let copy = {...ids,assigner_id:id.join(",")};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"}
ids={ids && ids.status_id}
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)}}
names={names && names.status_name}
chooseFunc={(id,name)=>{let copy = {...ids,status_id:id.join(",")};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"}
ids={ids && ids.sort_by}
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)}}
names={names && names.sortby_name}
chooseFunc={(id,name)=>{let copy = {...ids,sort_by:id.join(",")};let copyname = { ...names,sortby_name:name};setNames(copyname);setIds(copy);chooseFunc(copy)}}
/>
}
</ul>

View File

@ -0,0 +1,21 @@
import React ,{ useState } from 'react';
import { Tooltip } from 'antd';
import { CopyToClipboard } from 'react-copy-to-clipboard';
function Copy({ children , value }){
const [ title , setTitle ] = useState("点击复制链接");
return(
<CopyToClipboard text={value}
onCopy={() => setTitle("复制成功")}>
<Tooltip
placement="bottom"
title={title}
>
{children}
</Tooltip>
</CopyToClipboard>
)
}
export default Copy;

View File

@ -1,8 +1,10 @@
import React from 'react';
import { Checkbox , Tooltip } from 'antd';
import { Tooltip } from 'antd';
import { getImageUrl } from 'educoder';
import issue from '../Img/issue.png';
import { Link } from "react-router-dom";
import Copy from '../Component/copy';
// issue
function Datas({checkbox ,item , projectsId,owner}){
@ -27,7 +29,9 @@ function Datas({checkbox ,item , projectsId,owner}){
{checkbox}
<div className="ilog">
<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>}
{ item.project_issues_index &&
<Copy value={`/${owner}/${projectsId}/issues/${item.project_issues_index}`}><span className="number">#{item.project_issues_index}</span></Copy>
}
</div>
<div style={{marginTop:"-2px"}}>
<div className="idetails mt2">

View File

@ -3,12 +3,13 @@ import Modals from '../../Component/PublicModal/Index';
import { AlignTop } from '../../Component/layout';
import { Button } from 'antd';
function DelBox({visible,onCancel,onSuccess}){
function DelBox({visible,onCancel,onSuccess,content}){
return(
<Modals
visible={visible}
onCancel={onCancel}
title={"删除疑修"}
btn={
<div>
<Button size={'large'} onClick={onCancel}>取消</Button>
@ -19,7 +20,11 @@ function DelBox({visible,onCancel,onSuccess}){
<div className="desc">
<AlignTop className="deldesc">
<i className="iconfont icon-jinggao1 mr10 font-20 red"></i>
<div style={{paddingTop:"3px"}}><p className="font-15 mb20">您确定要删除所有选中的疑修</p><p className="color-grey-6">此操作将清空所有已选中的疑修请谨慎操作</p></div>
{ content ?
content
:
<div style={{paddingTop:"3px"}}><p className="font-15 mb20">您确定要删除所有选中的疑修</p><p className="color-grey-6">此操作将清空所有已选中的疑修请谨慎操作</p></div>
}
</AlignTop>
</div>
</Modals>

View File

@ -5,15 +5,34 @@ import { getImageUrl } from 'educoder';
const { Search } = Input;
// name
// list[]
// value[]
// onAdd
// searchFlag
// editFlag
// double
// onChange:id
function EditMenus({ name , emptyName='未设置',list,value , onAdd , searchFlag , editFlag , searchFunc ,double , onChange , imgFlag}){
/**
*
* @param name显示的标题
* @param names选择下拉项后显示的内容
* @param list[]选项
* @param emptyName:没有选择项时显示的内容
* @param value[]显示的值
* @param onAdd标记管理只针对标记
* @param searchFlag是否显示搜索输入框
* @param editFlag是否有编辑按钮
* @param double可多选
* @param onChange:选择项后返回id数组
* @returns
*/
function EditMenus({
name ,
names,
emptyName='未设置',
list,
value ,
onAdd ,
searchFlag ,
editFlag ,
searchFunc ,
double ,
onChange ,
imgFlag
}){
const [ menus , setMenus ] = useState([]);
const [ searchValue , setSearchValue ]= useState(undefined);
const [ showValue , setShowValue ] = useState(undefined);
@ -25,15 +44,9 @@ function EditMenus({ name , emptyName='未设置',list,value , onAdd , searchFla
useEffect(()=>{
setMenus(list);
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])
setValueId(value);
setShowValue(names && names.length >0 ? names : undefined);
},[names,value,list])
useEffect(() => {
document.addEventListener('click', clickMe , false);
@ -58,46 +71,36 @@ function EditMenus({ name , emptyName='未设置',list,value , onAdd , searchFla
let idStr = i && i.id ? i.id.toString() :i.name;
// idname
if(double){
if(l.indexOf(idStr)>=0){
l = valueId || [] ;
let nameArr = names || [] ;
if(l && l.indexOf(idStr)>=0){
l = l.filter(k=>k.toString() !== idStr);
nameArr = nameArr.filter(k=>k.toString() !== i.name);
}else{
if(valueId.length > double){
if(valueId && valueId.length >= double){
message.info(`最多只能添加${double}${name}`);
return;
}
l.push(idStr);
console.log(valueId,l,idStr);
nameArr.push(i.name);
}
setValueId(l);
console.log(l);
let nameList = i && i.id ? getByid(l) : getByName(l);
setShowValue(nameList.length >0 ? nameList.join(",") : undefined);
onChange(l);
setShowValue(nameArr);
onChange(l,nameArr);
}else{
if(l.indexOf(idStr)>=0){
if(l && l.indexOf(idStr)>=0){
setValueId([]);
onChange([]);
setShowValue(undefined);
}else{
setValueId([`${i.id || i.name}`]);
onChange([`${i.id || i.name}`]);
onChange([`${i.id || i.name}`],[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);
@ -151,7 +154,7 @@ function EditMenus({ name , emptyName='未设置',list,value , onAdd , searchFla
}
</div>
}>
<p className={showValue?"operatevalue color-grey-3 task-hide":"operatevalue task-hide"}>{showValue || emptyName}</p>
<p className={showValue?"operatevalue color-grey-3 task-hide":"operatevalue task-hide"}>{ (names && names.join(",")) || emptyName}</p>
</Dropdown>
</li>
)

View File

@ -1,52 +1,90 @@
import React ,{ useState , useRef } from 'react';
import React ,{ useState , useRef , useEffect } from 'react';
import { Input , Menu , Icon } from 'antd';
import { getImageUrl } from 'educoder';
import Drop from './drop';
const { Search } = Input;
// name
// lists
// imgControl:
// size:small120px,large:260px;
// chooseValue: id
// search:
// chooseFunc:
// update:
function Menus({name, id , lists , size , imgControl , searchFunc , chooseFunc , update },ref){
/**
* @param {name} 未选择时显示的内容
* @param {lists} 下拉列表从接口获取需一一填充
* @param {imgControl} 控制是否显示头像
* @param {size} 下拉框宽度small120px,large:260px
* @param {ids} 默认选择的项的id数组
* @param {search} 搜索方法
* @param {chooseFunc} 选择项后需调用列表的查询方法
* @param {update} 编辑状态
* @param {double} 是否可以多选
*/
function Menus({name, ids , lists , size , imgControl , searchFunc , chooseFunc , update , double ,names },ref){
const dropRef = useRef(null);
const [ chooseValue , setChooseValue ] = useState([]);
const [ showValue , setShowValue ] = useState(undefined);
useEffect(()=>{
setChooseValue(ids);
setShowValue(names);
console.log(names);
},[ids,names])
// menus
function changeMenusValue(value,id){
chooseFunc(id,value);
function changeMenusValue(i){
let l = ids;
let id = i.id.toString();
if(double){
l = ids ? ids.split(",") : [] ;
let nameArr = names ? names.split(",") : [] ;
if(l && l.indexOf(id)>=0){
l = l.filter(k=>k.toString() !== id);
nameArr = nameArr.filter(k=>k.toString() !== i.name);
}else{
l.push(id);
nameArr.push(i.name);
}
setChooseValue(l);
setShowValue(nameArr.join(","));
chooseFunc(l,nameArr.join(","));
}else{
if(l && l.indexOf(id)>=0){
setChooseValue([]);
setShowValue(undefined);
chooseFunc([]);
}else{
setChooseValue([`${i.id}`]);
setShowValue([i.name]);
chooseFunc([id],i.name);
}
}
dropRef.current && dropRef.current.clearVisible(false);
}
function menu(data){
return <div className={`overlaydrop ${size}`}>
{ size !== "small" &&
<div className="pb10"><Search placeholder={`搜索${name}`} allowClear onChange={(e)=>searchFunc(e.target.value)}/></div>
<div className="pb10"><Search placeholder={`搜索${name}`} onChange={(e)=>searchFunc(e.target.value)}/></div>
}
{
data && data.length>0 ?
<Menu selectedKeys={[`${id}`]}>
<Menu selectedKeys={chooseValue}>
{
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>
{i.color && <span style={{backgroundColor:i.color,marginRight:"0px"}} className="colorpiece"></span>}
<span className="task-hide" onClick={()=>changeMenusValue(i)}>{i.name}</span>
</Menu.Item>
})
}
</Menu>
:
<div className="pl15">暂无{id ? <span>'{name}'</span>: name}</div>
<div className="pl15">暂无{ids ? <span>'{name}'</span>: name}</div>
}
</div>
}
return(
<Drop ref={dropRef} overlay={menu(lists)} placement={"bottomRight"} >
<span className="task-hide">{(update && !id) ? `更换${name}` : name }</span>
<span className="task-hide">{showValue || (update ? `更换${name}` : name) }</span>
<Icon type="caret-down" className="ml5 color-grey-6" />
</Drop>
)

View File

@ -0,0 +1,109 @@
import React , { forwardRef , useState } from 'react';
import {LongWidth } from '../../Component/layout';
import { Form , Input , Button } from 'antd';
import MDEditor from "../../../modules/tpm/challengesnew/tpm-md-editor";
import Upload from "../../Upload/Index";
import Attachments from "../../Upload/attachment";
import UploadImg from '../Img/UploadImg.png';
function NewPanel(props,ref){
const [ description , setDescription ] = useState("");
const [ fileList , setFileList] = useState(undefined);
const [ attachments , setAttachments ] = useState([]);
const [ receivers_login , setReceiversLogin ] = useState(undefined);
const { createFunc , title , desc , files , onCancel } = props;
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
useState(()=>{
title && setTimeout(()=>{
setFieldsValue({subject:title});
},100)
desc && setDescription(desc);
files && setAttachments(files);
},[title , desc , files])
function onContentChange(value){
setDescription(value);
}
function UploadFunc(f){
let list = [];
if(files && files.length>0 ){
let arr = files.map(i=>{return i.id});
list = arr && arr.length>0 ? f.concat(arr) : f ;
}
console.log(list);
setFileList(list);
};
function changeAtWhoLoginList(loginList){
let list = new Set(receivers_login);
loginList.map(item => list.add(item));
setReceiversLogin(Array.from(list));
};
function sureFunc(){
validateFields((error,values)=>{
if (!error) {
createFunc(values,fileList,receivers_login,description);
}
})
}
function cancelFunc(){
if(onCancel){
onCancel();
}
}
return(
<React.Fragment>
<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={description}
onChange={onContentChange}
className="mt20"
changeAtWhoLoginList = {changeAtWhoLoginList}
></MDEditor>
<div className="pb20">
<Upload
className="commentStyle mt20"
isComplete={true}
load={UploadFunc}
icon={
<img
src={UploadImg}
width="58"
alt=""
style={{ marginBottom: 15 }}
/>
}
size={100}
showNotification={props.showNotification}
/>
{attachments && attachments.length > 0 &&
<Attachments
attachments={attachments}
showNotification={props.showNotification}
canDelete={true}
></Attachments>
}
</div>
<div style={{display:"flex"}}>
<Button type="primary" className="operateButton" style={{width:"100px"}} onClick={sureFunc}>创建</Button>
<Button className="ml30" style={{width:"100px"}} onClick={cancelFunc}>取消</Button>
</div>
</React.Fragment>
)
}
export default forwardRef(NewPanel);

View File

@ -1,48 +1,323 @@
import React from 'react';
import { Tooltip } from 'antd';
import React , { useEffect , useState , forwardRef } from 'react';
import { Spin , Form } from 'antd';
import { getImageUrl } from 'educoder';
import { Box , LongWidth } from '../../Component/layout';
import RenderHtml from "../../../components/render-html";
import EditMenus from '../Component/editMenus';
import Add from '../Component/comments/add';
import NewPanel from '../Component/newPanel';
import Attachments from "../../Upload/attachment";
import AddTagsBox from '../Component/addTagsBox';
import DelBox from '../Component/delBox';
import Date from '../Component/date';
import moment from 'moment';
import Copy from '../Component/copy';
import axios from 'axios';
function Details(props){
const [ details , setDetails ] = useState(undefined);
const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId;
const index = props.match.params.index;
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 [ 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});
const [ visible , setVisible ] = useState(false);
const [ delVisible , setDelVisible] = useState(false);
const [ edit , setEdit] = useState(false);
const [ start_date, setStartDate ] = useState("");
const [ due_date, setDueDate ] = useState("");
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 cIds = data.assigners && data.assigners.length>0 ? data.assigners.map((i)=>{return i.id.toString();}):undefined;
let cNames = data.assigners && data.assigners.length>0 ? data.assigners.map((i)=>{return i.name.toString();}):undefined;
setCharegeId(cIds);
setStatusId([`${data.status && data.status.id}`]);
setPrioritiesId([`${data.priority && data.priority.id}`]);
let tags = data.tags && data.tags.length>0 ? data.tags.map((i)=>{return i.id.toString();}):undefined;
let tagNames = data.tags && data.tags.length>0 ? data.tags.map((i)=>{return i.name.toString();}):undefined;
setTagId(tags);
setMillstoneId([`${data.milestone && data.milestone.id}`])
setBranchId(data.branch_name && [data.branch_name]);
const n = {
issue_priorities_name:data.priority ? [`${data.priority.name}`]:undefined,
issue_tag_name:tagNames && [tagNames],
milestone_name:data.milestone ? [`${data.milestone.name}`]:undefined,
status_name:data.status ? [`${data.status.name}`]:undefined,
assigner_name:cNames && [cNames]
}
setNames(n);
data.start_date && setStartDate(moment(data.start_date).format('YYYY-MM-DD'));
data.start_date && setDueDate(moment(data.due_date).format('YYYY-MM-DD'));
}
}).catch(error=>{})
}
function statusTag(name){
switch (name) {
case "低":
return "status low";
case "正常":
return "status normal";
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){
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 onSuccess(){
getSign();
setVisible(false);
}
function saveForeach(c,s,p,t,m,b,sDate,eDate){
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
}).then(result=>{
}).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){
const url = `/v1/${owner}/${projectsId}/issues/${index}`;
axios.patch(url,{
subject: values.subject,
attachment_ids: fileList,
receivers_login: receivers_login,
description: description
}).then(result=>{
if(result){
props.showNotification("疑修更新成功!");
Init();
setEdit(false);
}
}).catch(error=>{})
}
return(
details ?
<Box>
<LongWidth>
<div className="detailbanner">
<div className="detailtitle">
<div className="ilog">
<span className="status normal">正常</span>
<span className="number"><Tooltip title="点击复制链接" placement="bottom">#1</Tooltip></span>
</div>
<div>
<p className="name">fork仓库向原仓库发起合并请求查看文件跳转有误</p>
<div>
<a className="author"><img src={`https://testforgeplus.trustie.net/images/avatars/User/36480?t=1672730523`} alt="" />张嘉佳</a>
<span className="ml10" style={{color:"#898d9d"}}>添加于2022-09-27 13:59</span>
</div>
</div>
<DelBox
visible={delVisible}
onCancel={()=>setDelVisible(false)}
onSuccess={deleteFunc}
content={<div style={{paddingTop:"3px"}}><p className="font-15 mb20">您确定要删除当前疑修</p></div>}
/>
<AddTagsBox
owner={owner}
projectsId={projectsId}
visible={visible}
onCancel={()=>setVisible(false)} onSuccess={onSuccess}
/>
{
edit ?
<div style={{paddingTop:"25px"}} >
<NewPanel
{...props}
onCancel={()=>setEdit(false)}
title={details.subject}
desc={details.description}
files={details.attachments}
createFunc={createFunc}
/>
</div>
<ul className="detailoperate">
<li><a className="color-blue"><i className="iconfont icon-a-bianji12 font-12 mr5"></i>编辑</a></li>
<li><a className="color-blue ml20"><i className="iconfont icon-a-fuzhi2 font-12 mr5"></i>复制</a></li>
<li><a className="color-red ml20"><i className="iconfont icon-fuzhi-shanchu font-12 mr5"></i>删除</a></li>
</ul>
</div>
<div className="pt20 pb30">
:
<React.Fragment>
<div className="detailbanner">
<div className="detailtitle">
<div className="ilog">
{details.priority && <span className={statusTag(details.priority.name)}>{ details.priority.name }</span> }
<Copy value={`/${owner}/${projectsId}/issues/${index}`}><span className="number">#{details.project_issues_index}</span></Copy>
</div>
<div>
<p className="name">{details.subject}</p>
{
details.author &&
<div>
<a className="author"><img src={getImageUrl(details.author.image_url)} alt="" />{details.author.name}</a>
<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><a className="color-blue ml20"><i className="iconfont icon-a-fuzhi2 font-12 mr5"></i>复制</a></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 style={{padding:"20px"}}>
{details.description ?
<RenderHtml className="break_word_comments imageLayerParent" value={details.description} 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>
</React.Fragment>
}
{/* <div className="pt20 pb30">
<Add />
</div>
</div> */}
</LongWidth>
<div className="shortwidth mt25">
<EditMenus name="负责人" />
<EditMenus name="状态" />
<EditMenus name="优先级" />
<EditMenus name="标记" />
<EditMenus name="里程碑" />
<EditMenus name="负责人" names={names && names.assigner_name} imgFlag onChange={(ids,name)=>{saveForeach(ids);let copyname = { ...names,assigner_name:name};setNames(copyname);setCharegeId(ids);}} list={chargeList} value={charegeId} searchFlag searchFunc={(value)=>{setCharge(value)}} double={5}/>
<EditMenus name="状态" names={names && names.status_name} onChange={(ids,name)=>{setStatusId(ids);saveForeach(undefined,ids);let copyname = { ...names,status_name:name};setNames(copyname);}} list={statusList} value={statusId}/>
<EditMenus name="优先级" names={names && names.issue_priorities_name} onChange={(ids,name)=>{setPrioritiesId(ids);saveForeach(undefined,undefined,ids);let copyname = { ...names,issue_priorities_name:name};setNames(copyname);}} list={prioritiesList} value={prioritiesId}/>
<EditMenus name="标记" names={names && names.issue_tag_name} onChange={(ids,name)=>{setTagId(ids);saveForeach(undefined,undefined,undefined,ids);let copyname = { ...names,issue_tag_name:name};setNames(copyname);}} list={tagList} value={tagId} onAdd={()=>setVisible(true)} searchFlag double={3} searchFunc={(value)=>setTag(value)}/>
<EditMenus name="里程碑" names={names && names.milestone_name} emptyName="未关联" onChange={(ids,name)=>{setMillstoneId(ids);saveForeach(undefined,undefined,undefined,undefined,ids);let copyname = { ...names,milestone_name:name};setNames(copyname);}} value={millstoneId} list={millstoneList} searchFlag searchFunc={(value)=>setMillstone(value)}/>
<EditMenus name="关联分支" names={branchId} emptyName="未关联" onChange={(ids)=>{setBranchId(ids);saveForeach(undefined,undefined,undefined,undefined,undefined,ids);}} value={branchId} list={branchList} searchFlag searchFunc={(value)=>setBranch(value)}/>
<Date name="开始日期" today={start_date} setDate={(date)=>{setStartDate(date);saveForeach(undefined,undefined,undefined,undefined,undefined,undefined,date)}}/>
<Date name="结束日期" today={due_date} setDate={(date)=>{setDueDate(date);saveForeach(undefined,undefined,undefined,undefined,undefined,undefined,undefined,date)}}/>
</div>
</Box>
:
<div style={{width:"100%",display:"flex",alignItems:"center",justifyContent:'center',height:"400px"}}><Spin /></div>
)
}
export default Details;
export default Form.create()(forwardRef(Details));

View File

@ -35,6 +35,9 @@ function List(props){
const menuRef = useRef(null);
const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId;
console.log(props && props.projectDetail);
const { permission } = props && props.projectDetail;
console.log(permission);
useEffect(()=>{
@ -146,6 +149,7 @@ function List(props){
params:{ids:allValue}
}).then(result=>{
if(result){
setAllValue([]);
setVisible(false);
props.showNotification("疑修删除成功!");
Init();
@ -157,6 +161,7 @@ function List(props){
if(allValue && allValue.length>0){
// ids便
setUpdateIds(ids);
console.log(ids);
}else{
Init(ids);
}
@ -183,7 +188,10 @@ function List(props){
<a className="color-blue ml25" onClick={clearCondition} style={{ display: "flex" , alignItems: "center"}}><i className="iconfont icon-roundclose font-16 mr5"></i>清除筛选条件</a>
</div>
<div>
<Link to={`/${owner}/${projectsId}/issues/sign`} className="dorpdownButton"><img src={bj} alt="" className="mr5" />标记管理</Link>
{
permission && permission !== "reporter" &&
<Link to={`/${owner}/${projectsId}/issues/sign`} className="dorpdownButton"><img src={bj} alt="" className="mr5" />标记管理</Link>
}
<Link to={`/${owner}/${projectsId}/issues/new`} className="operateButton ml20"><img src={create} alt="" className="mr5" />创建疑修</Link>
</div>
</div>

View File

@ -1,21 +1,15 @@
import React , { useEffect , useState , forwardRef } from 'react';
import { Button, Input , Form } from 'antd';
import { Form } from 'antd';
import { Box , LongWidth } from '../../Component/layout';
import MDEditor from "../../../modules/tpm/challengesnew/tpm-md-editor";
import Upload from "../../Upload/Index";
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 NewPanel from '../Component/newPanel';
import axios from 'axios';
import moment from 'moment';
function New(props){
const [ description , setDescription ] = useState("");
const [ visible , setVisible ] = useState(false);
const [ fileList , setFileList] = useState(undefined);
const [ attachments , setAttachments ] = useState([]);
const [ statusList , setStatusList ] = useState([]);
@ -31,26 +25,38 @@ function New(props){
const [ charegeId , setCharegeId ] = useState([]);
const [ statusId , setStatusId ] = useState([`1`]);
const [ names , setNames ] = useState({author_name:undefined,issue_priorities_name:["正常"],issue_tag_name:undefined,milestone_name:undefined,sortby_name:undefined,status_name:['新增'],assigner_name:undefined});
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 [ 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;
//
function updateDocumentTitle(){
// if(form_type === 'feedback'){
// document.title = ``
// }else if(form_type === 'new'){
// document.title = `-${author.name}/${name}`
// }else{
// subject && (document.title = `${subject}--${author.name}/${name}`);
// }
}
//
useEffect(()=>{
getStatus();
},[])
function getStatus(){
const url = `/v1/${owner}/${projectsId}/issue_statues`;
axios.get(url).then(result=>{
@ -130,12 +136,6 @@ function New(props){
})
}
function onContentChange(value){
setDescription(value);
}
function UploadFunc(fileList){
setFileList(fileList);
};
//
function onSuccess(){
@ -145,36 +145,27 @@ function New(props){
}
//
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 createFunc(values,fileList,receivers_login,description){
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(
@ -188,60 +179,15 @@ function New(props){
<p className="font-20 color-grey-3 mt20 mb15">新建疑修</p>
<Box>
<LongWidth>
<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={description}
onChange={onContentChange}
className="mt20"
changeAtWhoLoginList = {changeAtWhoLoginList}
></MDEditor>
<div className="pb20">
<Upload
className="commentStyle mt20"
isComplete={true}
load={UploadFunc}
icon={
<img
src={UploadImg}
width="58"
alt=""
style={{ marginBottom: 15 }}
/>
}
size={100}
showNotification={props.showNotification}
/>
{attachments && attachments.length > 0 &&
<Attachments
attachments={attachments}
showNotification={props.showNotification}
canDelete={true}
></Attachments>
}
</div>
<div style={{display:"flex"}}>
<Button type="primary" className="operateButton" style={{width:"100px"}} onClick={createFunc}>创建</Button>
<Button className="ml30" style={{width:"100px"}}>取消</Button>
</div>
<NewPanel {...props} createFunc={createFunc}/>
</LongWidth>
<div className="shortwidth">
<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)}/>
<EditMenus name="负责人" value={charegeId} names={names && names.assigner_name} imgFlag onChange={(ids,name)=>{setCharegeId(ids);let copyname = { ...names,assigner_name:name};setNames(copyname);}} list={chargeList} searchFlag searchFunc={(value)=>setCharge(value)} double={5}/>
<EditMenus name="状态" value={statusId} names={names && names.status_name} onChange={(ids,name)=>{setStatusId(ids);let copyname = { ...names,status_name:name};setNames(copyname);}} list={statusList} editFlag/>
<EditMenus name="优先级" value={prioritiesId} names={names && names.issue_priorities_name} onChange={(ids,name)=>{setPrioritiesId(ids);let copyname = { ...names,issue_priorities_name:name};setNames(copyname);}} list={prioritiesList}/>
<EditMenus name="标记" value={tagId} names={names && names.issue_tag_name} onChange={(ids,name)=>{setTagId(ids);let copyname = { ...names,issue_tag_name:name};setNames(copyname);}} list={tagList} onAdd={()=>setVisible(true)} searchFlag double={3} searchFunc={(value)=>setTag(value)}/>
<EditMenus name="里程碑" value={millstoneId} names={names && names.milestone_name} emptyName="未关联" onChange={(ids,name)=>{setMillstoneId(ids);let copyname = { ...names,milestone_name:name};setNames(copyname);}} list={millstoneList} searchFlag searchFunc={(value)=>setMillstone(value)}/>
<EditMenus name="关联分支" value={branchId} names={branchId} 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>

View File

@ -27,26 +27,26 @@ function Index(props){
<Switch>
<Route
path="/:owner/:projectsId/issues/new"
render={() => (
<New {...props}/>
)}
></Route>
<Route
path="/:owner/:projectsId/issues/:index"
render={() => (
<Detail {...props}/>
render={(p) => (
<New {...props} {...p}/>
)}
></Route>
<Route
path="/:owner/:projectsId/issues/sign"
render={() => (
<Sign {...props}/>
render={(p) => (
<Sign {...props} {...p}/>
)}
></Route>
<Route
path="/:owner/:projectsId/issues/:index"
render={(p) => (
<Detail {...props} {...p}/>
)}
></Route>
<Route
path="/:owner/:projectsId/issues"
render={() => (
<List {...props}/>
render={(p) => (
<List {...props} {...p}/>
)}
></Route>
</Switch>

View File

@ -290,6 +290,7 @@
text-align: center;
display: block;
margin-top: 14px;
cursor: pointer;
}
}
// colorCard
@ -460,7 +461,7 @@
}
.colorpiece{
display: block;
width: 22px;
width: 22px!important;
height: 15px;
margin-right: 9px;
border-radius:2px;
@ -500,11 +501,11 @@
//详情页面
.detailbanner{
margin-top: 25px;
height:82px;
// height:82px;
background-color:#fafcff;
border:1px solid rgba(42, 97, 255, 0.23);
border-radius:4px;
padding:0px 25px 0px 20px;
padding:12px 25px 12px 20px;
display: flex;
align-items: center;
justify-content: space-between;
@ -514,9 +515,9 @@
font-size: 16px;
font-weight: 700;
color:#333;
height: 22px;
line-height: 22px;
margin-bottom: 9px!important;
max-width: 580px;
}
.author{
img{

View File

@ -742,11 +742,11 @@ class Detail extends Component {
}
></Route>
{/* 标签列表 */}
<Route path="/:owner/:projectsId/issues/tags"
{/* <Route path="/:owner/:projectsId/issues/tags"
render={
(props) => (<TagList {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
></Route> */}
{/* 仓库设置 */}
<Route path="/:owner/:projectsId/settings"
render={
@ -791,17 +791,17 @@ class Detail extends Component {
}
></Route> */}
{/* 修改详情 edit*/}
<Route path="/:owner/:projectsId/issues/:orderId/edit"
{/* <Route path="/:owner/:projectsId/issues/:orderId/edit"
render={
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"edit"} />)
}
></Route>
></Route> */}
{/* 复制详情 copyetail*/}
<Route path="/:owner/:projectsId/issues/:orderId/copyetail"
{/* <Route path="/:owner/:projectsId/issues/:orderId/copyetail"
render={
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"copy"} />)
}
></Route>
></Route> */}
{/* 任务详情 */}
{/* <Route path="/:owner/:projectsId/issues/:orderId"

View File

@ -1,10 +1,10 @@
import React , { forwardRef, useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { Button, Form , Input } from 'antd';
import { Form , Input } from 'antd';
import Axios from 'axios';
const { TextArea } = Input;
function New({ form , showNotification , history }) {
function New({ form , showNotification , history },ref) {
const { getFieldDecorator, validateFields , setFieldsValue } = form;
const [ msg , setMsg ] = useState(undefined);