Commit 50746e14 authored by wuyongsheng's avatar wuyongsheng

Merge branch 'master' into 'staging'

Master

See merge request !128
parents 453a73cf 181bec6a
<?xml version="1.0" encoding="UTF-8"?>
<svg width="15px" height="15px" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>矩形备份 7</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="矩形备份-7" stroke="#565C66" fill="#1E2633" x="0.5" y="0.5" width="14" height="14" rx="2"></rect>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="15px" height="15px" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 64</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-64">
<rect id="矩形备份-28" fill="#1370FF" x="0" y="0" width="15" height="15" rx="2"></rect>
<polyline id="路径-26" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" points="3.5 7.83740166 6.77434245 10.5 11.5 4.5"></polyline>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="15px" height="15px" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>矩形备份 22</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="矩形备份-22" stroke="#565C66" fill="#000000" x="0.5" y="0.5" width="14" height="14" rx="2"></rect>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 58备份 7</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-58备份-7">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-50" transform="translate(1.000000, 1.605109)" stroke="#C2C6CC" stroke-width="1.5">
<line x1="0" y1="2.39431484" x2="14" y2="2.39431484" id="路径-16"></line>
<path d="M3.37934347,2.39431484 L3.37934347,1 C3.37934347,0.44771525 3.82705872,1.01453063e-16 4.37934347,0 L9.63329305,0 C10.1855778,-1.01453063e-16 10.6332931,0.44771525 10.6332931,1 L10.6332931,2.39431484 L10.6332931,2.39431484" id="路径-17"></path>
<path d="M2.45321216,3.89402686 L2.45321216,11.9292428 C2.45321216,12.4815275 2.90092741,12.9292428 3.45321216,12.9292428 L10.4872657,12.9292428 C11.0395505,12.9292428 11.4872657,12.4815275 11.4872657,11.9292428 L11.4872657,3.89402686 L11.4872657,3.89402686" id="路径-20"></path>
<line x1="5.49894415" y1="3.89402686" x2="5.49894415" y2="10.3954667" id="路径-21"></line>
<line x1="8.49836822" y1="3.89402686" x2="8.49836822" y2="10.3954667" id="路径-22"></line>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 58备份</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-58备份">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-50" transform="translate(1.000000, 1.605109)" stroke="#DDE1E6" stroke-width="1.5">
<line x1="0" y1="2.39431484" x2="14" y2="2.39431484" id="路径-16"></line>
<path d="M3.37934347,2.39431484 L3.37934347,1 C3.37934347,0.44771525 3.82705872,1.01453063e-16 4.37934347,0 L9.63329305,0 C10.1855778,-1.01453063e-16 10.6332931,0.44771525 10.6332931,1 L10.6332931,2.39431484 L10.6332931,2.39431484" id="路径-17"></path>
<path d="M2.45321216,3.89402686 L2.45321216,11.9292428 C2.45321216,12.4815275 2.90092741,12.9292428 3.45321216,12.9292428 L10.4872657,12.9292428 C11.0395505,12.9292428 11.4872657,12.4815275 11.4872657,11.9292428 L11.4872657,3.89402686 L11.4872657,3.89402686" id="路径-20"></path>
<line x1="5.49894415" y1="3.89402686" x2="5.49894415" y2="10.3954667" id="路径-21"></line>
<line x1="8.49836822" y1="3.89402686" x2="8.49836822" y2="10.3954667" id="路径-22"></line>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 58备份 7</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-58备份-7">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-50" transform="translate(1.000000, 1.605109)" stroke="#565C66" stroke-width="1.5">
<line x1="0" y1="2.39431484" x2="14" y2="2.39431484" id="路径-16"></line>
<path d="M3.37934347,2.39431484 L3.37934347,1 C3.37934347,0.44771525 3.82705872,1.01453063e-16 4.37934347,0 L9.63329305,0 C10.1855778,-1.01453063e-16 10.6332931,0.44771525 10.6332931,1 L10.6332931,2.39431484 L10.6332931,2.39431484" id="路径-17"></path>
<path d="M2.45321216,3.89402686 L2.45321216,11.9292428 C2.45321216,12.4815275 2.90092741,12.9292428 3.45321216,12.9292428 L10.4872657,12.9292428 C11.0395505,12.9292428 11.4872657,12.4815275 11.4872657,11.9292428 L11.4872657,3.89402686 L11.4872657,3.89402686" id="路径-20"></path>
<line x1="5.49894415" y1="3.89402686" x2="5.49894415" y2="10.3954667" id="路径-21"></line>
<line x1="8.49836822" y1="3.89402686" x2="8.49836822" y2="10.3954667" id="路径-22"></line>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 13备份</title>
<defs>
<linearGradient x1="50%" y1="-4.26048086e-13%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#26AAF9" offset="0%"></stop>
<stop stop-color="#1370FF" offset="100%"></stop>
</linearGradient>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-13备份">
<rect id="矩形" fill="url(#linearGradient-1)" x="0" y="0" width="40" height="40" rx="4"></rect>
<g id="编组-4备份-4" transform="translate(9.000000, 9.000000)">
<g id="矩形-2">
<rect id="矩形" x="0" y="0" width="22" height="22"></rect>
</g>
<path d="M18.14,3 L3.86,3 C3.385,3 3,3.3852 3,3.86 L3,6.54 C3,7.015 3.385,7.4 3.86,7.4 L18.14,7.4 C18.615,7.4 19,7.015 19,6.54 L19,3.86 C19,3.3852 18.615,3 18.14,3 Z M17.28,5.68 L9.28,5.68 C9.298916,5.6446 9.30956773,5.6036 9.30956773,5.56 L9.30956773,4.84 C9.30956773,4.7964 9.298916,4.7554 9.28,4.72 L17.28,4.72 L17.28,5.68 Z M18.14,8.8 L3.86,8.8 C3.385,8.8 3,9.1852 3,9.66 L3,12.34 C3,12.815 3.385,13.2 3.86,13.2 L18.14,13.2 C18.615,13.2 19,12.815 19,12.34 L19,9.66 C19,9.1852 18.615,8.8 18.14,8.8 Z M17.28,11.48 L9.28,11.48 C9.298916,11.4446 9.30956773,11.4036 9.30956773,11.36 L9.30956773,10.64 C9.30956773,10.5964 9.298916,10.5554 9.28,10.52 L17.28,10.52 L17.28,11.48 Z M18.14,14.6 L3.86,14.6 C3.385,14.6 3,14.9852 3,15.46 L3,18.14 C3,18.615 3.385,19 3.86,19 L18.14,19 C18.615,19 19,18.615 19,18.14 L19,15.46 C19,14.9852 18.615,14.6 18.14,14.6 Z M17.28,17.28 L9.28,17.28 C9.298916,17.2446 9.30956773,17.2036 9.30956773,17.16 L9.30956773,16.44 C9.30956773,16.3964 9.298916,16.3554 9.28,16.32 L17.28,16.32 L17.28,17.28 Z" id="形状" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 22备份</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-22备份">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-57" transform="translate(1.500000, 0.500000)" stroke="#565C66" stroke-linejoin="round" stroke-width="1.5">
<polyline id="路径" points="2.61444632e-13 10.5038375 0 14 13 14 13 10.5"></polyline>
<polyline id="路径" points="11 6 6.5 10.5 2 6"></polyline>
<line x1="6.49585" y1="0" x2="6.5" y2="10" id="路径"></line>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 22备份</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-22备份">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-57" transform="translate(1.500000, 0.500000)" stroke="#8A9099" stroke-linejoin="round" stroke-width="1.5">
<polyline id="路径" points="2.61444632e-13 10.5038375 0 14 13 14 13 10.5"></polyline>
<polyline id="路径" points="11 6 6.5 10.5 2 6"></polyline>
<line x1="6.49585" y1="0" x2="6.5" y2="10" id="路径"></line>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 7备份 3</title>
<defs>
<linearGradient x1="50%" y1="-4.26048086e-13%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#75EBCB" offset="0%"></stop>
<stop stop-color="#0DD09B" offset="100%"></stop>
</linearGradient>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-7备份-3">
<rect id="矩形备份" fill="url(#linearGradient-1)" x="0" y="0" width="40" height="40" rx="4"></rect>
<g id="编组-7备份-14" transform="translate(9.000000, 9.000000)">
<rect id="矩形" x="0" y="0" width="22" height="22"></rect>
<g id="编组-6" transform="translate(3.928571, 2.357143)">
<path d="M1.2,0 L9.49020093,0 L9.49020093,0 L14.1428571,4.65265622 L14.1428571,16.0857143 C14.1428571,16.748456 13.6055988,17.2857143 12.9428571,17.2857143 L1.2,17.2857143 C0.5372583,17.2857143 -3.6292676e-16,16.748456 0,16.0857143 L0,1.2 C-8.11624501e-17,0.5372583 0.5372583,-3.22345535e-16 1.2,0 Z" id="矩形" fill="#FFFFFF"></path>
<g id="编组-4" transform="translate(3.535714, 7.142857)" stroke="#0DD09B" stroke-width="1.2">
<line x1="7.85086282e-15" y1="6.39285714" x2="7.07142857" y2="6.39285714" id="路径-15备份-2"></line>
<line x1="7.85086282e-15" y1="3.39285714" x2="7.07142857" y2="3.39285714" id="路径-15备份-3"></line>
<line x1="7.85086282e-15" y1="0.392857143" x2="7.07142857" y2="0.392857143" id="路径-15备份-4"></line>
</g>
<path d="M9.49020093,0 L14.1428571,4.65265622 L10.6902009,4.65265622 C10.0274592,4.65265622 9.49020093,4.11539792 9.49020093,3.45265622 L9.49020093,0 L9.49020093,0 Z" id="路径-9" fill="#9AF8E5"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 65备份</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-65备份">
<rect id="矩形" x="0" y="0" width="18" height="18"></rect>
<g id="1.Base基础/Icon图标/查看备份" transform="translate(1.000000, 1.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-58" transform="translate(0.500000, 1.488632)" stroke="#565C66" stroke-width="1.62830815">
<g id="编组">
<line x1="0" y1="0.5" x2="12.4755135" y2="0.5" id="路径"></line>
<line x1="0" y1="6.18590274" x2="4.99389897" y2="6.18590274" id="路径"></line>
<line x1="0" y1="11.8718055" x2="5.66782353" y2="11.8718055" id="路径"></line>
<line x1="13.0860211" y1="10.7189929" x2="15.2967853" y2="13.4172047" id="路径"></line>
<path d="M10.6064141,3.72994425 C11.6910045,3.72994425 12.6717682,4.15682942 13.3821406,4.84341174 C14.1027218,5.53986092 14.5458693,6.50270675 14.5458693,7.56473415 C14.5458693,8.62676155 14.1027218,9.58960738 13.3821406,10.2860566 C12.6717682,10.9726389 11.6910045,11.3995241 10.6064141,11.3995241 C9.52182361,11.3995241 8.54105997,10.9726389 7.83068751,10.2860566 C7.11010631,9.58960738 6.66695888,8.62676155 6.66695888,7.56473415 C6.66695888,6.50270675 7.11010631,5.53986092 7.83068751,4.84341174 C8.54105997,4.15682942 9.52182361,3.72994425 10.6064141,3.72994425 Z" id="路径"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 65</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-65">
<rect id="矩形" x="0" y="0" width="18" height="18"></rect>
<g id="1.Base基础/Icon图标/查看备份" transform="translate(1.000000, 1.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-58" transform="translate(0.500000, 1.488632)" stroke="#8A9099" stroke-width="1.62830815">
<g id="编组">
<line x1="0" y1="0.5" x2="12.4755135" y2="0.5" id="路径"></line>
<line x1="0" y1="6.18590274" x2="4.99389897" y2="6.18590274" id="路径"></line>
<line x1="0" y1="11.8718055" x2="5.66782353" y2="11.8718055" id="路径"></line>
<line x1="13.0860211" y1="10.7189929" x2="15.2967853" y2="13.4172047" id="路径"></line>
<path d="M10.6064141,3.72994425 C11.6910045,3.72994425 12.6717682,4.15682942 13.3821406,4.84341174 C14.1027218,5.53986092 14.5458693,6.50270675 14.5458693,7.56473415 C14.5458693,8.62676155 14.1027218,9.58960738 13.3821406,10.2860566 C12.6717682,10.9726389 11.6910045,11.3995241 10.6064141,11.3995241 C9.52182361,11.3995241 8.54105997,10.9726389 7.83068751,10.2860566 C7.11010631,9.58960738 6.66695888,8.62676155 6.66695888,7.56473415 C6.66695888,6.50270675 7.11010631,5.53986092 7.83068751,4.84341174 C8.54105997,4.15682942 9.52182361,3.72994425 10.6064141,3.72994425 Z" id="路径"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
......@@ -122,7 +122,7 @@ const theme = createTheme({
minWidth: "60px",
},
sizeMedium: {
"& p": { fontSize: "14px" },
"& p": { fontSize: "14px", lineHeight: "20px" },
height: "32px",
padding: "0 16px",
minWidth: "68px",
......
......@@ -7,6 +7,7 @@ import {
DialogTitle,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { ThemeProvider, createTheme } from "@mui/material/styles";
import MyButton from "./MyButton";
......@@ -51,8 +52,27 @@ export interface IDialogProps {
| "info"
| "warning"; //按钮颜色风格
loading?: boolean; // 确认按钮是否处于loading状态
isText?: boolean; // 是否文本弹窗
}
const theme = createTheme({
// 0px 12px 15px -7px rgb(0 0 0 / 11%), 0px 24px 38px 3px rgb(0 0 0 / 9%), 0px 9px 46px 8px rgb(0 0 0 / 9%)
// .css-1t1j96h-MuiPaper-root-MuiDialog-paper
components: {
MuiPaper: {
styleOverrides: {
root: {
"&.MuiDialog-paper": {
boxShadow:
"0px 12px 15px -7px rgb(0 0 0 / 11%), 0px 24px 38px 3px rgb(0 0 0 / 9%), 0px 9px 46px 8px rgb(0 0 0 / 9%)",
},
},
},
},
},
});
const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
const {
title,
......@@ -74,6 +94,7 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
clickMaskClose = false,
loading = false,
okColor = "primary",
isText = false,
} = props;
const handelClose = (
......@@ -91,7 +112,7 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
return footerRender ? (
footerRender()
) : (
<DialogActions style={{ padding: "0 24px 16px 24px" }}>
<DialogActions style={{ padding: "16px 24px 16px 24px" }}>
{showCancel ? (
<MyButton
text={cancelText || "取消"}
......@@ -127,54 +148,66 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
loading,
showConfirm,
]);
const contentPadding = useMemo(() => {
if (isText) {
return "8px 24px 24px"; // 文本
} else {
return "8px 24px 12px"; // 表单
}
}, [isText]);
return (
<Dialog
open={open}
onClose={handelClose}
style={style}
className={className}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
sx={{
"& .MuiDialog-container": {
"& .MuiPaper-root": {
// 设置最大宽度, 实际宽度让子元素撑大
maxWidth: "1920px",
borderRadius: "8px",
<ThemeProvider theme={theme}>
<Dialog
open={open}
onClose={handelClose}
style={style}
className={className}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
sx={{
"& .MuiDialog-container": {
"& .MuiPaper-root": {
// 设置最大宽度, 实际宽度让子元素撑大
maxWidth: "1920px",
borderRadius: "8px",
},
},
},
}}
>
{isHideHeader ? null : (
<DialogTitle id="alert-dialog-title" sx={{ padding: "20px 24px" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
fontWeight: 600,
}}
>
<span
style={{ fontSize: 16, lineHeight: "24px", color: "#1E2633" }}
>
{title}
</span>
<CloseIcon
onClick={onClose}
sx={{
fontSize: "18px",
color: "#C2C6CC",
cursor: "pointer",
":hover": { background: "#f0f2f5", borderRadius: "2px" },
}}
>
{isHideHeader ? null : (
<DialogTitle id="alert-dialog-title" sx={{ padding: "20px 24px" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
fontWeight: 600,
}}
/>
</div>
</DialogTitle>
)}
<DialogContent style={{ minWidth: 388 }}>{children}</DialogContent>
{Footer}
</Dialog>
>
<span
style={{ fontSize: 16, lineHeight: "24px", color: "#1E2633" }}
>
{title}
</span>
<CloseIcon
onClick={onClose}
sx={{
fontSize: "18px",
color: "#C2C6CC",
cursor: "pointer",
":hover": { background: "#f0f2f5", borderRadius: "2px" },
}}
/>
</div>
</DialogTitle>
)}
<DialogContent style={{ minWidth: 388, padding: contentPadding }}>
{children}
</DialogContent>
{Footer}
</Dialog>
</ThemeProvider>
);
};
......
......@@ -60,12 +60,22 @@ const theme = createTheme({
styleOverrides: {
root: {
color: "rgba(209, 214, 222, 1)",
"&.MuiCheckbox-indeterminate": {
color: "rgba(19, 112, 255, 1)",
},
"&.Mui-checked": {
color: "rgba(19, 112, 255, 1)",
},
},
},
},
MuiPaper: {
styleOverrides: {
root: {
boxShadow: "0px 3px 10px 0px rgba(0,24,57,0.14)",
},
},
},
},
});
......@@ -83,6 +93,7 @@ type IMyMultipleMenuProps = {
selectAllText?: string; // 全选的文字
showHiddenIcon?: boolean; // 是否显示 展开收起箭头
iconColor?: string; // 展开收起箭头的颜色
topContent?: any; // 在全选上面的元素 在全选上面 常用于解释说明
};
const MyMultipleMenu = (props: IMyMultipleMenuProps) => {
......@@ -95,6 +106,7 @@ const MyMultipleMenu = (props: IMyMultipleMenuProps) => {
selectAllText = "全部",
showHiddenIcon = true,
iconColor,
topContent = null,
} = props;
// 下拉框展示的相对位置参考元素
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
......@@ -175,6 +187,7 @@ const MyMultipleMenu = (props: IMyMultipleMenuProps) => {
"aria-labelledby": "basic-button",
}}
>
{topContent}
{showSelectAll && (
<MenuItem onClick={() => handleMenuAllClick()} key="indeterminate">
<Checkbox
......
......@@ -26,7 +26,7 @@ export type sortState = {
interface IMyTableProps {
rows: Array<any>; // 表格数据
headCells: Array<any>; // 表头配置
key?: string; // 表格数据的key
tableKey?: string; // 表格数据的key
loading?: boolean; // 是否正在加载数据
hasCheckbox?: boolean; // 是否有复选框
selectItems?: Array<any>; // 选中的项
......@@ -50,7 +50,7 @@ const MyTable = (props: IMyTableProps) => {
const {
rows,
headCells,
key = "id",
tableKey = "id",
loading = false,
hasCheckbox = false,
selectItems = [],
......@@ -168,8 +168,12 @@ const MyTable = (props: IMyTableProps) => {
MuiCheckbox: {
styleOverrides: {
root: {
color: "rgba(209, 214, 222, 1)",
"&.MuiCheckbox-indeterminate .MuiSvgIcon-root": {
color: "rgba(19, 112, 255, 1)",
},
"&.Mui-checked .MuiSvgIcon-root": {
color: "rgba(19, 110, 250, 1)",
color: "rgba(19, 112, 255, 1)",
},
},
},
......@@ -204,12 +208,12 @@ const MyTable = (props: IMyTableProps) => {
const onSelectAllClick = useCallback(
(e: any) => {
if (e.target.checked) {
setSelectItems && setSelectItems(rows.map((row) => row[key]));
setSelectItems && setSelectItems(rows.map((row) => row[tableKey]));
} else {
setSelectItems && setSelectItems([]);
}
},
[setSelectItems, key, rows]
[setSelectItems, tableKey, rows]
);
const onSelectRowClick = useCallback(
......@@ -359,8 +363,8 @@ const MyTable = (props: IMyTableProps) => {
}
return (
<TableBody>
{rows.map((row) => (
<TableRow key={row[key]}>
{rows.map((row, rowIndex) => (
<TableRow key={row[tableKey] || rowIndex}>
{hasCheckbox && (
<TableCell
align="left"
......@@ -368,10 +372,11 @@ const MyTable = (props: IMyTableProps) => {
>
<Checkbox
checked={
selectItems.filter((selectItem) => selectItem === row[key])
.length > 0
selectItems.filter(
(selectItem) => selectItem === row[tableKey]
).length > 0
}
onChange={(e) => onSelectRowClick(e, row[key])}
onChange={(e) => onSelectRowClick(e, row[tableKey])}
/>
</TableCell>
)}
......@@ -393,7 +398,15 @@ const MyTable = (props: IMyTableProps) => {
</div>
</MyTooltip>
)}
{!headCell.showOverflowTooltip && <>{row[headCell.id]}</>}
{!headCell.showOverflowTooltip && (
<div
style={{
width: headCell.width ? Number(headCell.width) - 32 : "",
}}
>
{row[headCell.id]}
</div>
)}
</TableCell>
))}
</TableRow>
......@@ -402,7 +415,7 @@ const MyTable = (props: IMyTableProps) => {
);
}, [
rows,
key,
tableKey,
hasCheckbox,
selectItems,
onSelectRowClick,
......
......@@ -8,6 +8,7 @@
*/
import { Tooltip, TooltipProps } from "@mui/material";
import { ThemeProvider, createTheme } from "@mui/material/styles";
import { useMemo } from "react";
interface IMyTooltipProps extends Omit<TooltipProps, "title"> {
title?: string | boolean;
......@@ -20,6 +21,7 @@ const theme = createTheme({
tooltip: {
backgroundColor: "rgba(7, 19, 38, .8)",
color: "#fff",
padding: 0,
},
arrow: {
"&:before": {
......@@ -34,12 +36,31 @@ const theme = createTheme({
const MyTooltip = (props: IMyTooltipProps) => {
const { title = false, children, placement = "top", ...other } = props;
const randerTitle = useMemo(() => {
if (title) {
return (
<div
style={{
maxHeight: "36vh",
overflow: "overlay",
padding: "8px 16px",
}}
>
{title}
</div>
);
} else {
return "";
}
}, [title]);
return (
<ThemeProvider theme={theme}>
<Tooltip
// interactive={true}
arrow
title={title || ''}
title={randerTitle}
placement={placement}
{...other}
>
......
import {useEffect,useState} from 'react'
interface WindowSize{
width:number
height:number
}
function useWindowSize():WindowSize{
const [windowSize,setWindowSize]=useState<WindowSize>({
width:0,
height:0,
})
useEffect(()=>{
const handler=()=>{
setWindowSize({
width:window.innerWidth,
height:window.innerHeight
})
}
handler()
window.addEventListener('resize',handler)
return ()=>{
window.removeEventListener('resize',handler)
}
},[])
return windowSize
}
export default useWindowSize
\ No newline at end of file
......@@ -77,11 +77,19 @@ const FileItem = observer((props: IProps) => {
if (text === "查看文件") {
if (
location?.state?.pathName !== fileItemInfo?.path ||
location?.pathname !== "/product/cadd/projectData"
location?.pathname !==
`/product/${
currentProjectStore.currentProductInfo.id || "cadd"
}/projectData`
) {
navigate(`/product/cadd/projectData`, {
state: { pathName: fileItemInfo?.path },
});
navigate(
`/product/${
currentProjectStore.currentProductInfo.id || "cadd"
}/projectData`,
{
state: { pathName: fileItemInfo?.path },
}
);
}
}
};
......
......@@ -10,6 +10,7 @@ import useMyRequest from "@/hooks/useMyRequest";
import { useStores } from "@/store";
import { toJS } from "mobx";
import { ITask } from "@/views/Project/ProjectSubmitWork/interface";
import { observer } from "mobx-react-lite";
type IProps = {
operatorList: ITask[];
......@@ -17,7 +18,7 @@ type IProps = {
setInputActive: any;
};
const OperatorList = (props: IProps) => {
const OperatorList = observer((props: IProps) => {
const { operatorList, setOperatorList, setInputActive } = props; // 流程图中流算子列表
const { currentProjectStore } = useStores();
const [list, setList] = useState<ITask[]>([]); // 算子列表
......@@ -249,6 +250,6 @@ const OperatorList = (props: IProps) => {
</div>
</div>
);
};
});
export default OperatorList;
......@@ -24,10 +24,15 @@
font-size: 14px;
line-height: 22px;
border-left: 3px solid #f7f8fa;
font-weight: 400;
display: flex;
justify-content: flex-start;
align-items: center;
}
.listItem:hover {
background-color: #eef1f5;
border-left: 3px solid #eef1f5;
font-weight: 500;
}
.routerIcon {
vertical-align: middle;
......@@ -39,4 +44,5 @@
border-left: 3px solid #1370ff;
color: #1370ff;
background-color: #e6eaf0;
font-weight: 500;
}
......@@ -80,9 +80,7 @@ const MenuLayout = observer(() => {
}
alt=""
/>
<span style={{ verticalAlign: "middle", fontWeight: "500" }}>
{item.name}
</span>
<span style={{ verticalAlign: "middle" }}>{item.name}</span>
</li>
);
}
......
......@@ -110,7 +110,7 @@ const AddFolder = (props: IAddFolderProps) => {
onConfirm={handleAddSubmit}
title="新建文件夹"
>
<div style={{ padding: "12px 0" }}>
<div>
<MyInput
sx={{
width: "388px",
......@@ -125,7 +125,12 @@ const AddFolder = (props: IAddFolderProps) => {
helperText={fileNameCheck.help}
InputProps={{
endAdornment: (
<InputAdornment position="end" style={{ color: fileName.length >= 30 ? "#d32f2f" : "#C2C6CC" }}>
<InputAdornment
position="end"
style={{
color: fileName.length >= 30 ? "#d32f2f" : "#C2C6CC",
}}
>
{fileName.length}/30
</InputAdornment>
),
......
......@@ -49,8 +49,8 @@ const DeleteDialog = (props: IDeleteFileProps) => {
if (currentOperateFile) {
return [currentOperateFile];
} else {
return showList.filter((item: any) => {
return selectIds.indexOf(item.name) !== -1;
return selectIds.map((item) => {
return showList[item];
});
}
}, [currentOperateFile, selectIds, showList]);
......@@ -90,6 +90,7 @@ const DeleteDialog = (props: IDeleteFileProps) => {
onClose={() => setDeleteDialogOpen(false)}
onConfirm={handleSubmit}
okColor="error"
isText={true}
>
{currentOperateFile
? "确认删除该数据吗?"
......
......@@ -102,9 +102,11 @@ const MoveFile = (props: IMoveFileProps) => {
moveFolderArr = [];
}
} else {
moveFolderArr = showList.filter((item: any) => {
return selectIds.indexOf(item.name) !== -1 && item.type === "directory";
});
moveFolderArr = selectIds
.map((item) => {
return showList[item];
})
.filter((item) => item.type === "directory");
}
pathArr = moveFolderArr.map((item: any) => {
return path === "/" ? `/${item.name}` : `${path}/${item.name}`;
......@@ -147,8 +149,8 @@ const MoveFile = (props: IMoveFileProps) => {
if (currentOperateFile) {
return [currentOperateFile];
} else {
return showList.filter((item: any) => {
return selectIds.indexOf(item.name) !== -1;
return selectIds.map((item) => {
return showList[item];
});
}
}, [currentOperateFile, selectIds, showList]);
......
......@@ -11,7 +11,8 @@
margin: 0 16px 16px 0;
border: 1px solid rgba(235, 237, 240, 1);
border-radius: 4px;
min-height: 275px;
min-height: 339px;
max-height: 339px;
box-sizing: border-box;
position: relative;
cursor: pointer;
......@@ -32,11 +33,11 @@
margin-bottom: 0;
}
.datasetLiTop {
height: 55%;
height: 185px;
box-sizing: border-box;
}
.datasetLiBottom {
height: 45%;
height: 152px;
box-sizing: border-box;
background-color: RGBA(247, 248, 250, 1);
display: flex;
......@@ -66,8 +67,8 @@
line-height: 22px;
}
.datasetLiDataLi {
height: 20px;
line-height: 20px;
height: 28px;
line-height: 28px;
color: rgba(30, 38, 51, 1);
font-size: 12px;
padding: 0 16px;
......@@ -94,3 +95,21 @@
.nullBox {
visibility: hidden;
}
.blackCheckBox {
position: absolute;
top: 16px;
right: 20px;
z-index: 1;
width: 15px;
height: 15px;
background-image: url(../../../../../../assets/project/blackCheckBox.svg);
}
.blackCheckBoxActive {
background-image: url(../../../../../../assets/project/blackCheckBoxActive.svg);
}
.blackCheckBox:hover {
background-image: url(../../../../../../assets/project/blackCheckBoxHover.svg);
}
.blackCheckBoxActive:hover {
background-image: url(../../../../../../assets/project/blackCheckBoxActive.svg);
}
......@@ -73,9 +73,6 @@ const DatasetCardTable = (props: IDatasetCardTableProps) => {
)}
</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)
......@@ -117,19 +114,13 @@ const DatasetCardTable = (props: IDatasetCardTableProps) => {
/>
)}
{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
className={classNames({
[style.blackCheckBox]: true,
[style.blackCheckBoxActive]: selectItems.includes(
item.id
),
})}
/>
)}
</div>
......
import { useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import MyTable from "@/components/mui/MyTableNew";
import { sortState } from "@/components/mui/MyTableNew";
......@@ -22,12 +22,19 @@ const DatasetTable = (props: IDatasetTableProps) => {
setSortState,
loading,
} = props;
const [innerWidth, setInnerWidth] = useState(window.innerWidth);
useEffect(() => {
window.addEventListener("resize", () => {
setInnerWidth(window.innerWidth);
});
}, []);
const headCells = useMemo(() => {
let width =
showData.length === 0
? window.innerWidth - 112
: `${(window.innerWidth - 112) / showData.length}`;
return showData.map((item, index) => {
? innerWidth - 112
: `${(innerWidth - 112) / showData.length}`;
return showData.map((item) => {
return {
id: item,
label: item,
......@@ -36,7 +43,7 @@ const DatasetTable = (props: IDatasetTableProps) => {
sort: true,
};
});
}, [showData]);
}, [showData, innerWidth]);
return (
<MyTable
rows={list}
......
......@@ -8,10 +8,16 @@
height: 100%;
}
.datasetBoxShowFoot {
padding-bottom: 64px;
padding-bottom: 76px;
}
.top {
margin-bottom: 16px;
position: relative;
margin: 0 -32px;
padding: 0 32px 16px;
}
.topBoxShadow {
box-shadow: 0 5px 4px -4px rgb(0, 0, 0, 0.12);
z-index: 10;
}
.title {
line-height: 22px;
......@@ -60,15 +66,26 @@
.searchBox {
width: 662px;
background-color: #fff;
padding: 20px 24px 24px;
padding: 20px 0 24px 24px;
box-sizing: border-box;
}
.deleteIcon {
cursor: pointer;
width: 16px;
height: 16px;
background-image: url(../../../../assets/project/delete.svg);
background-repeat: no-repeat;
}
.deleteIcon:hover {
background-image: url(../../../../assets/project/deleteHover.svg);
}
.deleteIconDisabled {
background-image: url(../../../../assets/project/deleteDisable.svg);
cursor: not-allowed;
}
.deleteIconDisabled:hover {
background-image: url(../../../../assets/project/deleteDisable.svg);
}
.searchTop {
margin-bottom: 12px;
}
......@@ -90,7 +107,9 @@
width: 180px;
}
.searchList {
margin-bottom: 24px;
margin-bottom: 8px;
max-height: 300px;
overflow-y: overlay;
}
.searchLi {
display: flex;
......@@ -102,6 +121,7 @@
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 24px;
}
.searchFooterLeft {
color: rgba(19, 112, 255, 1);
......@@ -115,21 +135,24 @@
.selectShowData {
font-size: 14px;
color: rgba(30, 38, 51, 1);
cursor: pointer;
}
.table {
flex: 1;
overflow-y: overlay;
display: flex;
flex-direction: column;
margin: 0 -32px;
padding: 0 32px;
}
.foot {
position: absolute;
z-index: 1;
bottom: 0;
background-color: #fff;
width: calc(100vw - 64px);
box-sizing: border-box;
height: 76px;
padding: 0 32px;
margin: 0 32px;
display: flex;
justify-content: flex-end;
......@@ -138,3 +161,10 @@
.borderTop {
border-top: 1px solid rgba(240, 242, 245, 1);
}
.topContent {
padding: 4px 16px;
color: rgba(138, 144, 153, 1);
line-height: 20px;
font-size: 12px;
}
......@@ -69,6 +69,20 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
const [downloadOpen, setDownloadOpen] = useState(false); // 下载弹窗显示控制
const [firstGetList, setFirstGetList] = useState(true); // 第一次请求列表
// 滚轮是否到顶,判断是否显示阴影
const [isTop, setIsTop] = useState(true);
// 滚动滚轮时监听是否到顶
const onscroll = (e: any) => {
if (e.target.scrollTop <= 0) {
console.log(1);
setIsTop(true);
} else {
console.log(2);
setIsTop(false);
}
};
// 页码改变
const pageChange = (value: number) => {
getList(value - 1);
......@@ -200,6 +214,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
// 显示数据变化
const handleSetShowData = (e: any) => {
if (e.length === 0) {
setShowData([dataTypes[0].value]);
return;
}
setShowData(e);
......@@ -282,15 +297,13 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
onChange={(e) => handleQueryChange(e, index)}
sx={{ marginRight: "16px", width: "180px" }}
></MyInput>
<img
<div
onClick={() => handleDeleteQuery(index)}
src={jobDel}
alt=""
className={classNames({
[style.deleteIcon]: true,
[style.deleteIconDisabled]: querylist.length === 1,
})}
/>
></div>
</div>
);
})}
......@@ -331,7 +344,12 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
[style.datasetBoxShowFoot]: true,
})}
>
<div className={style.top}>
<div
className={classNames({
[style.top]: true,
[style.topBoxShadow]: !isTop,
})}
>
<div className={style.title}>{name}</div>
<div className={style.screens}>
<div className={style.screensLeft}>
......@@ -395,6 +413,9 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
setValue={(e: any) => handleSetShowData(e)}
showSelectAll={true}
iconColor="rgba(138, 144, 153, 1)"
topContent={
<div className={style.topContent}>至少勾选一项</div>
}
>
<span className={style.selectShowData}>
选择显示数据({showData.length})
......@@ -432,7 +453,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
</div>
</div>
</div>
<div className={style.table}>
<div className={style.table} onScroll={onscroll}>
{tableType === "table" && (
<DatasetTable
list={list}
......
......@@ -14,6 +14,9 @@
margin-bottom: 14px;
font-weight: 600;
}
.tableBox {
height: 350px;
}
.dropBox {
cursor: pointer;
height: 300px;
......
......@@ -8,7 +8,7 @@ import style from "./index.module.css";
import MyDialog from "@/components/mui/MyDialog";
import { uuid } from "@/utils/util";
import { useMessage } from "@/components/MySnackbar";
import MyTable from "@/components/mui/MyTable";
import MyTable from "@/components/mui/MyTableNew";
import fileIcon from "@/assets/project/fileIcon.svg";
import noFile from "@/assets/project/noFile.svg";
import uploaderIcon from "@/assets/project/uploaderIcon.svg";
......@@ -149,9 +149,9 @@ const UpLoaderFile = observer((props: IMoveFileProps) => {
}, [uploaderDialogOpen]);
const fileListHeadCells = [
{ id: "name", numeric: false, label: "名称", width: "60%" },
{ id: "size", numeric: false, label: "大小", width: "25%" },
{ id: "caozuo", numeric: false, label: "操作", width: "15%" },
{ id: "name", label: "名称", width: 300 },
{ id: "size", label: "大小", width: 120 },
{ id: "caozuo", label: "操作", width: 100 },
];
const renderName = (item: any) => {
......@@ -163,7 +163,7 @@ const UpLoaderFile = observer((props: IMoveFileProps) => {
);
};
const renderSize = (item: any) => {
return <span>{item.size ? storageUnitFromB(Number(item.size)) : "-"}</span>;
return `${item.size ? storageUnitFromB(Number(item.size)) : "-"}`;
};
const handleRowDelete = (index: number) => {
......@@ -175,7 +175,7 @@ const UpLoaderFile = observer((props: IMoveFileProps) => {
return (
<MyButton
text="删除"
style={{ position: "relative", left: "-18px" }}
style={{ position: "relative", left: "-18px", height: "22px" }}
variant="text"
size="small"
color="error"
......@@ -224,25 +224,14 @@ const UpLoaderFile = observer((props: IMoveFileProps) => {
</div>
<div className={style.tableBox}>
<MyTable
rowHover={true}
stickyHeader={true}
fixedHead={true}
rows={fileList.map((item: any, index: number) => ({
...item,
name: renderName(item),
size: renderSize(item),
caozuo: renderButtons(item, index),
}))}
rowsPerPage={"99"}
headCells={fileListHeadCells}
footer={false}
// headTableCellStyle={{
// fontSize: "12px",
// lineHeight: "20px",
// color: "#8A9099",
// }}
tableContainerStyle={{
maxHeight: "300px",
}}
/>
</div>
{fileList.length === 0 && (
......
.projectData {
position: relative;
height: calc(100vh - 57px);
}
.projectDataStickyTop {
height: 100%;
padding: 28px 24px 64px;
position: relative;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.projectDataStickyTopPadding {
padding: 28px 24px 24px;
}
.projectDataTitle {
font-size: 18px;
......@@ -15,6 +23,11 @@
.projectDataHeader {
position: relative;
}
.tableBox {
/* flex: 1; */
height: calc(100% - 146px);
}
.projectDataButtonAndSearch {
display: flex;
justify-content: space-between;
......
......@@ -2,12 +2,11 @@ import React, { useState, useCallback, useEffect, useMemo } from "react";
import style from "./index.module.css";
import classnames from "classnames";
import { IconButton } from "@mui/material";
import MyTable from "@/components/mui/MyTable";
import MyTable from "@/components/mui/MyTableNew";
import dataSetIcon from "@/assets/project/dataSetIcon.svg";
import refresh from "@/assets/project/refresh.svg";
import fileIcon from "@/assets/project/fileIcon.svg";
import folderIcon from "@/assets/project/folderIcon.svg";
import noFile from "@/assets/project/noFile.svg";
import AddFolder from "./AddFolder";
import MoveFile from "./MoveFile";
import DeleteDialog from "./DeleteDialog";
......@@ -73,6 +72,11 @@ const ProjectData = observer(() => {
setPath(locationInfo?.pathName || "/");
}, [location]);
// 切换文件数据集时情况勾选项
useEffect(() => {
setSelectIds([]);
}, [activeTab]);
// 列表展示的数据
const showList = useMemo(() => {
if (activeTab === "file") {
......@@ -86,12 +90,24 @@ const ProjectData = observer(() => {
fileList.push(item);
}
});
return [...folderList, ...fileList];
let arr = [...folderList, ...fileList];
return arr.map((item, index) => {
return {
...item,
id: index,
};
});
} else {
const folderList = list.filter((item: any) => {
return item.type === "directory";
});
return [...folderList, ...dataSetList];
let arr = [...folderList, ...dataSetList];
return arr.map((item, index) => {
return {
...item,
id: index,
};
});
}
}, [list, dataSetList, activeTab]);
......@@ -256,45 +272,16 @@ const ProjectData = observer(() => {
};
// table配置
const versionsHeadCells = useMemo(() => {
if (showCheckBox) {
return [
{ id: "checkbox" },
{ id: "name", numeric: false, label: "名称", width: "25%" },
{ id: "size", numeric: false, label: "大小", width: "25%", sort: true },
{
id: "mtime",
numeric: false,
label: "创建时间",
width: "25%",
sort: true,
},
{ id: "caozuo", numeric: false, label: "操作", width: "25%" },
];
} else {
return [
{ id: "name", numeric: false, label: "名称", width: "25%" },
{ id: "size", numeric: false, label: "大小", width: "25%", sort: true },
{
id: "mtime",
numeric: false,
label: "创建时间",
width: "25%",
sort: true,
},
{ id: "caozuo", numeric: false, label: "操作", width: "25%" },
];
}
}, [showCheckBox]);
// 点击复选框
const hanldeCheckbox = (e: any) => {
const selectarr = e.map((item: any) => {
let andIndex = item.indexOf("&index=");
return item.slice(5, andIndex);
});
setSelectIds(selectarr);
};
const versionsHeadCells = [
{ id: "name", label: "名称" },
{ id: "size", label: "大小", width: 200 },
{
id: "mtime",
label: "创建时间",
width: 200,
},
{ id: "caozuo", label: "操作", width: 200 },
];
// 文件夹下钻
const handleViewFolders = (item: any) => {
......@@ -312,7 +299,6 @@ const ProjectData = observer(() => {
// 查看数据集
const handleSeeDataset = (item: any) => {
console.log(item);
setSeeDatasetName(item.name);
setShowSeeDataset(true);
};
......@@ -373,6 +359,7 @@ const ProjectData = observer(() => {
position: "relative",
left: "-10px",
minWidth: "10px",
height: "22px",
padding: "0 10px",
visibility:
item.type !== "dataSet" && item.type !== "directory"
......@@ -391,6 +378,7 @@ const ProjectData = observer(() => {
position: "relative",
left: "-10px",
minWidth: "10px",
height: "22px",
padding: "0 10px",
}}
variant="text"
......@@ -410,6 +398,7 @@ const ProjectData = observer(() => {
position: "relative",
left: "-10px",
minWidth: "10px",
height: "22px",
padding: "0 10px",
}}
variant="text"
......@@ -529,7 +518,13 @@ const ProjectData = observer(() => {
if (currentProjectStore.currentProjectInfo.name) {
return (
<div className={style.projectData}>
<div className={style.projectDataStickyTop}>
{/* <div className={style.projectDataStickyTop}> */}
<div
className={classnames({
[style.projectDataStickyTop]: true,
[style.projectDataStickyTopPadding]: selectIds.length === 0,
})}
>
<div className={style.projectDataTitle}>项目数据</div>
<div className={style.projectDataHeader}>
<div className={style.projectDataButtonAndSearch}>
......@@ -593,32 +588,22 @@ const ProjectData = observer(() => {
</div>
</div>
</div>
<MyTable
footer={false}
rowHover={true}
onRef={tableRef}
stickyHeader={true}
initSelected={selectIds}
headCells={versionsHeadCells}
rowsPerPage={"99"}
checkboxData={(e: any) => {
hanldeCheckbox(e);
}}
rows={showList.map((item: any, index: number) => ({
...item,
id: `name=${item.name}&index=${index}`,
name: renderName(item),
size: renderSize(item),
mtime: renderMtime(item),
caozuo: renderButtons(item),
}))}
/>
{showList.length === 0 && (
<div className={style.noDataBox}>
<img className={style.noDataImg} src={noFile} alt="" />
<span className={style.noDataText}>暂无数据</span>
</div>
)}
<div className={style.tableBox}>
<MyTable
fixedHead={true}
hasCheckbox={showCheckBox}
headCells={versionsHeadCells}
selectItems={selectIds}
setSelectItems={setSelectIds}
rows={showList.map((item: any, index: number) => ({
...item,
name: renderName(item),
size: renderSize(item),
mtime: renderMtime(item),
caozuo: renderButtons(item),
}))}
/>
</div>
</div>
{selectIds.length > 0 && (
<div className={style.projectDataStickyBox}>
......@@ -635,7 +620,6 @@ const ProjectData = observer(() => {
/>
<MyButton
text={`批量移动 (${selectIds.length})`}
// color="neutral"
variant="contained"
style={{ marginRight: "24px" }}
onClick={() => {
......
......@@ -58,10 +58,11 @@
overflow: hidden;
}
.middleDynamic{
.middleDynamic {
display: flex;
position: absolute;
left: 0;
transition: left .4s ease-in-out;
}
.logTitle {
......@@ -78,6 +79,10 @@
border-right: 1px solid #10141A;
}
.logTitle:hover {
background-color: #23272E;
}
.logName {
max-width: 90px;
overflow: hidden;
......@@ -128,4 +133,12 @@
justify-content: end;
height: 76px;
padding-right: 24px;
}
.gradientBox {
position: absolute;
right: 49px;
width: 28px;
height: 32px;
background: linear-gradient(90deg, rgba(29, 33, 38, 0) 0%, #1D2126 100%);
}
\ No newline at end of file
import { useState, useCallback, useEffect, useMemo } from "react";
import classnames from "classnames";
import style from "./index.module.css";
import CloseIcon from "@mui/icons-material/Close";
import MyButton from "@/components/mui/MyButton";
import MyTooltip from "@/components/mui/MyTooltip";
import InsertDriveFileOutlinedIcon from "@mui/icons-material/InsertDriveFileOutlined";
import CloudEController from "@/api/fileserver/CloudEController";
import { useStores } from "@/store";
......@@ -10,6 +10,7 @@ import { toJS } from "mobx";
import FullScreenDrawer from "@/components/CommonComponents/FullScreenDrawer";
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import useWindowSize from '@/hooks/useWindowSize'
type LogViewProps = {
......@@ -20,6 +21,7 @@ type LogViewProps = {
const LogView = (props: LogViewProps) => {
const { logs, setShowLogView } = props;
const { currentProjectStore } = useStores();
const { width, height } = useWindowSize();
const fileToken = toJS(currentProjectStore.currentProjectInfo.filetoken);
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
// 当前选择的日志
......@@ -29,6 +31,13 @@ const LogView = (props: LogViewProps) => {
// 当前日志路径
const [logPath, setLogPath] = useState('')
const [displacement, setDisplacement] = useState(0)
const [middleDynamicWidth, setMiddleDynamicWidth] = useState(0)
const [leftButtonColor, setLeftButtonColor] = useState('#585D62')
const [rightButtonColor, setRightButtonColor] = useState('#585D62')
useEffect(() => {
setLogPath(logs[logCurrent]?.logPath)
}, [logs]);
......@@ -54,6 +63,29 @@ const LogView = (props: LogViewProps) => {
setLogPath(logs[logCurrent]?.logPath)
}, [logCurrent]);
//获取盒子的总宽度,用于滑动效果判断
useEffect(() => {
const box = document.getElementById('middleDynamic')
setMiddleDynamicWidth(box ? box.offsetWidth : 0)
}, [])
useEffect(() => {
if (middleDynamicWidth < width - 97) {
setLeftButtonColor('#585D62')
setRightButtonColor('#585D62')
}
if (displacement === 0) {
setLeftButtonColor('#585D62')
} else {
setLeftButtonColor('#C0C5CD')
}
if (middleDynamicWidth > width - 97 && displacement !== -middleDynamicWidth + width - 97) {
setRightButtonColor('#C0C5CD')
} else {
setRightButtonColor('#585D62')
}
}, [width, middleDynamicWidth, displacement])
// 下载当前日志
const handleDownLoad = () => {
const path = logPath.slice(12)
......@@ -64,29 +96,70 @@ const LogView = (props: LogViewProps) => {
);
}
const rightClick = () => {
if (middleDynamicWidth < width - 97) {
return
}
if (-displacement > middleDynamicWidth - width * 1.8 + 97) {
setDisplacement(-middleDynamicWidth + width - 97)
return
}
const newDisplacement = displacement - width * 0.8;
setDisplacement(newDisplacement)
}
const leftClick = () => {
if (-displacement < width * 0.8) {
setDisplacement(0)
return
}
const newDisplacement = displacement + width * 0.8;
setDisplacement(newDisplacement)
}
return (
<FullScreenDrawer handleClose={setShowLogView} zIndex={1002}>
<div className={style.logViewBox}>
<div className={style.logViewContentMask}></div>
<div className={style.logViewTop}>
<div className={style.leftButton}><ChevronLeftIcon /></div>
<div
className={style.leftButton}
onClick={leftClick}
style={{ color: leftButtonColor, cursor: leftButtonColor === '#585D62' ? 'default' : 'pointer' }}
>
<ChevronLeftIcon />
</div>
<div className={style.middleFixed}>
<div className={style.middleDynamic}>
<div className={style.middleDynamic} id='middleDynamic' style={{ left: `${displacement}px` }}>
{logs.map((item: any, index: number) => {
return <div
key={index}
onClick={() => { setLogCurrent(index) }}
className={classnames({
[style.logTitle]: true,
[style.logTitleSelected]: index === logCurrent,
})}>
<InsertDriveFileOutlinedIcon className={style.fileIcon} />
<span className={style.logName}>{item.logName}</span>
</div>
return <MyTooltip
title={item.logName}
placement="bottom"
arrow={false}
enterDelay={1000}
>
<div
key={index}
onClick={() => { setLogCurrent(index) }}
className={classnames({
[style.logTitle]: true,
[style.logTitleSelected]: index === logCurrent,
})}>
<InsertDriveFileOutlinedIcon className={style.fileIcon} />
<span className={style.logName}>{item.logName}</span>
</div>
</MyTooltip>
})}
</div>
</div>
<div className={style.rightButton}><ChevronRightIcon /></div>
<div className={style.gradientBox}></div>
<div
className={style.rightButton}
onClick={rightClick}
style={{ color: rightButtonColor, cursor: rightButtonColor === '#585D62' ? 'default' : 'pointer' }}
>
<ChevronRightIcon />
</div>
</div>
<div className={style.logViewContent}>
{logText}
......
import styles from "../index.module.css";
import { ITaskInfo } from "../../ProjectSubmitWork/interface";
import jobSue from "@/assets/project/jobSue.svg";
import jobStop from "@/assets/project/jobStop.svg";
import jobRun from "@/assets/project/jobRun.svg";
import jobFail from "@/assets/project/jobFail.svg";
import taskResultsFileIcon from "@/assets/project/taskResultsFileIcon.svg";
import taskResultsDatasetIcon from "@/assets/project/taskResultsDatasetIcon.svg";
import { IState } from "../../ProjectSubmitWork/interface";
import classNames from "classnames";
type ITaskInfoProps = {
workFlowJobInfo: ITaskInfo;
randerOutputs1: Array<any>;
handleDownLoadOutput: any;
handleShowPopper: any;
setGoToProjectDataPath: any;
setShowLogView: any;
state: IState | undefined;
name: any;
};
const stateMap = {
SUBMITTED: "正在启动",
RUNNING: "正在运行",
ABORTED: "运行终止",
FAILED: "运行失败",
SUCCEEDED: "运行成功",
};
const TaskInfo = (props: ITaskInfoProps) => {
const {
workFlowJobInfo,
randerOutputs1,
handleDownLoadOutput,
handleShowPopper,
setGoToProjectDataPath,
setShowLogView,
state,
name,
} = props;
return (
<div className={styles.taskInfo}>
<div className={styles.title}>
任务结果
<span className={styles.taskResultsNum}>{randerOutputs1.length}</span>
</div>
{workFlowJobInfo?.outputs &&
Object.keys(workFlowJobInfo?.outputs).length > 0 && (
<div className={styles.taskResults}>
{randerOutputs1.map((item, index) => {
return (
<div key={index} className={styles.outputLi}>
<div className={styles.outputLiLeft}>
<img
className={classNames({
[styles.outputLiLeftImg]: true,
[styles.outputLiLeftImgBoxShadow2]:
item.type === "file",
})}
src={
item.type === "file"
? taskResultsFileIcon
: taskResultsDatasetIcon
}
alt=""
/>
<div className={styles.outputLiLeftContent}>
<div className={styles.outputItemName}>{item.name}</div>
<div className={styles.outputLiSize}>{item.size}</div>
</div>
</div>
<div
onClick={(e: any) => {
handleDownLoadOutput(item);
}}
className={classNames({
[styles.outputLiRight]: true,
[styles.seeDataset]: item.type !== "file",
[styles.downloadFile]: item.type === "file",
})}
></div>
</div>
);
})}
</div>
)}
{(!workFlowJobInfo?.outputs ||
Object.keys(workFlowJobInfo?.outputs).length === 0) && (
<div className={styles.notResults}>暂无结果文件</div>
)}
<div className={styles.title}>任务信息</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>任务名称</div>
<div className={styles.taskInfoValue} title={name}>
{name || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>任务ID</div>
<div className={styles.taskInfoValue} title={workFlowJobInfo?.id}>
{workFlowJobInfo?.id || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>输出路径</div>
<div
className={classNames({
[styles.taskInfoValue]: true,
[styles.taskInfoValueClick]: true,
})}
onClick={(e: any) => {
handleShowPopper(
e,
"即将跳转至项目数据内该任务的输出路径,确认继续吗?",
"bottom"
);
setGoToProjectDataPath(workFlowJobInfo?.outputPath as string);
}}
>
{workFlowJobInfo?.outputPath || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>运行状态</div>
<div className={styles.taskInfoValue}>
{state === "SUCCEEDED" && (
<img className={styles.taskInfoValueIcon} src={jobSue} alt="" />
)}
{["SUBMITTED", "RUNNING"].includes(state || "") && (
<img className={styles.taskInfoValueIcon} src={jobRun} alt="" />
)}
{state === "ABORTED" && (
<img className={styles.taskInfoValueIcon} src={jobStop} alt="" />
)}
{state === "FAILED" && (
<img className={styles.taskInfoValueIcon} src={jobFail} alt="" />
)}
{state ? stateMap[state] : "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>源模板</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.specTitle || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>源模板版本</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.specVersion || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>花费(元)</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.jobCost || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>创建人</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.creator || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>创建时间</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.createTime || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>运行时间</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.costTime || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>日志文件</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.logPath && (
<>
<span
className={styles.taskInfoDownload}
onClick={() => setShowLogView(true)}
>
查看
</span>
</>
)}
{!workFlowJobInfo?.logPath && "-"}
</div>
</div>
</div>
);
};
export default TaskInfo;
......@@ -70,37 +70,79 @@
font-weight: 600;
margin-bottom: 16px;
}
.taskResultsNum {
color: rgba(19, 112, 255, 1);
line-height: 24px;
font-size: 16px;
margin-left: 8px;
}
.taskResults {
padding: 24px;
padding: 20px 24px 20px 20px;
background-color: rgba(247, 248, 250, 1);
margin-bottom: 24px;
border-radius: 4px;
}
.outputLi {
display: flex;
justify-content: space-between;
align-items: center;
margin: 6px 0;
margin-bottom: 20px;
}
.outputLi:last-child {
margin-bottom: 0;
}
.outputLiLeft {
cursor: pointer;
display: flex;
align-items: center;
color: rgba(19, 112, 255, 1);
font-size: 14px;
}
.outputLiLeftImg {
box-shadow: 0px 5px 11px -5px rgba(19, 110, 250, 0.64);
}
.outputLiLeftImgBoxShadow2 {
box-shadow: 0px 5px 11px -5px rgba(13, 204, 152, 0.64);
}
.outputItemName {
max-width: 172px;
white-space: nowrap;
display: block;
overflow: hidden;
text-overflow: ellipsis;
line-height: 22px;
font-size: 14px;
font-weight: 600;
color: rgba(30, 38, 51, 1);
margin-bottom: 4px;
}
.outputLiSize {
line-height: 20px;
font-size: 12px;
color: rgba(138, 144, 153, 1);
}
.outputLiLeftImg {
margin-right: 12px;
margin-right: 16px;
width: 40px;
height: 40px;
}
.outputLiRight {
color: rgba(138, 144, 153, 1);
font-size: 12px;
cursor: pointer;
}
.seeDataset {
width: 18px;
height: 18px;
background-image: url(../../../assets/project/taskResultsSeeIcon.svg);
}
.seeDataset:hover {
background-image: url(../../../assets/project/taskResultsSeeHoverIcon.svg);
}
.downloadFile {
width: 16px;
height: 16px;
background-image: url(../../../assets/project/taskResultsDownloadIcon.svg);
}
.downloadFile:hover {
background-image: url(../../../assets/project/taskResultsDownloadHoverIcon.svg);
}
.notResults {
background-color: rgba(247, 248, 250, 1);
......
......@@ -13,6 +13,7 @@ import classNames from "classnames";
import { useLocation, useNavigate } from "react-router-dom";
import MyButton from "@/components/mui/MyButton";
import TaskInfo from "./TaskInfo";
import useMyRequest from "@/hooks/useMyRequest";
import {
fetchWorkFlowJob,
......@@ -21,15 +22,12 @@ import {
} from "@/api/project_api";
import { IResponse } from "@/api/http";
import jobSue from "@/assets/project/jobSue.svg";
import jobStop from "@/assets/project/jobStop.svg";
import jobRun from "@/assets/project/jobRun.svg";
import fullScreen from "@/assets/project/fullScreen.svg";
import partialScreen from "@/assets/project/partialScreen.svg";
import goback from "@/assets/project/goback.svg";
import CloudEController from "@/api/fileserver/CloudEController";
import jobFail from "@/assets/project/jobFail.svg";
import fileIcon from "@/assets/project/fileIcon.svg";
import dataSetIcon from "@/assets/project/dataSetIcon.svg";
import { useStores } from "@/store";
import { ITaskInfo } from "../ProjectSubmitWork/interface";
import Flow from "../components/Flow";
......@@ -51,14 +49,6 @@ import MyTooltip from "@/components/mui/MyTooltip";
import styles from "./index.module.css";
const stateMap = {
SUBMITTED: "正在启动",
RUNNING: "正在运行",
ABORTED: "运行终止",
FAILED: "运行失败",
SUCCEEDED: "运行成功",
};
const statusMap = {
Done: "运行完成",
Running: "正在运行",
......@@ -197,25 +187,16 @@ const ProjectSubmitWork = observer(() => {
const goToProjectData = (path: string) => {
path = path.slice(12);
if (path) {
navigate(`/product/cadd/projectData`, {
navigate(`/product/${productId || "cadd"}/projectData`, {
state: { pathName: path },
});
} else {
navigate(`/product/cadd/projectData`, {
navigate(`/product/${productId || "cadd"}/projectData`, {
state: { pathName: "/" },
});
}
};
// 通过文件路径获取文件所在文件夹路径 如 输入 /ProjectData/task_a.out 输出/ProjectData/
// const getFolderPath = (path: string) => {
// const lastIndex = path.lastIndexOf("/");
// if (lastIndex !== -1) {
// path = path.slice(0, lastIndex);
// }
// return path;
// };
// 下载任务结果
const handleDownLoadOutput = (item: any) => {
// 是文件下载
......@@ -236,13 +217,13 @@ const ProjectSubmitWork = observer(() => {
/** 返回事件 */
const onBack = useCallback(() => {
if (locationInfo.from === "projectOverview") {
navigate("/product/cadd/projectOverview");
navigate(`/product/${productId || "cadd"}/projectOverview`);
} else {
navigate("/product/cadd/projectWorkbench", {
navigate(`/product/${productId || "cadd"}/projectWorkbench`, {
state: { type: "workbenchList" },
});
}
}, [navigate, locationInfo.from]);
}, [navigate, locationInfo.from, productId]);
const getOutouts = (outputs: any) => {
if (outputs) {
......@@ -483,173 +464,16 @@ const ProjectSubmitWork = observer(() => {
{fullScreenShow ? null : (
<div className={styles.swFormBox}>
{!activeFlowIndex && (
<div className={styles.taskInfo}>
<div className={styles.title}>任务结果</div>
{workFlowJobInfo?.outputs &&
Object.keys(workFlowJobInfo?.outputs).length > 0 && (
<div className={styles.taskResults}>
{randerOutputs1.map((item, index) => {
return (
<div key={index} className={styles.outputLi}>
<div
className={styles.outputLiLeft}
onClick={(e: any) => {
handleDownLoadOutput(item);
}}
>
<img
className={styles.outputLiLeftImg}
src={
item.type === "file" ? fileIcon : dataSetIcon
}
alt=""
/>
<span className={styles.outputItemName}>
{item.name}
</span>
</div>
<span className={styles.outputLiRight}>
{item.size}
</span>
</div>
);
})}
</div>
)}
{(!workFlowJobInfo?.outputs ||
Object.keys(workFlowJobInfo?.outputs).length === 0) && (
<div className={styles.notResults}>暂无结果文件</div>
)}
<div className={styles.title}>任务信息</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>任务名称</div>
<div className={styles.taskInfoValue} title={name}>
{name || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>任务ID</div>
<div
className={styles.taskInfoValue}
title={workFlowJobInfo?.id}
>
{workFlowJobInfo?.id || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>输出路径</div>
<div
className={classNames({
[styles.taskInfoValue]: true,
[styles.taskInfoValueClick]: true,
})}
onClick={(e: any) => {
handleShowPopper(
e,
"即将跳转至项目数据内该任务的输出路径,确认继续吗?",
"bottom"
);
setGoToProjectDataPath(
workFlowJobInfo?.outputPath as string
);
}}
>
{workFlowJobInfo?.outputPath || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>运行状态</div>
<div className={styles.taskInfoValue}>
{state === "SUCCEEDED" && (
<img
className={styles.taskInfoValueIcon}
src={jobSue}
alt=""
/>
)}
{["SUBMITTED", "RUNNING"].includes(state || "") && (
<img
className={styles.taskInfoValueIcon}
src={jobRun}
alt=""
/>
)}
{state === "ABORTED" && (
<img
className={styles.taskInfoValueIcon}
src={jobStop}
alt=""
/>
)}
{state === "FAILED" && (
<img
className={styles.taskInfoValueIcon}
src={jobFail}
alt=""
/>
)}
{state ? stateMap[state] : "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>源模板</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.specTitle || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>源模板版本</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.specVersion || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>花费(元)</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.jobCost || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>创建人</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.creator || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>创建时间</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.createTime || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>运行时间</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.costTime || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>日志文件</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.logPath && (
<>
{/* <span
className={styles.taskInfoDownload}
onClick={() => handleDownLoad(workFlowJobInfo?.logPath)}
>
下载
</span> */}
<span
className={styles.taskInfoDownload}
onClick={() => setShowLogView(true)}
>
查看
</span>
</>
)}
{!workFlowJobInfo?.logPath && "-"}
</div>
</div>
</div>
<TaskInfo
workFlowJobInfo={workFlowJobInfo as ITaskInfo}
randerOutputs1={randerOutputs1}
handleDownLoadOutput={handleDownLoadOutput}
handleShowPopper={handleShowPopper}
setGoToProjectDataPath={setGoToProjectDataPath}
setShowLogView={setShowLogView}
state={state}
name={name}
/>
)}
{activeFlowIndex && (
<div className={styles.suanziInfo}>
......@@ -778,12 +602,7 @@ const ProjectSubmitWork = observer(() => {
projectId={projectId as string}
></SeeDataset>
)}
{showLogView && (
<LogView
logs={logs}
setShowLogView={handleClose}
/>
)}
{showLogView && <LogView logs={logs} setShowLogView={handleClose} />}
</div>
);
});
......
......@@ -2,6 +2,9 @@ import { useMemo, useCallback, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import MyProgress from "@/components/mui/MyProgress";
import style from "./index.module.css";
import { useStores } from "@/store";
import { toJS } from "mobx";
import { observer } from "mobx-react-lite";
import runTime from "../../../../assets/project/runTime.svg";
import jobCostImg from "../../../../assets/project/jobCost.svg";
......@@ -38,6 +41,8 @@ const TaskCard = (props: TaskCardProps) => {
} = props;
const navigate = useNavigate();
const [displayTitleBlue, setDisplayTitleBlue] = useState<boolean>(false);
const { currentProjectStore } = useStores();
const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品ID
const randerOutputs = useMemo(() => {
if (outputs) {
......@@ -68,13 +73,13 @@ const TaskCard = (props: TaskCardProps) => {
path = path.slice(0, lastIndex);
}
path = path.slice(12);
navigate(`/product/cadd/projectData`, {
navigate(`/product/${productId || "cadd"}/projectData`, {
state: { pathName: path || "/", dataType: type },
});
};
// 跳转详情页
const gotoDetail = (id: string) => {
navigate(`/product/cadd/projectJobDetail`, {
navigate(`/product/${productId || "cadd"}/projectJobDetail`, {
state: { taskId: id, from: "projectOverview" },
});
};
......
......@@ -67,7 +67,9 @@
color: #1e2633;
margin-right: 8px;
}
.red{
color: rgba(255, 78, 78, 1);
}
.verticalLine {
height: 32px;
border-right: 1px solid #ebedf0;
......
......@@ -169,7 +169,10 @@ const ProjectOverview = observer(() => {
项目剩余预算
</div>
<div>
<span className={style.numberDisplay}>
<span className={classNames({
[style.numberDisplay]: true,
[style.red]:overviewInfo.projectRemainingBudget?.toFixed(2) < 100
})}>
{overviewInfo.projectRemainingBudget?.toFixed(2)}
</span>
......
......@@ -40,6 +40,7 @@ const BaseInfo = observer(() => {
const message = useMessage();
const { currentProjectStore } = useStores();
const fileToken = toJS(currentProjectStore.currentProjectInfo.filetoken);
const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品ID
const [projectInfo, setProjectInfo] = useState<any>({});
const [deleteProjectName, setDeleteProjectName] = useState("");
const [nameCheck, setNameCheck] = useState({
......@@ -258,7 +259,7 @@ const BaseInfo = observer(() => {
{
onSuccess: async (result: any) => {
message.success("修改成功");
const projectList = await getProjectList();
const projectList = await getProjectList(productId);
currentProjectStore.setProjectList(projectList);
projectInfo.filetoken = fileToken;
currentProjectStore.changeProject(projectInfo);
......@@ -272,7 +273,7 @@ const BaseInfo = observer(() => {
checkName(projectInfo.name, true) &&
checkBudget(projectInfo.projectBudget, true)
) {
updateProjectRun({ ...projectInfo, product: "cadd" });
updateProjectRun({ ...projectInfo, product: `${productId || "cadd"}` });
} else {
return;
}
......@@ -282,7 +283,7 @@ const BaseInfo = observer(() => {
onSuccess: async (result: any) => {
message.success("删除成功");
setDialogOpen(false);
const projectList = await getProjectList();
const projectList = await getProjectList(productId);
currentProjectStore.setProjectList(projectList);
// 项目删完了
currentProjectStore.changeProject({});
......
......@@ -9,15 +9,17 @@
import { toJS } from "mobx";
import { observer } from "mobx-react-lite";
import _ from "lodash";
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import { Box, OutlinedInput } from "@mui/material";
import { memo, useCallback, useEffect, useState } from "react";
import { Box } from "@mui/material";
import Dialog from "@/components/mui/MyDialog";
import useMyRequest from "@/hooks/useMyRequest";
import { useStores } from "@/store";
import { useMessage } from "@/components/MySnackbar";
import MyBorderlessSelect, { IOption } from "@/components/mui/MyBorderlessSelect";
import MyTable from "@/components/mui/MyTable";
import MyBorderlessSelect, {
IOption,
} from "@/components/mui/MyBorderlessSelect";
import MyTable from "@/components/mui/MyTableNew";
import SearchInput from "@/components/BusinessComponents/SearchInput";
import {
addProjectUser,
......@@ -35,7 +37,6 @@ const AddMember = observer((props: IProps) => {
const { addMemberDialog, setAddMemberDialog, getTableList } = props;
const { currentProjectStore } = useStores();
const [tableData, setTableData] = useState([]);
const [projectMember, setProjectMember] = useState("");
const [filterTableData, setFilterTableData] = useState([]);
......@@ -54,30 +55,29 @@ const AddMember = observer((props: IProps) => {
[tableData]
);
const columns = useMemo(() => {
return [
{ id: "checkbox", width: 50 },
{ id: "username", label: "项目成员", width: 160 },
{
id: "projectRole",
label: "项目权限",
width: 160,
render: (item: string, row: any, index: number) => {
const defaultValue = selectOptions.filter(
(every) => every.value === item
);
return (
<MyBorderlessSelect
value={defaultValue?.length ? defaultValue[0]?.value : "VIEWER"}
onChange={(val) => changePermission(val, index)}
options={selectOptions}
size="small"
/>
);
},
},
];
}, [changePermission, selectOptions]);
const columns = [
{ id: "username", label: "项目成员", width: 200 },
{
id: "projectRole",
label: "项目权限",
width: 100,
},
];
const randerRole = (item: any, index: number) => {
const defaultValue = selectOptions.filter(
(every) => every.value === item.projectRole
);
return (
<MyBorderlessSelect
value={defaultValue?.length ? defaultValue[0]?.value : "VIEWER"}
onChange={(val) => changePermission(val, index)}
options={selectOptions}
size="small"
sx={{ position: "relative", left: "-13px" }}
/>
);
};
/** 过滤表格数据 */
useEffect(() => {
......@@ -93,11 +93,14 @@ const AddMember = observer((props: IProps) => {
}, [projectMember, tableData]);
// 获取表格数据接口
const { run: getProjectUsersList } = useMyRequest(fetchProjectUsersList, {
onSuccess: (res: any) => {
setTableData(res?.data);
},
});
const { run: getProjectUsersList, loading } = useMyRequest(
fetchProjectUsersList,
{
onSuccess: (res: any) => {
setTableData(res?.data);
},
}
);
// 获取项目权限
const { run: getProjectPower } = useMyRequest(fetchProjectPower, {
......@@ -120,6 +123,7 @@ const AddMember = observer((props: IProps) => {
useEffect(() => {
if (addMemberDialog) {
setProjectMember("");
getProjectPower();
}
}, [addMemberDialog, getProjectPower]);
......@@ -173,23 +177,22 @@ const AddMember = observer((props: IProps) => {
placeholder="搜索项目成员"
sx={{ mb: 2 }}
/>
<div style={{ overflow: "overlay", maxHeight: 400 }}>
<div style={{ height: "320px" }}>
<MyTable
noDataText={
projectMember ? `暂无 "${projectMember}" 搜索结果` : undefined
}
tableContainerStyle={{ height: 346 }}
checkboxData={(val: string[]) => setCheckData(val)}
param="username"
disabledParam={"enabled"}
rowHover={true}
stickyHeader={true}
rows={filterTableData}
rowsPerPage="99"
tableKey="username"
hasCheckbox={true}
selectItems={checkData}
setSelectItems={setCheckData}
fixedHead={true}
rows={filterTableData.map((item: any, idnex) => ({
...item,
projectRole: randerRole(item, idnex),
}))}
headCells={columns}
footer={false}
tableStyle={{ minWidth: "auto" }}
borderBottom="none"
loading={loading}
/>
</div>
</Box>
......
.headerBox {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.removeItemBox {
color: #ff4e4e;
margin-left: 32px;
cursor: pointer;
color: #ff4e4e;
margin-left: 32px;
cursor: pointer;
}
.tableBox {
height: calc(100vh - 300px);
}
......@@ -7,15 +7,12 @@
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import _ from "lodash";
import OutlinedInput from "@mui/material/OutlinedInput";
import { Box } from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
import Add from "@mui/icons-material/Add";
import { toJS } from "mobx";
import { observer } from "mobx-react";
import MyTable from "@/components/mui/MyTable";
import MyTable from "@/components/mui/MyTableNew";
import { IResponse, useHttp } from "@/api/http";
import RemoveItem from "./components/RemoveItem";
import ChangePermission from "./components/ChangePermission";
......@@ -52,44 +49,44 @@ const ProjectMembers = observer(() => {
const [projectName, setProjectMember] = useState("");
/** 过滤后数据 */
const [filterTableData, setFilterTableData] = useState([]);
const [loading, setLoading] = useState(false);
const randerOperation = (item: any) => {
return item?.projectRole === "OWNER" ? null : (
<>
<span
style={{ color: "#1370FF", cursor: "pointer" }}
onClick={() => {
onPermissionBtn(item);
}}
>
更改权限
</span>
<span
className={styles.removeItemBox}
onClick={() => {
onRemoveItemBtn(item.username);
}}
>
移出项目
</span>
</>
);
};
const columns = useMemo(() => {
const val: any = [
{ id: "username", label: "成员名称" },
{ id: "projectRoleDesc", label: "项目权限" },
let val: any = [
{ id: "username", label: "成员名称", width: 200 },
{ id: "projectRoleDesc", label: "项目权限", width: 200 },
{ id: "phone", label: "联系方式" },
...(projectRole !== "OWNER"
? []
: [
{
id: "operation",
label: "操作",
width: 160,
render: (item: any, row: any) => {
return row?.projectRole === "OWNER" ? null : (
<>
<span
style={{ color: "#1370FF", cursor: "pointer" }}
onClick={() => {
onPermissionBtn(row);
}}
>
更改权限
</span>
<span
className={styles.removeItemBox}
onClick={() => {
onRemoveItemBtn(row.username);
}}
>
移出项目
</span>
</>
);
},
},
]),
];
if (projectRole === "OWNER") {
val.push({
id: "operation",
label: "操作",
width: 180,
});
}
return val;
}, [projectRole]);
......@@ -97,14 +94,19 @@ const ProjectMembers = observer(() => {
const getTableList = useCallback(() => {
const projectInfo = toJS(currentProjectStore?.currentProjectInfo);
if (!projectInfo?.id) return;
setLoading(true);
http
.get<IResponse<any>>("/cpp/project/get", {
params: { id: projectInfo?.id || "" },
})
.then((res) => {
setLoading(false);
const { data = {} } = res;
setTableData(data?.members || []);
setProjectRole(data?.projectRole || "");
})
.catch(() => {
setLoading(false);
});
}, [currentProjectStore?.currentProjectInfo, http]);
......@@ -142,12 +144,12 @@ const ProjectMembers = observer(() => {
projectRole: row?.projectRole || "",
});
};
// 回车搜索
// 回车搜索
const handleKeyWordChangeKeyUp = (e: any) => {
if (e.keyCode === 13) {
setProjectMember(e.target.value);
}
}
if (e.keyCode === 13) {
setProjectMember(e.target.value);
}
};
return (
<>
......@@ -159,7 +161,7 @@ const ProjectMembers = observer(() => {
/>
{currentProjectStore?.currentProjectInfo?.projectRole === "OWNER" ? (
<MyButton
text='添加成员'
text="添加成员"
style={{ backgroundColor: "#1370FF " }}
variant="contained"
onClick={onAddMember}
......@@ -168,16 +170,18 @@ const ProjectMembers = observer(() => {
/>
) : null}
</Box>
<MyTable
rowHover={true}
stickyHeader={true}
rows={filterTableData}
rowsPerPage={"99"}
headCells={columns}
footer={false}
tableStyle={{ minWidth: "auto" }}
borderBottom={"none"}
/>
<div className={styles.tableBox}>
<MyTable
fixedHead={true}
rows={filterTableData.map((item: any, index) => ({
...item,
operation: randerOperation(item),
}))}
tableKey="username"
headCells={columns}
loading={loading}
/>
</div>
<RemoveItem
removeDialog={removeDialog}
setRemoveDialog={setRemoveDialog}
......@@ -188,11 +192,13 @@ const ProjectMembers = observer(() => {
getTableList={getTableList}
setPermissionDialog={setPermissionDialog}
/>
<AddMember
addMemberDialog={addMemberDialog}
setAddMemberDialog={setAddMemberDialog}
getTableList={getTableList}
/>
{addMemberDialog && (
<AddMember
addMemberDialog={addMemberDialog}
setAddMemberDialog={setAddMemberDialog}
getTableList={getTableList}
/>
)}
</>
);
});
......
......@@ -7,6 +7,7 @@
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { memo, useMemo } from "react";
import { useLocation } from "react-router-dom";
import { Box } from "@mui/system";
import { useStores } from "@/store/index";
......@@ -20,6 +21,7 @@ import usePass from "@/hooks/usePass";
const ProjectSetting = observer(() => {
const { currentProjectStore } = useStores();
const isPass = usePass();
const location: any = useLocation();
const tabList = useMemo(() => {
return [
{
......@@ -54,7 +56,10 @@ const ProjectSetting = observer(() => {
</span>
</div>
<Box sx={{ width: "100%", typography: "body1" }}>
<Tabs tabList={tabList} />
<Tabs
tabList={tabList}
defaultValue={location?.state?.type || "projectMember"}
/>
</Box>
</div>
);
......
......@@ -34,6 +34,7 @@ const ProjectSubmitWork = observer(() => {
const Message = useMessage();
const { currentProjectStore } = useStores();
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品ID
const [templateConfigInfo, setTemplateConfigInfo] =
useState<ITemplateConfig>();
const location: any = useLocation();
......@@ -46,7 +47,7 @@ const ProjectSubmitWork = observer(() => {
// 前往工作台
const goToWorkbench = (toWorkbenchList = false) => {
navigate("/product/cadd/projectWorkbench", {
navigate(`/product/${productId || "cadd"}/projectWorkbench`, {
state: { type: toWorkbenchList ? "workbenchList" : "" },
});
};
......
......@@ -132,4 +132,4 @@ export interface ITaskInfo extends ITemplateConfig {
outputs?: any; // 结果文件
}
type IState = "SUCCEEDED" | "RUNNING" | "ABORTED" | "FAILED";
export type IState = "SUCCEEDED" | "RUNNING" | "ABORTED" | "FAILED";
......@@ -10,11 +10,13 @@ import { memo, useMemo } from "react";
import { Box } from "@mui/system";
import { observer } from "mobx-react-lite";
import { useLocation } from "react-router-dom";
import { useStores } from "@/store/index";
import WorkbenchTemplate from "./workbenchTemplate";
import WorkbenchList from "./workbenchList";
import Tabs from "@/components/mui/Tabs";
import usePass from "@/hooks/usePass";
import NoProject from "@/components/BusinessComponents/NoProject";
import Template from "@/assets/project/workbenchTemplate.svg";
import TemplateSelect from "@/assets/project/workbenchTemplate_select.svg";
import TemplateHover from "@/assets/project/workbenchTemplate_hover.svg";
......@@ -23,6 +25,7 @@ import ListHover from "@/assets/project/workbenchList_hover.svg";
import ListSelect from "@/assets/project/workbenchList_select.svg";
const ProjectWorkbench = observer(() => {
const { currentProjectStore } = useStores();
const isPass = usePass();
const location: any = useLocation();
......@@ -48,30 +51,33 @@ const ProjectWorkbench = observer(() => {
},
];
}, [isPass]);
return (
<div style={{ padding: "28px 24px 24px" }}>
<div style={{ display: "flex", alignItems: "center" }}>
<span
style={{
fontSize: "18px",
lineHeight: "26px",
fontWeight: "600",
color: "#1E2633",
marginBottom: "3px",
}}
>
工作台
</span>
if (currentProjectStore.currentProjectInfo.name) {
return (
<div style={{ padding: "28px 24px 24px" }}>
<div style={{ display: "flex", alignItems: "center" }}>
<span
style={{
fontSize: "18px",
lineHeight: "26px",
fontWeight: "600",
color: "#1E2633",
marginBottom: "3px",
}}
>
工作台
</span>
</div>
<Box sx={{ width: "100%", typography: "body1" }}>
<Tabs
tabList={tabList}
defaultValue={location?.state?.type || "workbenchTemplate"}
/>
</Box>
</div>
<Box sx={{ width: "100%", typography: "body1" }}>
<Tabs
tabList={tabList}
defaultValue={location?.state?.type || "workbenchTemplate"}
/>
</Box>
</div>
);
);
} else {
return <NoProject />;
}
});
export default memo(ProjectWorkbench);
......@@ -7,18 +7,15 @@
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { memo, useCallback, useEffect, useState } from "react";
import _ from "lodash";
import { useNavigate } from "react-router-dom";
import { Box, Typography } from "@mui/material";
import OutlinedInput from "@mui/material/OutlinedInput";
import { TablePagination } from "@mui/material";
import MyPagination from "@/components/mui/MyPagination";
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";
......@@ -77,6 +74,7 @@ const ProjectMembers = observer(() => {
const { currentProjectStore } = useStores();
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品ID
const isPass = usePass();
const [jobName, setJobName] = useState("");
const [jobList, setJobList] = useState([]);
......@@ -287,11 +285,11 @@ const ProjectMembers = observer(() => {
/** 点击每一行 */
const rowClick = useCallback(
(id: string) => {
navigate(`/product/cadd/projectJobDetail`, {
navigate(`/product/${productId || "cadd"}/projectJobDetail`, {
state: { taskId: id, from: "workbenchList" },
});
},
[navigate]
[navigate, productId]
);
// 回车搜索
......@@ -312,7 +310,8 @@ const ProjectMembers = observer(() => {
<SearchInput
onKeyUp={handleKeyWordChangeKeyUp}
onBlur={handleKeyWordChangeBlur}
sx={{ width: 340 }} />
sx={{ width: 340 }}
/>
{/* <Box className={styles.tabHeaderSelect}>
<TextField
select
......@@ -463,7 +462,7 @@ const ProjectMembers = observer(() => {
<Box className={styles.tabBoxJobOperate}>
{currentProjectStore.currentProjectInfo.projectRole ===
"USER" &&
item.creator !==
item.creator !==
JSON.parse(localStorage.getItem("userInfo") || "{}")
?.name ? (
""
......
......@@ -4,11 +4,9 @@ import classNames from "classnames";
import { Box, Typography } from "@mui/material";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import SearchIcon from "@mui/icons-material/Search";
import MyButton from "@/components/mui/MyButton";
import OutlinedInput from "@mui/material/OutlinedInput";
import MySwitch from "@/components/mui/MySwitch";
import FullScreenDrawer from "@/components/CommonComponents/FullScreenDrawer";
import Checkbox from "@mui/material/Checkbox";
import useMyRequest from "@/hooks/useMyRequest";
import AddIcon from "@mui/icons-material/Add";
import WorkFlowEdit from "@/views/WorkFlowEdit";
......
.content {
width: 400px;
font-size: 14px;
line-height: 22px;
color: rgba(30, 38, 51, 1);
}
import MyDialog from "@/components/mui/MyDialog";
import MyButton from "@/components/mui/MyButton";
import { DialogActions } from "@mui/material";
import style from "./index.module.css";
import { useStores } from "@/store";
import { observer } from "mobx-react-lite";
import { toJS } from "mobx";
import { useNavigate } from "react-router-dom";
const RemindBudgetDialog = observer((props: any) => {
const navigate = useNavigate();
const { rbOpen, rbClose, goToProjectSubmitWork, id, isParentUser, isOwner } =
props;
const { currentProjectStore } = useStores();
const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品ID
const goToprojectSetting = () => {
navigate(`/product/${productId || "cadd"}/projectSetting`, {
state: { type: "baseInfo" },
});
};
const footerRender = () => {
return (
<DialogActions style={{ padding: "16px 24px 16px 24px" }}>
<MyButton
text="继续使用"
onClick={() => goToProjectSubmitWork(id)}
variant="outlined"
color="secondary"
/>
{isParentUser && isOwner && (
<MyButton
text="添加预算"
onClick={() => goToprojectSetting()}
variant="contained"
style={{ marginLeft: "12px" }}
/>
)}
</DialogActions>
);
};
return (
<>
<MyDialog
open={rbOpen}
onClose={rbClose}
title="项目剩余预算不足提示"
footerRender={footerRender}
isText={true}
>
<div className={style.content}>
当前项目剩余预算不足100元,存在余额不足的风险,可能导致无法启动任务或中断运行中的任务,建议您先添加项目预算或联系项目所有者添加预算!
</div>
</MyDialog>
</>
);
});
export default RemindBudgetDialog;
......@@ -13,6 +13,7 @@ const SimpleDialog = (props: any) => {
onConfirm={onConfirm}
title={title}
okColor="error"
isText={true}
>
<Box>
<Typography sx={{ fontSize: "14px", fontWeight: "400" }}>
......
......@@ -6,113 +6,146 @@
* @FilePath: /bkunyun/src/views/Project/ProjectWorkbench/workbenchTemplate/components/templateBox.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { memo, useCallback } from "react";
import { memo, useCallback, useState } from "react";
import styles from "../index.module.css";
import { Box, Typography } from "@mui/material";
import MyButton from "@/components/mui/MyButton";
import usePass from "@/hooks/usePass";
import RemindBudgetDialog from "./RemindBudgetDialog";
import { useNavigate } from "react-router-dom";
import { toJS } from "mobx";
import { useStores } from "@/store";
import { observer } from "mobx-react-lite";
const TemplateBox = (props: any) => {
const TemplateBox = observer((props: any) => {
const info = props.data;
const { isParentUser, isOwner, greaterThan100 } = props;
const { currentProjectStore } = useStores();
const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品ID
const isPass = usePass();
const navigate = useNavigate();
const [rbOpen, setRbOpen] = useState(false);
const [id, setId] = useState("");
const addTemplateBlock = useCallback(
const goToProjectSubmitWork = useCallback(
(id: string) => {
navigate(`/product/cadd/projectSubmitWork`, {
navigate(`/product/${productId || "cadd"}/projectSubmitWork`, {
state: { id },
});
},
[navigate]
[navigate, productId]
);
const handleJudgeBudget = useCallback(
(id: string) => {
setId(id);
if (greaterThan100) {
goToProjectSubmitWork(id);
} else {
setRbOpen(true);
}
},
[goToProjectSubmitWork, setRbOpen, setId, greaterThan100]
);
return (
<Box className={styles.template}>
<Box className={styles.templateBlock}>
<Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography
<>
<Box className={styles.template}>
<Box className={styles.templateBlock}>
<Box>
<Box
sx={{
fontSize: "14px",
fontWeight: "600",
color: "#1E2633",
marginBottom: "4px",
overflow: "hidden",
textOverflow: "ellipsis",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
{info.title}
</Typography>
{info.creator !== "root" && (
<Box
<Typography
sx={{
fontSize: "14px",
fontWeight: "600",
color: "#1E2633",
marginBottom: "4px",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{info.title}
</Typography>
{info.creator !== "root" && (
<Box
sx={{
backgroundColor: "rgba(227, 250, 236, 1)",
color: "rgba(2, 171, 131, 1)",
lineHeight: "20px",
padding: "1px 9px",
fontSize: "12px",
}}
>
自定义
</Box>
)}
</Box>
<Box sx={{ display: "flex", marginBottom: "8px" }}>
<Typography
sx={{
backgroundColor: "rgba(227, 250, 236, 1)",
color: "rgba(2, 171, 131, 1)",
lineHeight: "20px",
padding: "1px 9px",
fontSize: "12px",
fontWeight: "400",
color: "#1370FF",
marginRight: "24px",
}}
>
自定义
</Box>
)}
</Box>
<Box sx={{ display: "flex", marginBottom: "8px" }}>
<Typography
sx={{
fontSize: "12px",
fontWeight: "400",
color: "#1370FF",
marginRight: "24px",
}}
>
版本:{info.version}
</Typography>
<Typography
sx={{ fontSize: "12px", fontWeight: "400", color: "#1370FF" }}
>
更新时间:{info.updatedTime}
版本:{info.version}
</Typography>
<Typography
sx={{ fontSize: "12px", fontWeight: "400", color: "#1370FF" }}
>
更新时间:{info.updatedTime}
</Typography>
</Box>
<Typography className={styles.templateDescText}>
{info.description ? info.description : "此模板暂无描述。"}
</Typography>
</Box>
<Typography className={styles.templateDescText}>
{info.description ? info.description : "此模板暂无描述。"}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "end",
}}
>
{isPass("PROJECT_WORKBENCH_FLOES_USE", "MANAGER") && (
<MyButton
size="medium"
text="删除模版"
onClick={() => {
props.startDialog(info.id);
}}
style={{ backgroundColor: "#F0F2F5", color: "#565C66" }}
/>
)}
{isPass("PROJECT_WORKBENCH_FLOES_USE", "USER") && (
<MyButton
size="medium"
text="使用模版"
onClick={() => addTemplateBlock(info.id)}
style={{ marginLeft: "12px" }}
/>
)}
<Box
sx={{
display: "flex",
justifyContent: "end",
}}
>
{isPass("PROJECT_WORKBENCH_FLOES_USE", "MANAGER") && (
<MyButton
size="medium"
text="删除模版"
onClick={() => {
props.startDialog(info.id);
}}
style={{ backgroundColor: "#F0F2F5", color: "#565C66" }}
/>
)}
{isPass("PROJECT_WORKBENCH_FLOES_USE", "USER") && (
<MyButton
size="medium"
text="使用模版"
onClick={() => handleJudgeBudget(info.id)}
style={{ marginLeft: "12px" }}
/>
)}
</Box>
</Box>
</Box>
</Box>
{rbOpen && (
<RemindBudgetDialog
rbOpen={rbOpen}
rbClose={() => setRbOpen(false)}
id={id}
goToProjectSubmitWork={goToProjectSubmitWork}
isParentUser={isParentUser}
isOwner={isOwner}
></RemindBudgetDialog>
)}
</>
);
};
});
export default memo(TemplateBox);
......@@ -10,8 +10,8 @@ import { memo, useEffect, useState } from "react";
import { Box, Typography } from "@mui/material";
import { toJS } from "mobx";
import { observer } from "mobx-react-lite";
import FormatListBulletedRoundedIcon from '@mui/icons-material/FormatListBulletedRounded';
import FormatListBulletedRoundedIcon from "@mui/icons-material/FormatListBulletedRounded";
import { getLoaclStorageOfKey } from "@/api/fileserver/utils";
import MyButton from "@/components/mui/MyButton";
import SearchInput from "@/components/BusinessComponents/SearchInput";
......@@ -24,11 +24,15 @@ import {
getWorkbenchTemplate,
deleteWorkbenchTemplate,
} from "@/api/workbench_api";
import { getOverviewInfo, getProject } from "@/api/project_api";
import usePass from "@/hooks/usePass";
import { useStores } from "@/store";
import styles from "./index.module.css";
const userInfo = getLoaclStorageOfKey("userInfo");
const ProjectMembers = observer(() => {
const { currentProjectStore } = useStores();
const projectIdData = toJS(currentProjectStore.currentProjectInfo.id);
......@@ -109,6 +113,49 @@ const ProjectMembers = observer(() => {
}
};
// 项目剩余预算是否大于100 Greater than 100
const [greaterThan100, setGreaterThan100] = useState(false);
// 获取概览基本信息 用于获取项目剩余预算 projectRemainingBudget
const { run: getOverview } = useMyRequest(getOverviewInfo, {
onSuccess: (result: any) => {
if (result.data.projectRemainingBudget > 100) {
setGreaterThan100(true);
} else {
setGreaterThan100(false);
}
},
});
useEffect(() => {
if (currentProjectStore.currentProjectInfo.id) {
getOverview({
id: currentProjectStore.currentProjectInfo.id as string,
});
}
}, [currentProjectStore.currentProjectInfo.id, getOverview]);
// 用户是否为父用户
const [isParentUser] = useState(!userInfo.parent ? true : false);
// 当前用户是否为项目的所有者
const [isOwner, setIsOwner] = useState(false);
const { run: getProjectFn } = useMyRequest(getProject, {
onSuccess: (result: any) => {
if (result.data.projectRole === "OWNER") {
setIsOwner(true);
} else {
setIsOwner(false);
}
},
});
useEffect(() => {
getProjectFn({
id: currentProjectStore.currentProjectInfo.id as string,
});
}, [currentProjectStore.currentProjectInfo.id, getProjectFn]);
return (
<Box className={styles.headerBox}>
<Box className={styles.tabBox}>
......@@ -116,7 +163,7 @@ const ProjectMembers = observer(() => {
{isPass("PROJECT_WORKBENCH_FLOES_ADD", "MANAGER") && (
<MyButton
text={"管理工作流模板"}
startIcon={<FormatListBulletedRoundedIcon fontSize="small"/>}
startIcon={<FormatListBulletedRoundedIcon fontSize="small" />}
onClick={addTemplateBlock}
size={"medium"}
/>
......@@ -147,7 +194,14 @@ const ProjectMembers = observer(() => {
templateList.length > 0 &&
templateList.map((item, key) => {
return (
<TemplateBox key={key} data={item} startDialog={startDialog} />
<TemplateBox
key={key}
data={item}
startDialog={startDialog}
isParentUser={isParentUser}
isOwner={isOwner}
greaterThan100={greaterThan100}
/>
);
})}
</Box>
......
......@@ -10,6 +10,8 @@ import { useMessage } from "@/components/MySnackbar";
import { getProjectList } from "../../project";
import { useStores } from "@/store";
import { checkIsNumberLetterChinese } from "@/utils/util";
import { observer } from "mobx-react-lite";
import { toJS } from "mobx";
import {
setFileServerEndPointLocalStorage,
getFiletokenAccordingToId,
......@@ -27,12 +29,13 @@ type IAddProjectProps = {
setAddOpen: any;
};
const AddProject = (props: IAddProjectProps) => {
const AddProject = observer((props: IAddProjectProps) => {
const { addOpen, setAddOpen } = props;
const { currentProjectStore } = useStores();
const navigate = useNavigate();
const message = useMessage();
const [name, setName] = useState("");
const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品ID
const [nameCheck, setNameCheck] = useState({
error: false,
help: "",
......@@ -62,7 +65,7 @@ const AddProject = (props: IAddProjectProps) => {
setAddOpen(false);
setLoading(false);
message.success("新建项目成功");
const projectList = await getProjectList();
const projectList = await getProjectList(productId);
currentProjectStore.setProjectList(projectList);
let project: any = {};
projectList.forEach((item: any) => {
......@@ -75,7 +78,7 @@ const AddProject = (props: IAddProjectProps) => {
project.filetoken = res;
currentProjectStore.changeProject(project);
});
navigate(`/product/cadd/projectOverview`);
navigate(`/product/${productId || "cadd"}/projectOverview`);
}
},
onError: () => {
......@@ -157,7 +160,7 @@ const AddProject = (props: IAddProjectProps) => {
name,
desc,
zoneId,
product: "cadd",
product: productId || "cadd",
});
} else {
return;
......@@ -232,6 +235,6 @@ const AddProject = (props: IAddProjectProps) => {
</div>
</MyDialog>
);
};
});
export default AddProject;
......@@ -12,8 +12,8 @@ import {
getDataFileToken,
} from "@/api/project_api";
export const getProjectList = async () => {
const res = await getProjectListApi({ product: "cadd" });
export const getProjectList = async (id = 'cadd') => {
const res = await getProjectListApi({ product: id });
return res.data;
};
......
......@@ -64,7 +64,7 @@ const SaveCustomTemplate = (props: IProps) => {
});
// 自定义模板保存方法
const { run: saveUserSpecRun } = useMyRequest(saveUserSpec, {
const { run: saveUserSpecRun, loading } = useMyRequest(saveUserSpec, {
onSuccess: (res) => {
Message.success("保存成功!");
onBack && onBack();
......@@ -220,6 +220,7 @@ const SaveCustomTemplate = (props: IProps) => {
title="保存自定义模板"
onClose={handleCloseDialog}
onConfirm={handleOncofirm}
loading={loading}
>
<div className={styles.saveBox}>
<MyInput
......
......@@ -117,27 +117,26 @@ const MyTableDemo = () => {
{
id: "a",
label: "属性a",
width: "150",
width: 150,
},
{
id: "b",
label: "属性b",
width: "250",
width: 150,
},
{
id: "c",
label: "属性c",
width: "350",
width: 150,
},
{
id: "d",
label: "属性d",
width: "250",
},
{
id: "caozuo",
label: "操作",
width: "250",
width: 150,
},
];
......@@ -145,13 +144,13 @@ const MyTableDemo = () => {
{
id: "a",
label: "属性a",
width: "200",
width: 200,
showOverflowTooltip: true,
},
{
id: "b",
label: "属性b",
width: "200",
width: 200,
},
{
id: "c",
......@@ -161,7 +160,7 @@ const MyTableDemo = () => {
{
id: "d",
label: "属性d",
width: "200",
width: 200,
},
];
......@@ -169,24 +168,23 @@ const MyTableDemo = () => {
{
id: "a",
label: "属性a",
width: "25%",
width: 200,
sort: true,
},
{
id: "b",
label: "属性b",
width: "25%",
width: 200,
sort: true,
},
{
id: "c",
label: "属性c",
width: "25%",
width: 200,
},
{
id: "d",
label: "属性d",
width: "25%",
},
];
......
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