tesgsdfsgfd/index.tsx

435 lines
17 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

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

import { 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">&#xe6d1;</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);