ADD file via upload implemented #1

This commit is contained in:
floraachy 2024-10-25 14:43:48 +08:00
parent dbb3624b4d
commit a18594e1c3
1 changed files with 434 additions and 0 deletions

434
index.tsx Normal file
View File

@ -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">&#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);