Commit 5ceeea43 authored by jiangzijing's avatar jiangzijing

feat:项目概览接口初调

parent 398a522b
......@@ -39,6 +39,8 @@ const RESTAPI = {
API_OPERATOR_LIST:`${BACKEND_API_URI_PREFIX}/cpp/workflow/actorspecs`, // 获取算子列表
API_VERSION_OPERATOR:`${BACKEND_API_URI_PREFIX}/cpp/workflow/actorversion`, // 获取指定版本算子
API_SAVE_USERSPEC:`${BACKEND_API_URI_PREFIX}/cpp/workflow/saveuserspec`, // 保存用户自定义工作流模板
API_OVERVIEW_GET:`${BACKEND_API_URI_PREFIX}/cpp/basicInformation`, // 获取概览基本信息
API_TASK_OVERVIEW_LIST:`${BACKEND_API_URI_PREFIX}/cpp/workflowJobInformation`, // 查询任务概览
};
export default RESTAPI;
......@@ -246,6 +246,31 @@ const getworkFlowTaskInfo = (params: { jobId: string; taskId: string }) => {
});
};
//获取概览基本信息
const getOverviewInfo=(params: { id: string })=>{
return request({
url:`${Api.API_OVERVIEW_GET}/${params.id}`,
method:"get",
})
}
//获取任务概览
type getTaskOverviewParams = {
projectId: string;
jobName?: string;
day?: number;
page?: number;
size?: number;
};
const getTaskOverview=(params:getTaskOverviewParams)=>{
return request({
url:Api.API_TASK_OVERVIEW_LIST,
method:"get",
params,
})
}
export {
current,
menu,
......@@ -266,4 +291,6 @@ export {
fetchWorkFlowJob,
submitWorkFlow,
getworkFlowTaskInfo,
getOverviewInfo,
getTaskOverview
};
......@@ -46,16 +46,14 @@
justify-content: center;
width: 78px;
height: 22px;
background: #EBF3FF;
border-radius: 2px;
font-size: 12px;
color: #1370FF;
}
.statusImg {
width: 10px;
height: 10px;
margin-right: 3px;
margin-right: 5px;
}
.taskCreator {
......@@ -91,6 +89,7 @@
flex: 1;
display: flex;
position: relative;
overflow: auto;
}
.noResult {
......@@ -100,4 +99,23 @@
transform: translate(-50%, -50%);
font-size: 14px;
color: #8A9099;
}
.resultBox{
padding: 16px 24px 16px 42px;
width: 100%;
}
.result{
font-size: 12px;
color: #1E2633;
cursor: pointer;
}
.result:hover{
color: #1370FF;
}
.outputLeftImg{
vertical-align:middle;
margin-right: 8px;
}
\ No newline at end of file
import { useMemo, useCallback, useEffect, useState } from "react";
import LinearProgress, { linearProgressClasses } from '@mui/material/LinearProgress';
import MyProgress from "@/components/mui/MyProgress";
import style from "./index.module.css";
import runTime from '../../../../assets/project/runTime.svg'
import jobCost from '../../../../assets/project/jobCost.svg'
import jobCostImg from '../../../../assets/project/jobCost.svg'
import jobSue from '../../../../assets/project/jobSue.svg'
import jobFail from '../../../../assets/project/jobFail.svg'
import jobRun from '../../../../assets/project/jobRun.svg'
......@@ -14,23 +16,131 @@ import onload from '../../../../assets/project/onload.svg'
import fileIcon from "@/assets/project/fileIcon.svg";
import dataSetIcon from "@/assets/project/dataSetIcon.svg";
const TaskCard = () => {
type TaskCardProps = {
name: string;
creator: string;
state: string;
completeNum: number;
totalNum: number;
costTime: string;
jobCost: number;
outputs: Array<any>;
};
const TaskCard = (props: TaskCardProps) => {
const { name, creator, state, completeNum, totalNum, costTime, jobCost, outputs } = props;
const randerOutputs = useMemo(() => {
if (outputs) {
let result = Object.keys(outputs);
let arr = result.map((item: any) => {
let type = "file";
if (outputs[item].indexOf("dataset") !== -1) {
type = "dataset";
}
return {
name: item,
type,
path: outputs[item],
};
});
return arr;
} else {
return [];
}
}, [outputs])
console.log(randerOutputs)
// 渲染状态图标
const renderStatusIcon = (data: string) => {
switch (data) {
case "RUNNING":
return jobRun
case "ABORTED":
return jobCadence
case "FAILED":
return jobFail
case "SUCCEEDED":
return jobSue
default:
return jobCadence
}
}
// 渲染状态
const renderStatusText = (data: string) => {
switch (data) {
case "RUNNING":
return '正在运行'
case "ABORTED":
return '运行终止'
case "FAILED":
return '运行失败'
case "SUCCEEDED":
return '运行成功'
default:
return '未知'
}
}
// 渲染字体颜色
const renderTextColor = (data: string) => {
switch (data) {
case "RUNNING":
return "#1370FF";
case "ABORTED":
return "#C2C6CC";
case "FAILED":
return "#FF4E4E";
case "SUCCEEDED":
return "#0DD09B";
default:
return "#C2C6CC";
}
};
// 渲染状态框背景颜色
const renderBackgroundColor = (data: string) => {
switch (data) {
case "RUNNING":
return "#EBF3FF";
case "ABORTED":
return "#F5F6F7";
case "FAILED":
return "#FFECE8";
case "SUCCEEDED":
return "#E8FFF1";
default:
return "#C2C6CC";
}
};
//渲染进度条颜色
const renderProgressColor = useCallback((data: any) => {
switch (data) {
case "RUNNING":
return "info";
case "ABORTED":
return "disable";
case "FAILED":
return "error";
case "SUCCEEDED":
return "success";
default:
return "disable";
}
}, []);
return <div className={style.cardBox}>
<div className={style.cardLeft}>
<div className={style.topLine}>
<div className={style.taskName}>Docking兼分子动力学模拟</div>
<div className={style.taskStatus}>
<img src={jobRun} alt="" className={style.statusImg} />
<span>正在运行</span>
<div className={style.taskName}>{name}</div>
<div className={style.taskStatus} style={{ color: renderTextColor(state), background: renderBackgroundColor(state) }}>
<img src={renderStatusIcon(state)} alt="" className={style.statusImg} />
<span>{renderStatusText(state)}</span>
</div>
</div>
<div className={style.taskCreator}>jiangzijing</div>
<div className={style.taskCreator}>{creator}</div>
<div className={style.taskProgress}>
<div className={style.progressInfo}>
<div>Progress</div>
<div>8/10</div>
<div style={{ color: renderTextColor(state) }}>{completeNum + "/" + totalNum}</div>
</div>
<LinearProgress variant="determinate" value={80}
{/* <MyProgress color={renderProgressColor(state)} value={(completeNum / totalNum) * 100}/> */}
<LinearProgress variant="determinate" value={(completeNum / totalNum) * 100}
sx={{
borderRadius: '3px',
height: "6px",
......@@ -40,16 +150,30 @@ const TaskCard = () => {
</div>
<div className={style.bottomLine}>
<img alt="" src={runTime} />
<div className={style.bottomInfo}>0小时26分钟</div>
<img alt="" src={jobCost} />
<div className={style.bottomInfo}>200.00</div>
<div className={style.bottomInfo}>{costTime}</div>
<img alt="" src={jobCostImg} />
<div className={style.bottomInfo}>{jobCost?.toFixed(2)}</div>
</div>
</div>
<div className={style.dividingLine}>
<div className={style.arrow}></div>
</div>
<div className={style.cardRight}>
{false?<div></div>:<div className={style.noResult}>暂无结果文件</div>}
{randerOutputs.length === 0 ? <div className={style.noResult}>暂无结果文件</div> :
<div className={style.resultBox}>
{randerOutputs.map((item, index) => {
return <div key={index} className={style.result}>
<img
className={style.outputLeftImg}
src={
item.type === "file" ? fileIcon : dataSetIcon
}
alt=""
/>
{item.name}</div>
})}
</div>
}
</div>
</div>
}
......
......@@ -77,9 +77,28 @@
}
.taskDisplay {
position: relative;
margin: 20px 24px;
overflow: hidden;
background: #F7F8FA;
border-radius: 8px;
min-height: calc(100vh - 275px);
}
.noDataBox{
position: absolute;
top: 50%;
left:50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.noDataText {
margin-top: 8px;
font-size: 14px;
line-height: 22px;
color: #8a9099;
}
\ No newline at end of file
import React, { useState, useCallback, useEffect, useMemo } from "react";
import { observer } from "mobx-react-lite";
import useMyRequest from "@/hooks/useMyRequest";
import {
getOverviewInfo,
getTaskOverview,
} from "@/api/project_api";
import { useStores } from "@/store/index";
import { InputBase, IconButton } from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
import NoProject from "@/components/BusinessComponents/NoProject";
import { observer } from "mobx-react-lite";
import projectImg from "@/assets/project/projectIconSmall.svg";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import TaskCard from './TaskCard'
import noFile from "@/assets/project/noFile.svg";
import style from "./index.module.css";
const ProjectOverview = observer(() => {
const { currentProjectStore } = useStores();
// 概览基本信息
const [overviewInfo, setOverviewInfo] = useState<any>({});
// 任务概览列表
const [taskList, setTaskList] = useState([])
const [jobName, setJobName] = useState('')
const [page, setPage] = useState(0)
const [size, setSize] = useState(10)
// 选择近7天or近15天or近30天
const [activeTab, setActiveTab] = useState("seven");
const [day, setDay] = useState("7");
// 获取概览基本信息
const { run: getOverview } = useMyRequest(getOverviewInfo, {
onSuccess: (result: any) => {
setOverviewInfo(result.data);
},
});
// 获取任务概览
const { run: getTaskOverviewList } = useMyRequest(getTaskOverview, {
onSuccess: (result: any) => {
setTaskList(result.data.content);
},
});
useEffect(() => {
getOverview({
id: currentProjectStore.currentProjectInfo.id as string,
});
}, [currentProjectStore.currentProjectInfo.id, getOverview]);
useEffect(() => {
getTaskOverviewList({
projectId: currentProjectStore.currentProjectInfo.id as string,
jobName: jobName,
day: Number(day),
page: page,
size: size,
});
}, [currentProjectStore.currentProjectInfo.id, getTaskOverviewList, day, jobName]);
// 搜索值改变
const handleJobNameChange = (e: any) => {
if (e.target.value.length > 30) {
return;
}
setJobName(e.target.value);
};
// 按回车搜索
const handleJobNameChangeKeyUp = (e: any) => {
if (e.keyCode === 13) {
}
};
if (currentProjectStore.currentProjectInfo.name) {
return (
<>
......@@ -34,17 +91,17 @@ const ProjectOverview = observer(() => {
<div className={style.basicInformationRight}>
<div>
<div className={style.otherInformationBox}>项目总消费</div>
<div><span className={style.numberDisplay}>1,324</span></div>
<div><span className={style.numberDisplay}>{overviewInfo.projectCost?.toFixed(2)}</span></div>
</div>
<div className={style.verticalLine}></div>
<div>
<div className={style.otherInformationBox}>项目预算</div>
<div><span className={style.numberDisplay}>1,324</span></div>
<div className={style.otherInformationBox}>项目剩余预算</div>
<div><span className={style.numberDisplay}>{overviewInfo.projectRemainingBudget?.toFixed(2)}</span></div>
</div>
<div className={style.verticalLine}></div>
<div>
<div className={style.otherInformationBox}>项目存储大小</div>
<div><span className={style.numberDisplay}>123</span> G</div>
<div><span className={style.numberDisplay}>{overviewInfo.projectStorage?.toFixed(2)}</span> G</div>
</div>
</div>
</div>
......@@ -52,43 +109,59 @@ const ProjectOverview = observer(() => {
<div className={style.searchLineLeft}>
<div className={style.taskOverview}>任务概览</div>
<RadioGroupOfButtonStyle
value={activeTab}
value={day}
radioOptions={[
{ value: "seven", label: "近7天" },
{ value: "fifteen", label: "近15天" },
{ value: "thirty", label: "近30天" },
{ value: "7", label: "近7天" },
{ value: "15", label: "近15天" },
{ value: "30", label: "近30天" },
]}
handleRadio={setActiveTab}
handleRadio={setDay}
></RadioGroupOfButtonStyle>
</div>
<div className={style.projectDataSearch}>
<InputBase
className={style.searchInput}
placeholder="输入关键词搜索"
inputProps={{ "aria-label": "输入关键词搜索" }}
// value={keyWord}
// onChange={handleKeyWordChange}
value={jobName}
onChange={handleJobNameChange}
style={{ width: "280px", fontSize: "14px" }}
// onKeyUp={handleKeyWordChangeKeyUp}
onKeyUp={handleJobNameChangeKeyUp}
/>
<IconButton
type="submit"
className={style.searchButton}
aria-label="search"
size="small"
style={{ padding: "4px" }}
// onClick={handleRefresh}
>
<SearchIcon
className={style.searchIcon}
style={{ color: "#999" }}
/>
</IconButton>
</div>
</div>
<div className={style.taskDisplay}>
<TaskCard />
<TaskCard />
{/* 任务列表为空展示 */}
{taskList.length === 0 && (
<div className={style.noDataBox}>
<img className={style.noDataImg} src={noFile} alt="" />
<span className={style.noDataText}>暂无任务</span>
</div>
)}
{/* 任务列表卡片渲染 */}
{taskList.length > 0 && taskList.map((item: any) => {
return <TaskCard
name={item.name}
creator={item.creator}
state={item.state}
completeNum={item.completeNum}
totalNum={item.totalNum}
costTime={item.costTime}
jobCost={item.jobCost}
outputs={item.outputs}
key={item.id}
/>
})}
</div>
</>
);
......
......@@ -117,7 +117,7 @@ const BaseInfo = observer(() => {
},
{
label: "项目预算:",
value: "100.00",//todo改
value: projectInfo.projectBudget,
},
{
label: "扣费账号:",
......@@ -179,6 +179,13 @@ const BaseInfo = observer(() => {
});
};
const budgetChange = (e: any) => {
// console.log(e.target.value)
}
const budgetBlur = (e: any) => {
// console.log(e.target.value)
}
const { run: updateProjectRun, loading: updateLoading } = useMyRequest(
updateProject,
{
......@@ -327,10 +334,11 @@ const BaseInfo = observer(() => {
<TextField
required
// error={nameCheck.error}
id="name"
id="projectBudget"
variant="outlined"
value="100.00" //todo改
onChange={nameChange}
value={projectInfo.projectBudget}
onChange={budgetChange}
onBlur={budgetBlur}
// helperText={nameCheck.help}
size="small"
sx={{
......@@ -338,7 +346,7 @@ const BaseInfo = observer(() => {
}}
InputProps={{
startAdornment: <InputAdornment position="start">¥</InputAdornment>,
}}
}}
/>
</div>
<div className={style.projectInfoListLi}>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment