负责人、标记弹框平铺

This commit is contained in:
caishi 2023-03-08 10:07:14 +08:00
parent fd1e2fa668
commit c440358236
9 changed files with 404 additions and 47 deletions

View File

@ -0,0 +1,252 @@
import React ,{ useState , useEffect , useRef } from 'react';
import { findDOMNode } from 'react-dom';
import { Dropdown , Menu , Input , message, Button} from 'antd';
import { getImageUrl } from 'educoder';
const { Search } = Input;
/**
*
* @param {placeholder} placeholder:默认显示内容为空时
* @param {editFlag} editFlag:是否有编辑权限
* @param {searchFlag} searchFlag:是否显示搜索框
* @param {selectValueList} selectValueList:将选中的list保存
* @param {searchFunc} searchFunc:搜索方法
* @param {onAdd} onAdd:标记管理
* @param {headImg} headImg:是否显示头像
* @param {menus} menus:下拉列表
* @param {chooseFunc} chooseFunc:选择下拉列表
* @param {double} double:undefined为单选有值就是最多选的数量
* @param {colorFlag} colorFlag:选中值需根据颜色显示背景
* @param {mustFlag} mustFlag:必须选择一个
* @param {removeFlag} removeFlag:移除按钮
* @returns
*/
function ChooseMenu({
placeholder ="未设置",
editFlag,
searchFlag,
selectValueList,
searchFunc,
onAdd,
headImg,
menus,
chooseFunc,double,colorFlag,mustFlag,removeFlag
}){
const [ visible , setVisible ] = useState(false);
const [ searchValue , setSearchValue ]= useState(undefined);
const [ valuesId , setValuesId ] = useState([]);
const [ count , setCount ] = useState(double);
const [ saveList , setSaveList ] = useState(undefined);
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);
const pointer = !target || (target && target.className && (target.className.indexOf("removeicon")===-1 && target.className.indexOf("icon-guanbi")===-1));
if(!isChild && !isBox && pointer){
setVisible(false);
}
}
}
// id
useEffect(()=>{
if(selectValueList && selectValueList.length > 0 && visible ){
renderSelectList(selectValueList);
setSaveList(selectValueList);
setCount(selectValueList.length);
}else{
setValuesId([]);
setCount(0);
}
if(!visible){
setSearchValue(undefined);
searchFunc(undefined);
}
},[selectValueList,visible])
function renderSelectList(list){
let a = list && list.length > 0 && list.map((i,k)=>{
return i.id ? i.id.toString() : i.name
})
setValuesId(a);
}
//
function changeSearchvalue(e){
setSearchValue(e.target.value);
searchFunc(e.target.value);
}
function renderNames(nameArrs){
return <React.Fragment>
{
nameArrs && nameArrs.length>0?
nameArrs.map((i,k)=>{
return(
<p style={{display:"flex",alignItems:"center"}} className={removeFlag?"removeFlag":''}>
{i.image_url && <img src={getImageUrl(i.image_url)} alt="" width="18px" height="18px" style={{borderRadius:"50%"}} className="mr5"/>}
{
colorFlag ?
(
colorFlag === "2" ?
<span className={"colorsquare task-hide"} style={{backgroundColor:`${i.color}`}}>{i.name}</span>
:
<span className={"colorsborder task-hide"} style={{borderColor:`${i.color}`,color:`${i.color}`}}>{i.name}</span>
)
:
<span className={"task-hide"}>{i.name}</span>
}
{ removeFlag && <a className="removeicon"><i className="iconfont icon-shanchu8 font-14"></i></a>}
</p>
)
})
:<span>{placeholder}</span>
}
</React.Fragment>
}
//
function chooseMenu(i){
let list = saveList && saveList.length > 0 ? [...saveList]:[] ;
let relist = [];
relist = list && list.length > 0 ? list:[];
let filter = [];
if(i.id){
filter = list.filter(j=>j.id === i.id);
}else{
filter = list.filter(j=>j.name === i.name);
}
if(filter && filter.length > 0){
if(i.id){
relist = list.filter(j=>j.id !== i.id);
}else{
relist = list.filter(j=>j.name !== i.name);
}
}else{
if(double && (saveList && saveList.length >= double)){
setCount(-1);
return;
}
if(double){
relist.push(i);
}else{
relist = [i];
}
}
renderSelectList(relist);
setSaveList(relist);
setCount(relist ? relist.length :0);
}
//
function onSureFunc(){
setVisible(false);
chooseFunc(saveList);
}
//
function removeSaveFunc(id){
let list = [...saveList];
let filter = list.filter(j=>j.id !== id);
setSaveList(filter);
renderSelectList(filter);
setCount(filter ? filter.length :0);
}
return(
<li>
<span>
{placeholder}
<Dropdown
visible={visible}
overlayClassName={"overlayChooseStyle"}
placement="bottomRight"
trigger={['click']}
overlay={
<div ref={refFa}>
{
saveList && saveList.length>0?
<ul className="choosedul">
{
saveList.map((i,k)=>{
return(
<li>
<span className="task-hide">{i.name}</span>
<a className="removeicon" onClick={()=>removeSaveFunc(i.id)}><i className="iconfont icon-guanbi font-12 color-blue"></i></a>
</li>
)
})
}
</ul>
:""
}
{ searchFunc &&
<div className="searchbox">
<Search
placeholder={`请输入${placeholder}名称进行搜索`}
value={searchValue}
onChange={changeSearchvalue}
style={{marginRight:"18px"}}
/>
</div>
}
{
menus && menus.length >0?
<Menu className="piecemenu" selectedKeys={valuesId}>
{
menus.map((i,k)=>{
return(
<Menu.Item key={i.id || i.name} className={colorFlag ?"colorli":"commonli"} style={{backgroundColor:colorFlag?`${i.color || "#000"}`:"#f4f6fe"}} onClick={()=>chooseMenu(i)}>
<span><span className="task-hide">{i.name}</span></span>
</Menu.Item>
)
})
}
</Menu>
:
<div className="menusEmpty">
<p>{searchValue ? <span>暂无{placeholder}{searchValue}</span>: `暂无${placeholder}`}</p>
</div>
}
<div className="counttips">
<div>
{ onAdd &&
<a className="color-blue font-15" onClick={()=>{setVisible(false);onAdd()}}>
<i className="iconfont icon-a-bianji12 font-14 mr5"></i>标记管理</a>
}
</div>
{
double && (count<0 ?
<p className="color-red font-13">最多添加{double}{placeholder}</p>
:
<p className="font-13" style={{color:"#898d9d"}}>还可添加{double - count}{placeholder}</p>
)
}
</div>
<div style={{textAlign:'center'}}>
<Button style={{width:"80px"}} onClick={()=>setVisible(false)}>取消</Button>
<Button style={{width:"80px"}} className="ml20" type="primary" onClick={onSureFunc}>确认</Button>
</div>
</div>
}>
{!editFlag &&
<a ref={refBox} onClick={()=>setVisible(visible ? false : true)}>
<i className="iconfont icon-a-bianji12 font-13" style={{color:"#898d9d"}}></i>
</a>
}
</Dropdown>
</span>
<div className={selectValueList && selectValueList.length > 0 ? "operatevalue color-grey-3":"operatevalue"}>{renderNames(selectValueList)}</div>
</li>
)
}
export default ChooseMenu;

View File

@ -1,6 +1,6 @@
import React from 'react';
import { getImageUrl } from 'educoder';
import issue from '../Img/issue.png';
import gold from '../Img/gold.png';
import { Link } from "react-router-dom";
import Copy from '../Component/copy';
import { Tooltip } from 'antd';
@ -40,7 +40,7 @@ function Datas({checkbox ,item , projectsId,owner}){
item.tags && item.tags.length>0?
item.tags.map((i,k)=>{
return(
<span style={{backgroundColor: `${i.color}`}} className="ml12 tagscolor task-hide" title={i.name}>{i.name}</span>
<span style={{backgroundColor: `${i.color}`}} className="ml8 tagscolor task-hide" title={i.name}>{i.name}</span>
)
})
:""
@ -54,10 +54,11 @@ function Datas({checkbox ,item , projectsId,owner}){
}
</div>
<Link to={`/${item.author && item.author.login}`}><i className="iconfont icon-chengyuan2 mr3 font-12" style={{color:'#898d9d'}}></i></Link>
<span className="mr20"><Link style={{color:"#898d9d"}} 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 style={{maxWidth:"310px"}} title={item.milestone_name} className="task-hide"><i className="iconfont icon-lichengbeiicon1 font-12 mr3"></i>{item.milestone_name}</span> }
<span className="mr12"><Link style={{color:"#898d9d"}} to={`/${item.author && item.author.login}`}>{item.author && item.author.name}</Link></span>
<span className="mr12">{item.created_at} 发布</span>
<span className="mr20">{item.updated_at}更新</span>
{item.blockchain_token_num && <span className="mr30"><img src={gold} alt="" width="13px" className="mr3"/>{item.blockchain_token_num}</span>}
{item.milestone_name && <span style={{maxWidth:item.blockchain_token_num ? "261px":"340px"}} title={item.milestone_name} className="task-hide"><i className="iconfont icon-lichengbeiicon1 font-12 mr3"></i>{item.milestone_name}</span> }
</div>
</div>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

View File

@ -15,6 +15,7 @@ import Copy from '../Component/copy';
import axios from 'axios';
import CommentList from '../Component/comments/list';
import Claims from '../../claims/claims';
import ChooseMenu from '../Component/chooseMenu';
function Details(props){
const [ details , setDetails ] = useState(undefined);
@ -395,7 +396,7 @@ function Details(props){
</LongWidth>
<div className="shortwidth mt25">
{orderId && <div className="claimpart"><Claims issue_id={orderId} {...props} refreshFunc={refreshFunc}/></div>}
<DropMenu
<ChooseMenu
placeholder="负责人"
menus={chargeList}
searchFunc={(value)=>{setCharge(value)}}
@ -423,7 +424,7 @@ function Details(props){
editFlag={details && !details.user_permission}
chooseFunc={(list)=>{setPrioritie_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,undefined,l);}}
/>
<DropMenu
<ChooseMenu
placeholder="标记"
menus={tagList}
searchFunc={(value)=>{setTag(value)}}

View File

@ -45,7 +45,7 @@ function List(props){
const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId;
const permission = props && props.projectDetail && props.projectDetail.permission;
const { projectDetail , current_user } = props;
const { projectDetail , current_user} = props;
useEffect(()=>{
if(projectDetail){

View File

@ -23,6 +23,9 @@ const New = Loadable({
function Index(props){
const pathname = props.history.location.pathname;
const {project } = props;
const open_blockchain = project && project.open_blockchain;
console.log("是否开启了确权:",open_blockchain);
useEffect(() => {
if (document) { //
@ -37,38 +40,38 @@ function Index(props){
<Route
path="/:owner/:projectsId/issues/:index/copy"
render={(p) => (
<Detail {...props} {...p}/>
<Detail {...props} {...p} open_blockchain={open_blockchain}/>
)}
></Route>
{/* 里程碑创建issue */}
<Route
path="/:owner/:projectsId/issues/:milepostId/new"
render={(p) => (
<New {...props} {...p}/>
<New {...props} {...p} open_blockchain={open_blockchain}/>
)}
></Route>
<Route
path="/:owner/:projectsId/issues/new"
render={(p) => (
<New {...props} {...p}/>
<New {...props} {...p} open_blockchain={open_blockchain}/>
)}
></Route>
<Route
path="/:owner/:projectsId/issues/sign"
render={(p) => (
<Sign {...props} {...p}/>
<Sign {...props} {...p} open_blockchain={open_blockchain}/>
)}
></Route>
<Route
path="/:owner/:projectsId/issues/:index"
render={(p) => (
<Detail {...props} {...p}/>
<Detail {...props} {...p} open_blockchain={open_blockchain}/>
)}
></Route>
<Route
path="/:owner/:projectsId/issues"
render={(p) => (
<List {...props} {...p}/>
<List {...props} {...p} open_blockchain={open_blockchain}/>
)}
></Route>
</Switch>

View File

@ -224,7 +224,7 @@
}
.tagscolor{
padding:0px 6px;
border-radius: 3px;
border-radius: 2px;
height: 20px;
line-height: 20px;
max-width: 108px;
@ -239,12 +239,12 @@
color: #898d9d;
margin-top: 12px;
font-size: 13px;
img{
height: 22px;
width: 22px;
margin-right: 4px;
border-radius: 50%;
}
// img{
// height: 22px;
// width: 22px;
// margin-right: 4px;
// border-radius: 50%;
// }
}
.issuecondition{
display: flex;
@ -293,7 +293,7 @@
.status{
display: block;
height:22px;
border-radius:3px;
border-radius:6px;
text-align: center;
margin-right: 10px;
line-height: 20px;
@ -714,7 +714,110 @@
// 声明
.claimpart{
padding-bottom: 10px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
margin-bottom: 20px;
}
// issue版本2
.overlayChooseStyle{
width: 636px;
background-color:#ffffff;
border-radius:6px;
box-shadow:0px 0px 10px rgba(24, 54, 181, 0.17);
z-index: 100;
padding:30px 20px;
.choosedul{
display: flex;
flex-wrap: wrap;
padding-bottom: 10px;
border-bottom: 1px solid #e4e4e6;
margin-bottom: 20px!important;
li{
height:24px;
background-color:#eff2ff;
border:1px solid;
border-color:#466aff;
border-radius:2px;
color:#466aff;
font-size:14px;
margin-right: 15px;
margin-bottom: 10px!important;
padding:0px 7px;
display: flex;
align-items: center;
span{
display: block;
max-width:120px ;
}
}
}
.counttips{
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.ant-menu{
display: flex;
flex-wrap: wrap;
padding:20px 0px 5px 0px;
box-sizing: border-box;
max-height: 307px;
overflow-y: auto;
li{
width: 100px;
height:32px;
line-height:30px;
text-align: center;
font-size:14px;
border-radius:2px;
margin-right: 24px!important;
margin-bottom: 15px!important;
border:1px solid!important;
border-color: #f4f6fe!important;
padding:0px 5px;
&.commonli{
background-color:#f4f6fe!important;
}
.removeicon{
display: block;
}
span.task-hide{
color: #3f455b;
margin:0px auto;
position: relative;
color:#3f455b;
max-width: 85px;
display: block;
}
&.colorli{
border-color: transparent!important;
span{
color: #fff;
position: relative;
margin:0px auto;
}
}
&.commonli.ant-menu-item-selected{
background-color:#e2e8ff!important;
color:#3f5097;
border-color:#466aff!important;
}
&.colorli.ant-menu-item-selected{
border-color: transparent!important;
}
&.colorli.ant-menu-item-selected{
&>span::before{
content:"";
position: absolute;
right: -12px;
color: #fff;
top: 0px;
}
}
&:nth-child(5n){
margin-right: 0px!important;
}
}
}
}

View File

@ -13,6 +13,9 @@
.menuPanels{
width: 295px;
.ant-popover-arrow{
bottom: 10.2px!important;
}
&.maxWidth{
width: 400px;
}
@ -60,11 +63,13 @@
flex-wrap: wrap;
padding-bottom: 2px;
a{
margin: 0px 10px 10px 0px;
margin: 0px 2px 0px 0px;
height: 22px;
line-height: 20px;
img{
border-radius: 50%;
width: 40px;
height: 40px;
width: 22px;
height: 22px;
}
&:nth-child(4n){
margin-right: 0px;

View File

@ -173,21 +173,21 @@ class claims extends React.Component {
const renderClaim = () => {
return (
<div className="claimNote_input" style={{ width: "400" }}>
<div className="mb5"> 声明留言</div>
<div className="mb10"> 声明留言</div>
<TextArea
rows={6}
rows={4}
type="text"
placeholder="例如可以留言你的解决思路......"
onChange={this.changeClaimNote}
value={claimNoteBody}
className={claimNoteBodyError ? 'error' : ''}
/>
<div className="mt10" style={{color: 'red'}}>{claimNoteBodyError}</div>
<div style={{ display: "flex", justifyContent: "center" }} className="mt10">
<Button onClick={() => this.cancelClaim()}> </Button>
<div style={{color: 'red',height:"20px",lineHeight:"20px"}}>{claimNoteBodyError}</div>
<div style={{ display: "flex", justifyContent: "center" }}>
<Button style={{width:"67px" }} onClick={() => this.cancelClaim()}> </Button>
<Button
onClick={() => this.yesClaim()}
style={{ marginLeft: "20px" }}
style={{ marginLeft: "20px",width:"67px" }}
type={"primary"}
>
@ -211,26 +211,19 @@ class claims extends React.Component {
className="radius"
src={getImageUrl(`/${item && item.user_picture}`)}
alt=""
width="30"
height="30"
width="46"
height="46"
/>
</Link>
<Link
to={`/${item && item.user_login}`}
className="show-user-link color-black ml10 fwb"
className="show-user-link color-black ml10"
>
<div>
{current_user.login == item.user_login ? (
<div></div>
) : (
<div>{item && item.user_name}</div>
)}
<div className="font-16" style={{fontWeight:500,color:"#1e1d1d"}}>{current_user.login === item.user_login ? "你": item.user_name} </div>
<span className="color-grey-8 font-12"> 声明于 {item.created_at}</span>
</div>
</Link>
<div style={{ marginLeft: "10px" }}>
{" "}
<span className="color-grey-8"> 声明于 {item.created_at}</span>
</div>
</AlignCenter>
</FlexAJ>
<div className="claimNote">
@ -245,6 +238,7 @@ class claims extends React.Component {
justifyContent: "center",
paddingBottom: "10px",
paddingTop: "10px",
width:"83px"
}}
>
<Button
@ -293,8 +287,6 @@ class claims extends React.Component {
</Button>}
</Popover>
<div className="ant-divider ant-divider-horizontal"> </div>
{claimerData && claimerData.length > 0 ? (
<div>
<div className="mt15">