Commit 8c034058 authored by chenshouchao's avatar chenshouchao

Merge branch 'feat-20220718' into 'release'

Feat 20220718

See merge request !35
parents 0a94454b 55e5598b
.noDataBox {
background-color: #fff;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
}
.noDataText {
margin-top: 8px;
font-size: 14px;
line-height: 22px;
color: #8a9099;
}
import noFile from "@/assets/project/noFile.svg";
import style from "./index.module.css";
type INoDataProps = {
text?: string;
noDataBoxStyle?: any;
};
const NoData = (props: INoDataProps) => {
return (
<div className={style.noDataBox} style={{ ...props.noDataBoxStyle }}>
<img className={style.noDataImg} src={noFile} alt="" />
<span className={style.noDataText}>
{props.text ? props.text : "暂无数据"}
</span>
</div>
);
};
export default NoData;
// 局部loading组件 挂载在目标块下,目标块最少要添加一个position: relative; 或者absolute
import CircularProgress from "@mui/material/CircularProgress";
type IMyCircularProgressProps = {
loading: boolean;
minHeight?: string;
maxHeight?: string;
zIndex?: number;
};
const MyCircularProgress = (props: IMyCircularProgressProps) => {
const {
loading,
minHeight = "none",
maxHeight = "100vh",
zIndex = "100",
} = props;
if (loading) {
return (
<div
style={{
minHeight: minHeight,
width: "100%",
height: "100%",
position: "absolute",
top: 0,
zIndex: zIndex,
}}
>
<div
style={{
width: "100%",
height: "100%",
position: "absolute",
top: 0,
opacity: 0.6,
background: "#fff",
}}
></div>
<div
style={{
width: "100%",
height: "100%",
maxHeight: maxHeight,
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<CircularProgress></CircularProgress>
</div>
</div>
);
} else {
return null;
}
};
export default MyCircularProgress;
......@@ -11,75 +11,75 @@ import Popover, { PopoverProps } from "@mui/material/Popover";
import Typography from "@mui/material/Typography";
interface IProps extends Omit<PopoverProps, "open"> {
/** 触发行为 */
trigger?: "hover" | "click";
/** 触发dom */
children: React.ReactNode;
/** 显示内容 */
content: React.ReactNode;
/** 触发行为 */
trigger?: "hover" | "click";
/** 触发dom */
children: React.ReactNode;
/** 显示内容 */
content: React.ReactNode;
}
const MyPopover = (props: IProps) => {
const [anchorEl, setAnchorEl] = React.useState<any | null>(null);
const [anchorEl, setAnchorEl] = React.useState<any | null>(null);
const {
trigger = "click",
children,
content,
anchorOrigin,
transformOrigin,
} = props;
const {
trigger = "click",
children,
content,
anchorOrigin,
transformOrigin,
} = props;
const handlePopoverOpen = (event: any) => {
setAnchorEl(event.currentTarget);
};
const handlePopoverOpen = (event: any) => {
setAnchorEl(event.currentTarget);
};
const handelClick = (event: any) => {
setAnchorEl(event?.currentTarget);
};
const handelClick = (event: any) => {
setAnchorEl(event?.currentTarget);
};
const handlePopoverClose = () => {
setAnchorEl(null);
};
const handlePopoverClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const id = open ? "simple-popover" : undefined;
const open = Boolean(anchorEl);
const id = open ? "simple-popover" : undefined;
return (
<div>
<Typography
aria-owns={id}
onClick={trigger === "click" ? handelClick : undefined}
onMouseEnter={trigger === "hover" ? handlePopoverOpen : undefined}
onMouseLeave={trigger === "hover" ? handlePopoverClose : undefined}
>
{children}
</Typography>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handlePopoverClose}
sx={{
pointerEvents: trigger === "hover" ? "none" : undefined,
}}
anchorOrigin={
anchorOrigin || {
vertical: "bottom",
horizontal: "center",
}
}
transformOrigin={
transformOrigin || {
vertical: "top",
horizontal: "center",
}
}
>
<Typography sx={{ p: 1 }}>{content}</Typography>
</Popover>
</div>
);
return (
<div>
<Typography
aria-owns={id}
onClick={trigger === "click" ? handelClick : undefined}
onMouseEnter={trigger === "hover" ? handlePopoverOpen : undefined}
onMouseLeave={trigger === "hover" ? handlePopoverClose : undefined}
>
{children}
</Typography>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handlePopoverClose}
sx={{
pointerEvents: trigger === "hover" ? "none" : undefined,
}}
anchorOrigin={
anchorOrigin || {
vertical: "bottom",
horizontal: "center",
}
}
transformOrigin={
transformOrigin || {
vertical: "top",
horizontal: "center",
}
}
>
<Typography sx={{ p: 1 }}>{content}</Typography>
</Popover>
</div>
);
};
export default MyPopover;
......@@ -17,6 +17,7 @@ import { useStores } from "@/store";
import { toJS } from "mobx";
import classNames from "classnames";
import Save from "./save";
import NoData from "@/components/BusinessComponents/NoData";
import Download from "./download";
import style from "./index.module.css";
......@@ -62,7 +63,9 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
setSort(e);
};
const handleKeywordChange = (e: any) => {
setKeyword(e.target.value);
if (e.target.value.length <= 30) {
setKeyword(e.target.value);
}
};
const pageChange = (value: number) => {
......@@ -248,102 +251,117 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
</div>
</div>
<div className={style.table}>
<div className={style.list}>
{list.map((item, index) => {
return (
<div
className={style.datasetLi}
key={item.id}
onClick={() => {
handleSelectItem(item.id);
}}
>
{isCadd && (
<div className={style.datasetLiTop}>
{list.length !== 0 && (
<>
<div className={style.list}>
{list.map((item, index) => {
return (
<div
className={style.datasetLi}
key={item.id}
onClick={() => {
handleSelectItem(item.id);
}}
>
{isCadd && (
<div className={style.datasetLiTop}>
{graphicDimension === "2D" && (
<KekuleView id={`${index}2d`} smi={item.smiles} />
)}
{graphicDimension === "3D" && (
<NglView id={`${index}3d`} content={item.pdb} />
)}
</div>
)}
<div className={style.datasetLiBottom}>
<div
className={style.datasetLiTitle}
title={item.smiles}
>
{item.smiles}
</div>
{showData.length !== 0 && (
<div className={style.datasetLiDataList}>
{Object.keys(item.meta)
.filter((key) => showData.indexOf(key) !== -1)
.map((key, index) => {
return (
<div
className={style.datasetLiDataLi}
key={index}
>
<span className={style.datasetLiDataLiKey}>
{key}
</span>
<span
className={style.datasetLiDataLiValue}
>
{item.meta[key]}
</span>
</div>
);
})}
</div>
)}
{showData.length === 0 && (
<div className={style.noDataList}>请选择显示数据</div>
)}
</div>
{graphicDimension === "2D" && (
<KekuleView id={`${index}2d`} smi={item.smiles} />
<Checkbox
size="small"
sx={{
padding: "0px",
position: "absolute",
top: "16px",
right: "20px",
zIndex: 1,
}}
checked={selectItems.includes(item.id)}
/>
)}
{graphicDimension === "3D" && (
<NglView id={`${index}3d`} content={item.pdb} />
<Checkbox
size="small"
sx={{
padding: "0px",
position: "absolute",
top: "16px",
right: "20px",
zIndex: 1,
background: "RGBA(30, 38, 51, 1)",
border: "1px solid #565C66",
borderRadius: "2px",
}}
checked={selectItems.includes(item.id)}
/>
)}
</div>
)}
<div className={style.datasetLiBottom}>
<div className={style.datasetLiTitle} title={item.smiles}>
{item.smiles}
</div>
{showData.length !== 0 && (
<div className={style.datasetLiDataList}>
{Object.keys(item.meta)
.filter((key) => showData.indexOf(key) !== -1)
.map((key, index) => {
return (
<div
className={style.datasetLiDataLi}
key={index}
>
<span className={style.datasetLiDataLiKey}>
{key}
</span>
<span className={style.datasetLiDataLiValue}>
{item.meta[key]}
</span>
</div>
);
})}
</div>
)}
{showData.length === 0 && (
<div className={style.noDataList}>请选择显示数据</div>
)}
</div>
{graphicDimension === "2D" && (
<Checkbox
size="small"
sx={{
padding: "0px",
position: "absolute",
top: "16px",
right: "20px",
zIndex: 1,
}}
checked={selectItems.includes(item.id)}
/>
)}
{graphicDimension === "3D" && (
<Checkbox
size="small"
sx={{
padding: "0px",
position: "absolute",
top: "16px",
right: "20px",
zIndex: 1,
background: "RGBA(30, 38, 51, 1)",
border: "1px solid #565C66",
borderRadius: "2px",
}}
checked={selectItems.includes(item.id)}
/>
)}
</div>
);
})}
{nullBox.map((item, index) => {
return (
<div
className={classNames({
[style.datasetLi]: true,
[style.nullBox]: true,
})}
key={index + "null"}
></div>
);
})}
</div>
<div className={style.pagination}>
<MyPagination page={page} pageChange={pageChange} count={count} />
</div>
);
})}
{nullBox.map((item, index) => {
return (
<div
className={classNames({
[style.datasetLi]: true,
[style.nullBox]: true,
})}
key={index + "null"}
></div>
);
})}
</div>
<div className={style.pagination}>
<MyPagination
page={page}
pageChange={pageChange}
count={count}
/>
</div>
</>
)}
{list.length === 0 && <NoData></NoData>}
</div>
</div>
<div className={style.foot}>
......
......@@ -12,6 +12,9 @@
font-weight: 600;
margin-bottom: 24px;
}
.projectDataHeader {
position: relative;
}
.projectDataButtonAndSearch {
display: flex;
justify-content: space-between;
......
......@@ -2,7 +2,6 @@ import React, { useState, useCallback, useEffect, useMemo } from "react";
import style from "./index.module.css";
import classnames from "classnames";
import { IconButton } from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
import RefreshIcon from "@mui/icons-material/Refresh";
import MyTable from "@/components/mui/MyTable";
import dataSetIcon from "@/assets/project/dataSetIcon.svg";
......@@ -26,7 +25,6 @@ import { useLocation } from "react-router-dom";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import SeeDataset from "./SeeDataset";
import { getDataFind, getDataFileSearch } from "@/api/project_api";
import MyInput from "@/components/mui/MyInput";
import MyButton from "@/components/mui/MyButton";
import SearchInput from "@/components/BusinessComponents/SearchInput";
......@@ -491,10 +489,10 @@ const ProjectData = observer(() => {
{index === 0
? "ProjectData"
: index > pathArr.length - 4
? item
: ""}
? item
: ""}
{index === pathArr.length - 1 ||
(index <= pathArr.length - 4 && index > 0) ? null : (
(index <= pathArr.length - 4 && index > 0) ? null : (
<i className={style.showPathI}>{">"}</i>
)}
{index === 1 && "..."}
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-07-26 20:39:32
* @LastEditTime: 2022-07-28 18:32:03
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -318,7 +318,8 @@ const BaseInfo = observer(() => {
>
项目名称
</div>
<TextField
<MyInput
required
error={nameCheck.error}
id="name"
......@@ -326,21 +327,8 @@ const BaseInfo = observer(() => {
value={projectInfo.name}
onChange={nameChange}
helperText={nameCheck.help}
size="small"
sx={{
width: "560px",
"& .MuiOutlinedInput-root": {
height: "36px",
},
}}
style={{ width: "560px" }}
/>
{/* <input
value={projectInfo.name}
className={style.projectInfoListLiValue}
onChange={nameChange}
maxLength={30}
placeholder="请输入项目名称"
></input> */}
</div>
<div className={style.projectInfoListLi}>
<div className={style.projectInfoListLiLabel}>项目描述</div>
......@@ -354,6 +342,13 @@ const BaseInfo = observer(() => {
placeholder="项目描述限制100字以内"
maxLength={100}
></textarea>
{/* <MyInput
value={projectInfo.desc}
multiline
rows={4}
placeholder="项目描述限制100字以内"
onChange={descChange}
/> */}
</div>
<div className={style.projectInfoListLi}>
<div className={style.projectInfoListLiLabel}>计算区</div>
......@@ -375,42 +370,26 @@ const BaseInfo = observer(() => {
</div>
<div className={style.projectInfoListLi}>
<div className={style.projectInfoListLiLabel}>创建人</div>
<input
<MyInput
value={projectInfo.owner}
disabled
className={classnames({
[style.projectInfoListLiValue]: true,
[style.disable]: true,
})}
></input>
style={{ width: "560px" }}
/>
</div>
<div className={style.projectInfoListLi}>
<div className={style.projectInfoListLiLabel}>项目预算</div>
{/* <MyInput
sx={{
width: "560px",
'& .MuiOutlinedInput-root': {
height: '36px'
}
}}
/> */}
<TextField
<MyInput
required
error={budgetCheck.error}
disabled={currentUserName !== projectInfo.tenantUser}
id="projectBudget"
// id="projectBudget"
variant="outlined"
value={projectInfo.projectBudget}
onChange={budgetChange}
onBlur={budgetBlur}
helperText={budgetCheck.help}
size="small"
sx={{
width: "560px",
"& .MuiOutlinedInput-root": {
height: "36px",
},
}}
// size="small"
style={{ width: "560px" }}
InputProps={{
startAdornment: (
<InputAdornment position="start">¥</InputAdornment>
......@@ -420,14 +399,11 @@ const BaseInfo = observer(() => {
</div>
<div className={style.projectInfoListLi}>
<div className={style.projectInfoListLiLabel}>扣费账号</div>
<input
<MyInput
value={projectInfo.tenantUser}
disabled
className={classnames({
[style.projectInfoListLiValue]: true,
[style.disable]: true,
})}
></input>
style={{ width: "560px" }}
/>
</div>
<div className={style.projectInfoListLi}>
<LoadingButton
......
......@@ -2,23 +2,24 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-07-26 11:13:10
* @LastEditTime: 2022-07-28 18:10:42
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { toJS } from "mobx";
import { observer } from "mobx-react-lite";
import _ from "lodash";
import Dialog from "@/components/mui/MyDialog";
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import { Box, OutlinedInput } from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
import Dialog from "@/components/mui/MyDialog";
import { IResponse, useHttp } from "@/api/http";
import { useStores } from "@/store";
import { useMessage } from "@/components/MySnackbar";
import MySelect, { IOption } from "@/components/mui/MySelect";
import MyTable from "@/components/mui/MyTable";
import SearchInput from "@/components/BusinessComponents/SearchInput";
interface IProps {
setAddMemberDialog: (val: boolean) => void;
addMemberDialog: boolean;
......@@ -158,19 +159,15 @@ const AddMember = observer((props: IProps) => {
title="添加成员"
>
<Box>
<Box sx={{ mb: 2 }}>
<OutlinedInput
onChange={(e: any) => {
_.debounce(() => {
setProjectMember(e.target.value);
}, 200)();
}}
placeholder="搜索项目成员"
size="small"
sx={{ width: "100%", height: 32 }}
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/>
</Box>
<SearchInput
onKeyUp={(e: any) => {
if (e.keyCode === 13) {
setProjectMember(e.target.value);
}
}}
placeholder="搜索项目成员"
sx={{ mb: 2 }}
/>
<div style={{ overflowY: "scroll", maxHeight: 400 }}>
<MyTable
checkboxData={(val: string[]) => setCheckData(val)}
......
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-22 16:20:26
* @LastEditors: 吴永生 15770852798@163.com
* @LastEditTime: 2022-07-28 19:02:19
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -11,29 +11,27 @@ import _ from "lodash";
import { useNavigate } from "react-router-dom";
import { Box, Typography } from "@mui/material";
import OutlinedInput from "@mui/material/OutlinedInput";
import SearchIcon from "@mui/icons-material/Search";
import { TablePagination } from '@mui/material';
import TextField from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem';
import { TablePagination } from "@mui/material";
import SimpleDialog from "./components/simpleDialog"
import MySelect from "@/components/mui/MySelect";
import SimpleDialog from "./components/simpleDialog";
import { useStores } from "@/store";
import useMyRequest from "@/hooks/useMyRequest";
import ActionsComponent from "../../../../components/Material.Ui/Table/ActionsComponent"
import runTime from '../../../../assets/project/runTime.svg'
import jobCost 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'
import jobCadence from '../../../../assets/project/jobCadence.svg'
import jobStop from '../../../../assets/project/jobStop.svg'
import jobDel from '../../../../assets/project/jobDel.svg'
import noData from '../../../../assets/project/noTemplate.svg'
import onload from '../../../../assets/project/onload.svg'
import ActionsComponent from "../../../../components/Material.Ui/Table/ActionsComponent";
import runTime from "../../../../assets/project/runTime.svg";
import jobCost 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";
import jobCadence from "../../../../assets/project/jobCadence.svg";
import jobStop from "../../../../assets/project/jobStop.svg";
import jobDel from "../../../../assets/project/jobDel.svg";
import noData from "../../../../assets/project/noTemplate.svg";
import onload from "../../../../assets/project/onload.svg";
import {
getWorkflowJobList,
deleteWorkflowJob,
cancelWorkflowJob
getWorkflowJobList,
deleteWorkflowJob,
cancelWorkflowJob,
} from "@/api/workbench_api";
import { toJS } from "mobx";
import { observer } from "mobx-react-lite";
......@@ -43,262 +41,252 @@ import SearchInput from "@/components/BusinessComponents/SearchInput";
import styles from "./index.module.css";
const currencies = [
{
value: 'ALL',
label: '全部',
},
{
value: 'RUNNING',
label: '正在运行',
},
{
value: 'SUCCEEDED',
label: '运行成功',
},
{
value: 'FAILED',
label: '运行失败',
},
{
value: 'ABORTED',
label: '运行终止',
},
{
value: "ALL",
label: "全部",
},
{
value: "RUNNING",
label: "正在运行",
},
{
value: "SUCCEEDED",
label: "运行成功",
},
{
value: "FAILED",
label: "运行失败",
},
{
value: "ABORTED",
label: "运行终止",
},
];
let timer: string | number | NodeJS.Timeout | null | undefined = null
let timer: string | number | NodeJS.Timeout | null | undefined = null;
const ProjectMembers = observer(() => {
const { currentProjectStore } = useStores();
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const isPass = usePass();
const [jobName, setJobName] = useState('')
const [jobList, setJobList] = useState([])
const [currency, setCurrency] = useState('ALL');
const [page, setPage] = useState(0)
const [size, setSize] = useState(10)
const [rowsPerPage, setRowsPerPage] = useState(10)
const [count, setCount] = useState(0)
/** 简单弹窗 */
const [jobData, setJobData] = useState('');
const [openDialog, setOpenDialog] = useState(false);
const [dialogType, setDialogType] = useState('del');
// 获取作业列表
const { run: getWorkflowJobInfo } = useMyRequest(getWorkflowJobList, {
onSuccess: (result: any) => {
setJobList(result.data.content);
setCount(result.data.totalElements)
timer && clearTimeout(timer as number)
timer = null;
timer = setTimeout(() => {
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === 'ALL' ? "" : currency
});
}, 60000);
},
});
useEffect(() => {
return () => {
clearTimeout(timer as number)
}
}, [])
const navigate = useNavigate()
// 删除作业
const { run: delWorkflowJob } = useMyRequest(deleteWorkflowJob, {
onSuccess: (result: any) => {
setOpenDialog(false)
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === 'ALL' ? "" : currency
});
},
});
// 删除作业
const { run: cancelWorkflowJobInfo } = useMyRequest(cancelWorkflowJob, {
onSuccess: (result: any) => {
setOpenDialog(false)
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === 'ALL' ? "" : currency
});
},
});
const searchChange = (data: any) => {
setJobName(data.length > 30 ? data.slice(0, 30) : data);
}
const handleChange = (event: any) => {
setCurrency(event.target.value);
};
/** 关闭弹窗 */
const closeDialog = () => {
setOpenDialog(false);
};
/** 弹窗确认 */
const onConfirm = () => {
if (dialogType === "del") {
delWorkflowJob({
id: jobData
})
} else {
cancelWorkflowJobInfo({
jobid: jobData
})
}
};
useEffect(() => {
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === 'ALL' ? "" : currency
});
}, [projectId, getWorkflowJobInfo]);
const handleChangePage = (event: any, newPage: any) => {
setPage(newPage)
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: newPage,
size: size,
name: jobName,
state: currency === 'ALL' ? "" : currency
});
}
const handleChangeRowsPerPage = (event: any) => {
setRowsPerPage(event.target.value)
setSize(event.target.value)
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: event.target.value,
name: jobName,
state: currency === 'ALL' ? "" : currency
});
}
useEffect(() => {
setTimeout(() => {
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === 'ALL' ? "" : currency
});
}, 300)
}, [jobName, currency]);
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: any) => {
switch (data) {
case "RUNNING":
return "#1370FF";
case "ABORTED":
return "#C2C6CC";
case "FAILED":
return "#FF4E4E";
case "SUCCEEDED":
return "#0DD09B";
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";
}
}, []);
/** 点击每一行 */
const rowClick = useCallback(
(id: string) => {
navigate(`/product/cadd/projectJobDetail`, {
state: { taskId: id },
});
},
[navigate],
);
// 回车搜索
const handleKeyWordChangeKeyUp = (e: any) => {
if (e.keyCode === 13) {
setJobName(e.target.value);
}
}
return (
<Box className={styles.headerBox}>
<Box className={styles.tabHeader}>
<Box sx={{ display: 'flex' }}>
<SearchInput
onKeyUp={handleKeyWordChangeKeyUp}
sx={{ width: 340 }}
/>
<Box className={styles.tabHeaderSelect}>
const { currentProjectStore } = useStores();
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const isPass = usePass();
const [jobName, setJobName] = useState("");
const [jobList, setJobList] = useState([]);
const [currency, setCurrency] = useState("ALL");
const [page, setPage] = useState(0);
const [size, setSize] = useState(10);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [count, setCount] = useState(0);
/** 简单弹窗 */
const [jobData, setJobData] = useState("");
const [openDialog, setOpenDialog] = useState(false);
const [dialogType, setDialogType] = useState("del");
// 获取作业列表
const { run: getWorkflowJobInfo } = useMyRequest(getWorkflowJobList, {
onSuccess: (result: any) => {
setJobList(result.data.content);
setCount(result.data.totalElements);
timer && clearTimeout(timer as number);
timer = null;
timer = setTimeout(() => {
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === "ALL" ? "" : currency,
});
}, 60000);
},
});
useEffect(() => {
return () => {
clearTimeout(timer as number);
};
}, []);
const navigate = useNavigate();
// 删除作业
const { run: delWorkflowJob } = useMyRequest(deleteWorkflowJob, {
onSuccess: (result: any) => {
setOpenDialog(false);
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === "ALL" ? "" : currency,
});
},
});
// 删除作业
const { run: cancelWorkflowJobInfo } = useMyRequest(cancelWorkflowJob, {
onSuccess: (result: any) => {
setOpenDialog(false);
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === "ALL" ? "" : currency,
});
},
});
const handleChange = (val: string) => {
setCurrency(val);
};
/** 关闭弹窗 */
const closeDialog = () => {
setOpenDialog(false);
};
/** 弹窗确认 */
const onConfirm = () => {
if (dialogType === "del") {
delWorkflowJob({
id: jobData,
});
} else {
cancelWorkflowJobInfo({
jobid: jobData,
});
}
};
useEffect(() => {
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === "ALL" ? "" : currency,
});
}, [projectId, getWorkflowJobInfo]);
const handleChangePage = (event: any, newPage: any) => {
setPage(newPage);
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: newPage,
size: size,
name: jobName,
state: currency === "ALL" ? "" : currency,
});
};
const handleChangeRowsPerPage = (event: any) => {
setRowsPerPage(event.target.value);
setSize(event.target.value);
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: event.target.value,
name: jobName,
state: currency === "ALL" ? "" : currency,
});
};
useEffect(() => {
setTimeout(() => {
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === "ALL" ? "" : currency,
});
}, 300);
}, [jobName, currency]);
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: any) => {
switch (data) {
case "RUNNING":
return "#1370FF";
case "ABORTED":
return "#C2C6CC";
case "FAILED":
return "#FF4E4E";
case "SUCCEEDED":
return "#0DD09B";
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";
}
}, []);
/** 点击每一行 */
const rowClick = useCallback(
(id: string) => {
navigate(`/product/cadd/projectJobDetail`, {
state: { taskId: id },
});
},
[navigate]
);
// 回车搜索
const handleKeyWordChangeKeyUp = (e: any) => {
if (e.keyCode === 13) {
setJobName(e.target.value);
}
};
return (
<Box className={styles.headerBox}>
<Box className={styles.tabHeader}>
<Box sx={{ display: "flex" }}>
<SearchInput onKeyUp={handleKeyWordChangeKeyUp} sx={{ width: 340 }} />
{/* <Box className={styles.tabHeaderSelect}>
<TextField
select
label="运行状态"
......@@ -319,131 +307,183 @@ const ProjectMembers = observer(() => {
}}
>
{currencies.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
</Box>
</Box>
<Box className={styles.tabUpdate} onClick={() => {
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === 'ALL' ? "" : currency
})
}} >
<img alt="" src={onload} />
</Box>
</Box>
<Box className={styles.body}>
{
jobList.length === 0 &&
<Box sx={{
display: 'flex', alignItems: 'center', flexDirection: 'column', minHeight: 'calc(100vh - 376px)',
justifyContent: 'center'
}}>
<img alt="" src={noData} />
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#8A9099' }}>暂无任务</Typography>
</Box>
}
{
jobList.length > 0 && jobList.map((item: any, key) => {
return (
<Box className={styles.tabBox} onClick={() => rowClick(item.id)}>
<Box className={styles.tabBoxInfo}>
<div className={styles.tabBoxTitle}>{item.name}</div>
<Box className={styles.tabBoxDescInfo}>
<div className={styles.tabBoxDesc} style={{ marginRight: "24px" }} >创建时间:{item.createTime}</div>
<div className={styles.tabBoxDesc}>创建人:{item.creator}</div>
</Box>
</Box>
<Box className={styles.tabBoxMiddle}>
<img alt="" src={runTime} />
<div className={styles.tabBoxTime}>{item.costTime}</div>
</Box>
<Box className={styles.tabBoxMiddle}>
<img alt="" src={jobCost} />
<div className={styles.tabBoxTime}>{item.jobCost}</div>
</Box>
<Box className={styles.tabBoxJobStatus}>
<img alt="" src={renderStatusIcon(item.state)} />
<div className={styles.tabBoxStatusText}>{renderStatusText(item.state)}</div>
<Box sx={{ width: '100%' }}>
<MyProgress color={renderProgressColor(item.state)} value={(item.completeNum / item.totalNum) * 100}
sx={{
marginRight: '16px',
}}
/>
</Box>
<div style={{ color: renderTextColor(item.state) }} className={styles.tabBoxStatusText}>{item.completeNum + "/" + item.totalNum}</div>
</Box>
{
item.state === "RUNNING" && isPass("PROJECT_WORKBENCH_JOBS_STOP", 'USER') && <Box className={styles.tabBoxJobOperate}>
<img alt=""
src={jobStop}
style={{ cursor: "pointer" }}
onClick={(event) => {
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
setJobData(item.id)
setOpenDialog(true)
setDialogType('stop')
}}
/>
</Box>
}
{
item.state !== "RUNNING" && isPass("PROJECT_WORKBENCH_JOBS_DELETE", 'MANAGER') && <Box className={styles.tabBoxJobOperate}>
<img alt=""
src={jobDel}
style={{ cursor: "pointer" }}
onClick={(event) => {
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
setJobData(item.id)
setOpenDialog(true)
setDialogType('del')
}}
/>
</Box>
}
</Box>
)
})
}
</Box>
<TablePagination
rowsPerPageOptions={[5, 10, 20, 50]}
labelRowsPerPage={'每页行数:'}
ActionsComponent={ActionsComponent}
component="div"
count={count || jobList.length}
rowsPerPage={rowsPerPage || 10}
page={page}
onPageChange={handleChangePage}//
onRowsPerPageChange={handleChangeRowsPerPage}//
/>
<SimpleDialog
text={dialogType === "del" ? '任务被删除后将无法恢复,确认继续吗?' : '正在运行的任务终止后将无法重新运行,确认继续吗?'}
title={dialogType === "del" ? '删除任务' : '终止任务'}
openDialog={openDialog}
closeDialog={closeDialog}
onConfirm={onConfirm}
/>
</Box >
);
</Box> */}
<Box className={styles.tabHeaderSelect}>
<MySelect
input={<OutlinedInput />}
value={currency}
onChange={handleChange}
options={currencies}
size="small"
sx={{
width: 180,
height: 32,
"& .MuiOutlinedInput-root": {
height: "32px",
color: "#1E2633",
fontSize: "14px",
},
"& .MuiInputLabel-root": {
color: "#8A9099",
fontSize: "14px",
},
}}
/>
</Box>
</Box>
<Box
className={styles.tabUpdate}
onClick={() => {
getWorkflowJobInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
page: page,
size: size,
name: jobName,
state: currency === "ALL" ? "" : currency,
});
}}
>
<img alt="" src={onload} />
</Box>
</Box>
<Box className={styles.body}>
{jobList.length === 0 && (
<Box
sx={{
display: "flex",
alignItems: "center",
flexDirection: "column",
minHeight: "calc(100vh - 376px)",
justifyContent: "center",
}}
>
<img alt="" src={noData} />
<Typography
sx={{ fontSize: "12px", fontWeight: "400", color: "#8A9099" }}
>
暂无任务
</Typography>
</Box>
)}
{jobList.length > 0 &&
jobList.map((item: any, key) => {
return (
<Box className={styles.tabBox} onClick={() => rowClick(item.id)}>
<Box className={styles.tabBoxInfo}>
<div className={styles.tabBoxTitle}>{item.name}</div>
<Box className={styles.tabBoxDescInfo}>
<div
className={styles.tabBoxDesc}
style={{ marginRight: "24px" }}
>
创建时间:{item.createTime}
</div>
<div className={styles.tabBoxDesc}>
创建人:{item.creator}
</div>
</Box>
</Box>
<Box className={styles.tabBoxMiddle}>
<img alt="" src={runTime} />
<div className={styles.tabBoxTime}>{item.costTime}</div>
</Box>
<Box className={styles.tabBoxMiddle}>
<img alt="" src={jobCost} />
<div className={styles.tabBoxTime}>{item.jobCost}</div>
</Box>
<Box className={styles.tabBoxJobStatus}>
<img alt="" src={renderStatusIcon(item.state)} />
<div className={styles.tabBoxStatusText}>
{renderStatusText(item.state)}
</div>
<Box sx={{ width: "100%" }}>
<MyProgress
color={renderProgressColor(item.state)}
value={(item.completeNum / item.totalNum) * 100}
sx={{
marginRight: "16px",
}}
/>
</Box>
<div
style={{ color: renderTextColor(item.state) }}
className={styles.tabBoxStatusText}
>
{item.completeNum + "/" + item.totalNum}
</div>
</Box>
{item.state === "RUNNING" &&
isPass("PROJECT_WORKBENCH_JOBS_STOP", "USER") && (
<Box className={styles.tabBoxJobOperate}>
<img
alt=""
src={jobStop}
style={{ cursor: "pointer" }}
onClick={(event) => {
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
setJobData(item.id);
setOpenDialog(true);
setDialogType("stop");
}}
/>
</Box>
)}
{item.state !== "RUNNING" &&
isPass("PROJECT_WORKBENCH_JOBS_DELETE", "MANAGER") && (
<Box className={styles.tabBoxJobOperate}>
<img
alt=""
src={jobDel}
style={{ cursor: "pointer" }}
onClick={(event) => {
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
setJobData(item.id);
setOpenDialog(true);
setDialogType("del");
}}
/>
</Box>
)}
</Box>
);
})}
</Box>
<TablePagination
rowsPerPageOptions={[5, 10, 20, 50]}
labelRowsPerPage={"每页行数:"}
ActionsComponent={ActionsComponent}
component="div"
count={count || jobList.length}
rowsPerPage={rowsPerPage || 10}
page={page}
onPageChange={handleChangePage} //
onRowsPerPageChange={handleChangeRowsPerPage} //
/>
<SimpleDialog
text={
dialogType === "del"
? "任务被删除后将无法恢复,确认继续吗?"
: "正在运行的任务终止后将无法重新运行,确认继续吗?"
}
title={dialogType === "del" ? "删除任务" : "终止任务"}
openDialog={openDialog}
closeDialog={closeDialog}
onConfirm={onConfirm}
/>
</Box>
);
});
export default memo(ProjectMembers);
import style from "./index.module.css";
import { MenuItem } from "@mui/material";
import React, { useState, useEffect } from "react";
import MyInput from "@/components/mui/MyInput";
import MyDialog from "@/components/mui/MyDialog";
import React, { useState, useEffect } from "react";
import useMyRequest from "@/hooks/useMyRequest";
import { hpczone, addProject } from "@/api/project_api";
import { useMessage } from "@/components/MySnackbar";
......@@ -14,6 +14,8 @@ import {
getFiletokenAccordingToId,
} from "@/views/Project/project";
import style from "./index.module.css";
type zoneIdOption = {
id: string;
name: string;
......
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