ADD file via upload implemented #1
This commit is contained in:
parent
dbb3624b4d
commit
a18594e1c3
|
@ -0,0 +1,434 @@
|
|||
import { Input , Badge , Avatar , Menu } from 'antd';
|
||||
import { Dispatch, Link, connect } from 'umi';
|
||||
import './index.less';
|
||||
import { EnterpriseModelState } from '@/models/enterprise';
|
||||
import { UsersModelState } from '@/models/user';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { WorkStandModelState } from '@/models/workStand';
|
||||
import { Table , Row , Col , Progress , Pagination , Spin } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { workItemIcon , workItemType , workItemStatus} from '@/constant/project';
|
||||
import { StatusTag } from '@/components/Tags/Tags';
|
||||
import { toTimeFormat } from '@/utils/util';
|
||||
// import { iterationStatusList } from '@/constant/project';
|
||||
import styles from './index.less';
|
||||
import NoData from '@/components/NoData';
|
||||
|
||||
interface HomePageProps {
|
||||
enterprise: EnterpriseModelState;
|
||||
user:UsersModelState
|
||||
dispatch:Dispatch,
|
||||
workStand:WorkStandModelState
|
||||
}
|
||||
const Index: React.FC<HomePageProps> = ({ enterprise ,user , dispatch , workStand }) => {
|
||||
const { currentUser } = user;
|
||||
const { identifier:enterIdentifier } = enterprise;
|
||||
const [ search , setSearch ] = useState<string>("");
|
||||
const [ selectKey , setSelectKey ] = useState<string>("assignedme");
|
||||
|
||||
const [ statictisData , setStatictisData ] = useState<any>([]);
|
||||
const [ dataSource , setDataSource ] = useState<any>([]);
|
||||
|
||||
const [ workLoading , setWorkLoading ] =useState<boolean>(true);
|
||||
const [ workPage , setWorkPage ] = useState<number>(1);
|
||||
const [ workTotal , setWorkTotal ] = useState<number>(0);
|
||||
|
||||
const [ projectData , setProjectData ] = useState<any>([]);
|
||||
const [ projectLoading , setProjectLoading ] =useState<boolean>(true);
|
||||
const [ projectPage , setProjectPage ] = useState<number>(1);
|
||||
const [ projectTotal , setProjectTotal ] = useState<number>(0);
|
||||
|
||||
const [ planData , setPlanData ] = useState<any>([]);
|
||||
const [ planLoading , setPlanLoading ] =useState<boolean>(true);
|
||||
const [ planPage , setPlanPage ] = useState<number>(1);
|
||||
const [ planTotal , setPlanTotal ] = useState<number>(0);
|
||||
|
||||
const [ authoredmeCount , setAuthoredmeCount ] = useState<number>(0);
|
||||
const [ assignedmeCount , setAssignedmeCount ] = useState<number>(0);
|
||||
|
||||
function getCurrentTime() {
|
||||
const currentHour = new Date().getHours();
|
||||
|
||||
if (currentHour >= 6 && currentHour < 9) {
|
||||
return "早上好!";
|
||||
} else if (currentHour >= 9 && currentHour < 12) {
|
||||
return "上午好!";
|
||||
}else if (currentHour >= 12 && currentHour < 14) {
|
||||
return "中午好!";
|
||||
} else if (currentHour >= 14 && currentHour < 18) {
|
||||
return "下午好!";
|
||||
} else if(currentHour >= 18) {
|
||||
return "晚上好!";
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
if(enterIdentifier){
|
||||
getStatistics();
|
||||
}
|
||||
},[enterIdentifier])
|
||||
|
||||
useEffect(()=>{
|
||||
if(enterIdentifier){
|
||||
getIteratioins();
|
||||
}
|
||||
},[enterIdentifier,planPage])
|
||||
|
||||
useEffect(()=>{
|
||||
if(enterIdentifier){
|
||||
getProjects();
|
||||
}
|
||||
},[enterIdentifier,projectPage])
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
if(enterIdentifier){
|
||||
setWorkPage(1);
|
||||
getWorkItem(1);
|
||||
}
|
||||
},[enterIdentifier,selectKey,search])
|
||||
|
||||
// 获取我的工作台统计信息
|
||||
async function getStatistics() {
|
||||
let res:any = await dispatch({
|
||||
type:"workStand/getMyStatistics",
|
||||
})
|
||||
setStatictisData(res?.data);
|
||||
setAssignedmeCount(res?.data?.assignedmeCount);
|
||||
setAuthoredmeCount(res?.data?.authoredmeCount);
|
||||
}
|
||||
// 获取我的迭代
|
||||
async function getIteratioins() {
|
||||
setPlanLoading(true);
|
||||
let res:any = await dispatch({
|
||||
type:"workStand/getMyIterations",
|
||||
payload:{
|
||||
pageNum:planPage,pageSize:5,statusIds:1
|
||||
}
|
||||
})
|
||||
if(res?.code === 200){
|
||||
setPlanData(res?.rows);
|
||||
setPlanTotal(res?.total);
|
||||
}
|
||||
setPlanLoading(false);
|
||||
}
|
||||
// 获取我的项目
|
||||
async function getProjects() {
|
||||
setProjectLoading(true);
|
||||
let res:any = await dispatch({
|
||||
type:"workStand/getMyProjects",
|
||||
payload:{
|
||||
pageNum:projectPage,pageSize:4,status:1
|
||||
}
|
||||
})
|
||||
if(res?.code === 200){
|
||||
setProjectData(res?.rows);
|
||||
setProjectTotal(res?.total);
|
||||
}
|
||||
setProjectLoading(false);
|
||||
}
|
||||
// 获取我的工作项
|
||||
async function getWorkItem(page:number) {
|
||||
setWorkLoading(true);
|
||||
let res:any = await dispatch({
|
||||
type:"workStand/getMyWorkItem",
|
||||
payload:{
|
||||
participantCategory:selectKey,page,limit:5,category:"opened",keyword:search
|
||||
}
|
||||
})
|
||||
if(res?.code === 200){
|
||||
setDataSource(res?.data?.issues);
|
||||
setWorkTotal(res?.data?.total_count);
|
||||
if(selectKey === "assignedme"){
|
||||
setAssignedmeCount(res?.data?.opened_count);
|
||||
}else{
|
||||
setAuthoredmeCount(res?.data?.opened_count);
|
||||
}
|
||||
}
|
||||
setWorkLoading(false);
|
||||
}
|
||||
|
||||
const columns: ColumnsType<API.projects.workItem>=[
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'subject',
|
||||
key: 'subject',
|
||||
width: '40%',
|
||||
ellipsis:{
|
||||
showTitle: false
|
||||
},
|
||||
render:(value:string,record:any)=>{
|
||||
return(
|
||||
<a className="alignCenter" onClick={async()=>{
|
||||
await dispatch({
|
||||
type:"project/setCurrent",
|
||||
payload: { id: record?.pm_project_id }
|
||||
})
|
||||
await dispatch({
|
||||
type:'project/setOpen',
|
||||
payload:{
|
||||
open:false,
|
||||
id:record?.id,
|
||||
editOpen:true,
|
||||
pmIssueType:record?.pm_issue_type,
|
||||
parent:"workStand",
|
||||
onOk:getWorkItem
|
||||
}
|
||||
})
|
||||
window.history.pushState({},"0",`/${enterIdentifier}/projects/${record?.pm_project_id}/${workItemType[record?.pm_issue_type]}/${record?.id}`)
|
||||
}}><i className={`iconfontColor ${workItemIcon[record?.pm_issue_type]} font16 mr10`} /><span className={"hide"}>{value}</span></a>
|
||||
)
|
||||
}
|
||||
},{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: '14%',
|
||||
ellipsis:{
|
||||
showTitle: false
|
||||
},
|
||||
render:(value:any,record:any)=>{
|
||||
let type = record?.pm_issue_type === 1? workItemType.demand : record?.pm_issue_type === 2 ? workItemType.task :workItemType.bug;
|
||||
let connectIssueStatus = workItemStatus[type];
|
||||
let text = value;
|
||||
text.name = connectIssueStatus[value?.id];
|
||||
return <StatusTag item={ text }></StatusTag>
|
||||
}
|
||||
},{
|
||||
title: '优先级',
|
||||
dataIndex: 'priority',
|
||||
key: 'priority',
|
||||
width: '15%',
|
||||
ellipsis:{
|
||||
showTitle: false
|
||||
},
|
||||
render:(value:any)=>{
|
||||
return <div className={"alignCenter"}>
|
||||
<i style={{display: "inlineBlock", width: 7, height: 7, borderRadius:" 50%",marginRight: 6, background:`${value?.pm_color}`}}></i>
|
||||
{ value?.name }
|
||||
</div>
|
||||
}
|
||||
},{
|
||||
title: '负责人',
|
||||
dataIndex: 'assigners',
|
||||
key: 'assigners',
|
||||
width: '18%',
|
||||
ellipsis:{
|
||||
showTitle: false
|
||||
},
|
||||
render:(value:any)=>{
|
||||
let list = value.length > 0 ? value.map((i:any)=>{return i?.name}):[];
|
||||
// <Avatar shape={"circle"} style={{backgroundColor:"#C1DAFF",marginRight:6}} size={24} src={value?.image_url} alt="" />
|
||||
return list?.length ? list.toString() :"--"
|
||||
}
|
||||
},{
|
||||
title: '时间',
|
||||
dataIndex: 'created_at',
|
||||
key: 'created_at',
|
||||
ellipsis:{
|
||||
showTitle: false
|
||||
},
|
||||
align:"center",
|
||||
render:(value:any)=>{
|
||||
return <span>{toTimeFormat(value)}</span>
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const planColumns:ColumnsType<API.projects.iteration>=[
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'sprintName',
|
||||
key: 'sprintName',
|
||||
ellipsis:{
|
||||
showTitle: false
|
||||
},
|
||||
render:(value:string,record:any)=>{
|
||||
return(
|
||||
<Link to={`/${enterIdentifier}/projects/${record?.pmsProjectId}/iteration/${record?.id}`} className={"font15 fontw400 col0d0Text alignCenter"}><img src={require("@/assets/image/workStand/planTitle.png")} alt="" className="mr20"/><span className="hide">{value}</span></Link>
|
||||
)
|
||||
}
|
||||
},
|
||||
// {
|
||||
// title: '状态',
|
||||
// dataIndex: 'status',
|
||||
// key: 'status',
|
||||
// width: '15%',
|
||||
// ellipsis:{
|
||||
// showTitle: false
|
||||
// },
|
||||
// render:(value:any,record:any)=>{
|
||||
// const item = iterationStatusList.find(e => e.id === +value)
|
||||
// return item ? <StatusTag item={ item }></StatusTag> : ''
|
||||
// }
|
||||
// },
|
||||
{
|
||||
title: '负责人',
|
||||
dataIndex: 'sprintAssignee',
|
||||
key: 'sprintAssignee',
|
||||
width: '13%',
|
||||
ellipsis:{
|
||||
showTitle: false
|
||||
},
|
||||
render:(value:any)=>{
|
||||
return <span><Avatar shape={"circle"}gap={0} style={{backgroundColor:"#fff",marginRight:6}} size={24} src={value?.avatar} alt="" />{value?.nickName}</span>
|
||||
}
|
||||
},{
|
||||
title: '工作进度',
|
||||
dataIndex: 'sprintIssuesStatistics',
|
||||
key: 'sprintIssuesStatistics',
|
||||
width: '25%',
|
||||
ellipsis:{
|
||||
showTitle: false
|
||||
},
|
||||
render:(value:any,record:any)=>{
|
||||
let closeCount = +value?.count_closed;
|
||||
let totalCount = +value?.count_total;
|
||||
return <span className="alignCenter">工作项进度<Progress percent={+(closeCount/totalCount).toFixed(2)*100} style={{marginLeft:10,marginBottom:5}} strokeColor={"#2C75FF"} showInfo={false}/>{closeCount}/{totalCount}</span>
|
||||
}
|
||||
},{
|
||||
title: '工作进度',
|
||||
dataIndex: 'sprintIssuesStatistics',
|
||||
key: 'sprintIssuesStatistics',
|
||||
width: '25%',
|
||||
ellipsis:{
|
||||
showTitle: false
|
||||
},
|
||||
render:(value:any,record:any)=>{
|
||||
let closeCount = +value?.hour_closed;
|
||||
let totalCount = +value?.hour_total;
|
||||
|
||||
return <span className="alignCenter">工时容量<Progress percent={+(closeCount/totalCount).toFixed(2)*100} style={{marginLeft:10,marginBottom:5}} strokeColor={"#00AA82"} showInfo={false}/>{!(closeCount && totalCount) ? 0 :+(+(closeCount||0) / +(totalCount)).toFixed(2)*100}%</span>
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div className={styles.staging}>
|
||||
<div className={`${styles.stagingInfo} ${styles.stagingItem}`}>
|
||||
<div className={`alignCenter ${styles.staginInfoFirst}`}>
|
||||
{/* <Badge dot={true} offset={[-6,6]} color={"#14CA54"}> </Badge>*/}
|
||||
<Avatar shape={"circle"} style={{backgroundColor:"#C1DAFF"}} size={48} src={currentUser?.avatar} />
|
||||
<span className={`ml15 fontw500 col283Text font20`}>{currentUser?.nickName}</span>
|
||||
<span className={`ml20 fontw400 col283Text font16`}>{getCurrentTime()}!</span>
|
||||
</div>
|
||||
<ul className={styles.stagingCard}>
|
||||
<li>
|
||||
<img src={require(`@/assets/image/workStand/task.png`)} alt="" />
|
||||
<div>
|
||||
<span>{statictisData?.projectTaskCount}</span>
|
||||
<span>我负责的任务</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<img src={require(`@/assets/image/workStand/needs.png`)} alt="" />
|
||||
<div>
|
||||
<span>{statictisData?.projectRequirementCount}</span>
|
||||
<span>我负责的需求</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<img src={require(`@/assets/image/workStand/issue.png`)} alt="" />
|
||||
<div>
|
||||
<span>{statictisData?.projectBugCount}</span>
|
||||
<span>我负责的缺陷</span>
|
||||
</div>
|
||||
</li>
|
||||
{
|
||||
statictisData?.productRequirementCount ?
|
||||
<li>
|
||||
<img src={require(`@/assets/image/workStand/productNeeds.png`)} alt="" />
|
||||
<div>
|
||||
<span>{statictisData?.productRequirementCount}</span>
|
||||
<span>我创建的产品需求</span>
|
||||
</div>
|
||||
</li>
|
||||
:""
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
<div className={`${styles.stagingWorkItem} ${styles.stagingItem}`}>
|
||||
<div className={`alignCenter ${styles.titles}`}>
|
||||
<img src={require('@/assets/image/workStand/workitem.png')} width="22px" style={{marginTop:"3px"}} alt="" />
|
||||
<span className="ml5">我的工作项</span>
|
||||
<Input
|
||||
className="search-input ml30"
|
||||
value={ search }
|
||||
onBlur={ (e:any) => { setSearch(e.target.value) } }
|
||||
onChange={ (e:any) => { setSearch(e.target.value) } }
|
||||
suffix={ <i className="iconfont"></i> }
|
||||
placeholder="搜索..."
|
||||
/>
|
||||
<img onClick={()=>{getWorkItem(workPage)}} style={{marginLeft:"auto",cursor:"pointer"}} src={require('@/assets/image/workStand/reset.png')} alt=""/>
|
||||
</div>
|
||||
<Menu mode="horizontal" selectedKeys={[selectKey]} onSelect={(e:any)=>{setSelectKey(e.key)}} className={styles.menusStyle}>
|
||||
<Menu.Item key="assignedme">我负责的<Badge count={assignedmeCount} showZero style={{backgroundColor:"rgba(136, 149, 168, 0.07)",color:"#445A7A",marginLeft:4}}/></Menu.Item>
|
||||
<Menu.Item key="authoredme">我创建的<Badge count={authoredmeCount} showZero style={{backgroundColor:"rgba(136, 149, 168, 0.07)",color:"#445A7A",marginLeft:4}}/></Menu.Item>
|
||||
</Menu>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={dataSource}
|
||||
showHeader={false}
|
||||
rowClassName={styles.rowStyle}
|
||||
loading={workLoading}
|
||||
pagination={{current:workPage,total:workTotal,pageSize:5,showQuickJumper:false,showSizeChanger:false,onChange:(p:number)=>{setWorkPage(p);getWorkItem(p)},hideOnSinglePage:true }}
|
||||
/>
|
||||
</div>
|
||||
<Row justify={"start"}>
|
||||
<Col span={8}>
|
||||
<div className={`${styles.stagingProjects} ${styles.stagingItem}`}>
|
||||
<div className={`alignCenter ${styles.titles}`}>
|
||||
<img src={require('@/assets/image/project/reportChart.png')} width="28px" style={{marginTop:"7px"}} alt="" />
|
||||
<span className="ml3">我的项目</span>
|
||||
<img onClick={()=>{getProjects()}} style={{marginLeft:"auto",cursor:"pointer"}} src={require('@/assets/image/workStand/reset.png')} alt=""/>
|
||||
</div>
|
||||
<Spin spinning={projectLoading}>
|
||||
{
|
||||
projectData?.length > 0 ?
|
||||
<div className={styles.listItems}>
|
||||
{
|
||||
projectData.map((i:any,key:number)=>{
|
||||
return(
|
||||
<div className={styles.listItemCard} key={key}>
|
||||
<div className="alignCenter mb10">
|
||||
<Link to={`/${enterIdentifier}/projects/${i?.id}`} className={`col283Text font16 fontw500 hide`} style={{flex:'1'}}>{i?.projectName}</Link>
|
||||
<span className={styles.cardTagicon}><i className="iconfont icon-xiangmuicon font18"/></span>
|
||||
</div>
|
||||
<p className="mb15"><span className="mr40">工作项 {i?.projectIssuesCount}</span><span>成员 {i?.projectMemberCount}</span></p>
|
||||
<Avatar shape={"circle"} style={{backgroundColor:"#F3F8FF",marginRight:6}} size={20} src={i?.projectAssignee?.avatar} alt="" /><span>{i?.projectAssignee?.nickName}</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
: <NoData />
|
||||
}
|
||||
<div style={{textAlign:"right",paddingBottom:15,paddingTop:12}}>
|
||||
<Pagination current={projectPage} pageSize={4} hideOnSinglePage={true} total={projectTotal} onChange={(p:number)=>{setProjectPage(p)}}/>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={16}>
|
||||
<div className={`${styles.stagingPlan} ${styles.stagingItem} ml25`}>
|
||||
<div className={`alignCenter ${styles.titles}`} style={{marginBottom:0}}>
|
||||
<img src={require('@/assets/image/workStand/plan.png')} width="22px" style={{marginTop:"3px"}} alt="" />
|
||||
<span className="ml5">进行中的迭代</span>
|
||||
<img onClick={()=>{getIteratioins()}} style={{marginLeft:"auto",cursor:"pointer"}} src={require('@/assets/image/workStand/reset.png')} alt=""/>
|
||||
</div>
|
||||
<Table
|
||||
columns={planColumns}
|
||||
dataSource={planData}
|
||||
showHeader={false}
|
||||
rowClassName={styles.rowStyle}
|
||||
loading={planLoading}
|
||||
pagination={{current:planPage,total:planTotal,pageSize:5,showQuickJumper:false,showSizeChanger:false,onChange:(p:number)=>{setPlanPage(p)},hideOnSinglePage:true }}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(({ enterprise , user , workStand }: { enterprise: EnterpriseModelState , user:UsersModelState , workStand:WorkStandModelState }) => ({enterprise,user,workStand}))(Index);
|
Loading…
Reference in New Issue