Commit 387dff16 authored by chenshouchao's avatar chenshouchao

feat: 迭代优化、预算不足提醒

parent 76f010d7
...@@ -7,6 +7,7 @@ import { ...@@ -7,6 +7,7 @@ import {
DialogTitle, DialogTitle,
} from "@mui/material"; } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
import { ThemeProvider, createTheme } from "@mui/material/styles";
import MyButton from "./MyButton"; import MyButton from "./MyButton";
...@@ -51,8 +52,27 @@ export interface IDialogProps { ...@@ -51,8 +52,27 @@ export interface IDialogProps {
| "info" | "info"
| "warning"; //按钮颜色风格 | "warning"; //按钮颜色风格
loading?: boolean; // 确认按钮是否处于loading状态 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 MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
const { const {
title, title,
...@@ -74,6 +94,7 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => { ...@@ -74,6 +94,7 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
clickMaskClose = false, clickMaskClose = false,
loading = false, loading = false,
okColor = "primary", okColor = "primary",
isText = false,
} = props; } = props;
const handelClose = ( const handelClose = (
...@@ -91,7 +112,7 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => { ...@@ -91,7 +112,7 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
return footerRender ? ( return footerRender ? (
footerRender() footerRender()
) : ( ) : (
<DialogActions style={{ padding: "0 24px 16px 24px" }}> <DialogActions style={{ padding: "16px 24px 16px 24px" }}>
{showCancel ? ( {showCancel ? (
<MyButton <MyButton
text={cancelText || "取消"} text={cancelText || "取消"}
...@@ -127,7 +148,16 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => { ...@@ -127,7 +148,16 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
loading, loading,
showConfirm, showConfirm,
]); ]);
const contentPadding = useMemo(() => {
if (isText) {
return "8px 24px 24px"; // 文本
} else {
return "8px 24px 12px"; // 表单
}
}, [isText]);
return ( return (
<ThemeProvider theme={theme}>
<Dialog <Dialog
open={open} open={open}
onClose={handelClose} onClose={handelClose}
...@@ -172,9 +202,12 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => { ...@@ -172,9 +202,12 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
</div> </div>
</DialogTitle> </DialogTitle>
)} )}
<DialogContent style={{ minWidth: 388 }}>{children}</DialogContent> <DialogContent style={{ minWidth: 388, padding: contentPadding }}>
{children}
</DialogContent>
{Footer} {Footer}
</Dialog> </Dialog>
</ThemeProvider>
); );
}; };
......
...@@ -110,7 +110,7 @@ const AddFolder = (props: IAddFolderProps) => { ...@@ -110,7 +110,7 @@ const AddFolder = (props: IAddFolderProps) => {
onConfirm={handleAddSubmit} onConfirm={handleAddSubmit}
title="新建文件夹" title="新建文件夹"
> >
<div style={{ padding: "12px 0" }}> <div>
<MyInput <MyInput
sx={{ sx={{
width: "388px", width: "388px",
...@@ -125,7 +125,12 @@ const AddFolder = (props: IAddFolderProps) => { ...@@ -125,7 +125,12 @@ const AddFolder = (props: IAddFolderProps) => {
helperText={fileNameCheck.help} helperText={fileNameCheck.help}
InputProps={{ InputProps={{
endAdornment: ( endAdornment: (
<InputAdornment position="end" style={{ color: fileName.length >= 30 ? "#d32f2f" : "#C2C6CC" }}> <InputAdornment
position="end"
style={{
color: fileName.length >= 30 ? "#d32f2f" : "#C2C6CC",
}}
>
{fileName.length}/30 {fileName.length}/30
</InputAdornment> </InputAdornment>
), ),
......
...@@ -90,6 +90,7 @@ const DeleteDialog = (props: IDeleteFileProps) => { ...@@ -90,6 +90,7 @@ const DeleteDialog = (props: IDeleteFileProps) => {
onClose={() => setDeleteDialogOpen(false)} onClose={() => setDeleteDialogOpen(false)}
onConfirm={handleSubmit} onConfirm={handleSubmit}
okColor="error" okColor="error"
isText={true}
> >
{currentOperateFile {currentOperateFile
? "确认删除该数据吗?" ? "确认删除该数据吗?"
......
...@@ -67,7 +67,9 @@ ...@@ -67,7 +67,9 @@
color: #1e2633; color: #1e2633;
margin-right: 8px; margin-right: 8px;
} }
.red{
color: rgba(255, 78, 78, 1);
}
.verticalLine { .verticalLine {
height: 32px; height: 32px;
border-right: 1px solid #ebedf0; border-right: 1px solid #ebedf0;
......
...@@ -169,7 +169,10 @@ const ProjectOverview = observer(() => { ...@@ -169,7 +169,10 @@ const ProjectOverview = observer(() => {
项目剩余预算 项目剩余预算
</div> </div>
<div> <div>
<span className={style.numberDisplay}> <span className={classNames({
[style.numberDisplay]: true,
[style.red]:overviewInfo.projectRemainingBudget?.toFixed(2) < 100
})}>
{overviewInfo.projectRemainingBudget?.toFixed(2)} {overviewInfo.projectRemainingBudget?.toFixed(2)}
</span> </span>
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
import { memo, useMemo } from "react"; import { memo, useMemo } from "react";
import { useLocation } from "react-router-dom";
import { Box } from "@mui/system"; import { Box } from "@mui/system";
import { useStores } from "@/store/index"; import { useStores } from "@/store/index";
...@@ -20,6 +21,7 @@ import usePass from "@/hooks/usePass"; ...@@ -20,6 +21,7 @@ import usePass from "@/hooks/usePass";
const ProjectSetting = observer(() => { const ProjectSetting = observer(() => {
const { currentProjectStore } = useStores(); const { currentProjectStore } = useStores();
const isPass = usePass(); const isPass = usePass();
const location: any = useLocation();
const tabList = useMemo(() => { const tabList = useMemo(() => {
return [ return [
{ {
...@@ -54,7 +56,10 @@ const ProjectSetting = observer(() => { ...@@ -54,7 +56,10 @@ const ProjectSetting = observer(() => {
</span> </span>
</div> </div>
<Box sx={{ width: "100%", typography: "body1" }}> <Box sx={{ width: "100%", typography: "body1" }}>
<Tabs tabList={tabList} /> <Tabs
tabList={tabList}
defaultValue={location?.state?.type || "projectMember"}
/>
</Box> </Box>
</div> </div>
); );
......
...@@ -4,11 +4,9 @@ import classNames from "classnames"; ...@@ -4,11 +4,9 @@ import classNames from "classnames";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle"; import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import MyButton from "@/components/mui/MyButton";
import OutlinedInput from "@mui/material/OutlinedInput"; import OutlinedInput from "@mui/material/OutlinedInput";
import MySwitch from "@/components/mui/MySwitch"; import MySwitch from "@/components/mui/MySwitch";
import FullScreenDrawer from "@/components/CommonComponents/FullScreenDrawer"; import FullScreenDrawer from "@/components/CommonComponents/FullScreenDrawer";
import Checkbox from "@mui/material/Checkbox";
import useMyRequest from "@/hooks/useMyRequest"; import useMyRequest from "@/hooks/useMyRequest";
import AddIcon from "@mui/icons-material/Add"; import AddIcon from "@mui/icons-material/Add";
import WorkFlowEdit from "@/views/WorkFlowEdit"; 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 { useNavigate } from "react-router-dom";
const RemindBudgetDialog = (props: any) => {
const navigate = useNavigate();
const { rbOpen, rbClose, goToProjectSubmitWork, id, isParentUser, isOwner } =
props;
const goToprojectSetting = () => {
navigate(`/product/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) => { ...@@ -13,6 +13,7 @@ const SimpleDialog = (props: any) => {
onConfirm={onConfirm} onConfirm={onConfirm}
title={title} title={title}
okColor="error" okColor="error"
isText={true}
> >
<Box> <Box>
<Typography sx={{ fontSize: "14px", fontWeight: "400" }}> <Typography sx={{ fontSize: "14px", fontWeight: "400" }}>
......
...@@ -6,19 +6,23 @@ ...@@ -6,19 +6,23 @@
* @FilePath: /bkunyun/src/views/Project/ProjectWorkbench/workbenchTemplate/components/templateBox.tsx * @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 * @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 styles from "../index.module.css";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import MyButton from "@/components/mui/MyButton"; import MyButton from "@/components/mui/MyButton";
import usePass from "@/hooks/usePass"; import usePass from "@/hooks/usePass";
import RemindBudgetDialog from "./RemindBudgetDialog.tsx";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
const TemplateBox = (props: any) => { const TemplateBox = (props: any) => {
const info = props.data; const info = props.data;
const { isParentUser, isOwner, greaterThan100 } = props;
const isPass = usePass(); const isPass = usePass();
const navigate = useNavigate(); const navigate = useNavigate();
const [rbOpen, setRbOpen] = useState(false);
const [id, setId] = useState("");
const addTemplateBlock = useCallback( const goToProjectSubmitWork = useCallback(
(id: string) => { (id: string) => {
navigate(`/product/cadd/projectSubmitWork`, { navigate(`/product/cadd/projectSubmitWork`, {
state: { id }, state: { id },
...@@ -27,7 +31,20 @@ const TemplateBox = (props: any) => { ...@@ -27,7 +31,20 @@ const TemplateBox = (props: any) => {
[navigate] [navigate]
); );
const handleJudgeBudget = useCallback(
(id: string) => {
setId(id);
if (!greaterThan100) {
goToProjectSubmitWork(id);
} else {
setRbOpen(true);
}
},
[goToProjectSubmitWork, setRbOpen, setId, greaterThan100]
);
return ( return (
<>
<Box className={styles.template}> <Box className={styles.template}>
<Box className={styles.templateBlock}> <Box className={styles.templateBlock}>
<Box> <Box>
...@@ -105,13 +122,24 @@ const TemplateBox = (props: any) => { ...@@ -105,13 +122,24 @@ const TemplateBox = (props: any) => {
<MyButton <MyButton
size="medium" size="medium"
text="使用模版" text="使用模版"
onClick={() => addTemplateBlock(info.id)} onClick={() => handleJudgeBudget(info.id)}
style={{ marginLeft: "12px" }} style={{ marginLeft: "12px" }}
/> />
)} )}
</Box> </Box>
</Box> </Box>
</Box> </Box>
{rbOpen && (
<RemindBudgetDialog
rbOpen={rbOpen}
rbClose={() => setRbOpen(false)}
id={id}
goToProjectSubmitWork={goToProjectSubmitWork}
isParentUser={isParentUser}
isOwner={isOwner}
></RemindBudgetDialog>
)}
</>
); );
}; };
......
...@@ -10,8 +10,8 @@ import { memo, useEffect, useState } from "react"; ...@@ -10,8 +10,8 @@ import { memo, useEffect, useState } from "react";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import { toJS } from "mobx"; import { toJS } from "mobx";
import { observer } from "mobx-react-lite"; 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 MyButton from "@/components/mui/MyButton";
import SearchInput from "@/components/BusinessComponents/SearchInput"; import SearchInput from "@/components/BusinessComponents/SearchInput";
...@@ -24,11 +24,15 @@ import { ...@@ -24,11 +24,15 @@ import {
getWorkbenchTemplate, getWorkbenchTemplate,
deleteWorkbenchTemplate, deleteWorkbenchTemplate,
} from "@/api/workbench_api"; } from "@/api/workbench_api";
import { getOverviewInfo, getProject } from "@/api/project_api";
import usePass from "@/hooks/usePass"; import usePass from "@/hooks/usePass";
import { useStores } from "@/store"; import { useStores } from "@/store";
import styles from "./index.module.css"; import styles from "./index.module.css";
const userInfo = getLoaclStorageOfKey("userInfo");
const ProjectMembers = observer(() => { const ProjectMembers = observer(() => {
const { currentProjectStore } = useStores(); const { currentProjectStore } = useStores();
const projectIdData = toJS(currentProjectStore.currentProjectInfo.id); const projectIdData = toJS(currentProjectStore.currentProjectInfo.id);
...@@ -109,6 +113,49 @@ const ProjectMembers = observer(() => { ...@@ -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 ( return (
<Box className={styles.headerBox}> <Box className={styles.headerBox}>
<Box className={styles.tabBox}> <Box className={styles.tabBox}>
...@@ -116,7 +163,7 @@ const ProjectMembers = observer(() => { ...@@ -116,7 +163,7 @@ const ProjectMembers = observer(() => {
{isPass("PROJECT_WORKBENCH_FLOES_ADD", "MANAGER") && ( {isPass("PROJECT_WORKBENCH_FLOES_ADD", "MANAGER") && (
<MyButton <MyButton
text={"管理工作流模板"} text={"管理工作流模板"}
startIcon={<FormatListBulletedRoundedIcon fontSize="small"/>} startIcon={<FormatListBulletedRoundedIcon fontSize="small" />}
onClick={addTemplateBlock} onClick={addTemplateBlock}
size={"medium"} size={"medium"}
/> />
...@@ -147,7 +194,14 @@ const ProjectMembers = observer(() => { ...@@ -147,7 +194,14 @@ const ProjectMembers = observer(() => {
templateList.length > 0 && templateList.length > 0 &&
templateList.map((item, key) => { templateList.map((item, key) => {
return ( return (
<TemplateBox key={key} data={item} startDialog={startDialog} /> <TemplateBox
key={key}
data={item}
startDialog={startDialog}
isParentUser={isParentUser}
isOwner={isOwner}
greaterThan100={greaterThan100}
/>
); );
})} })}
</Box> </Box>
......
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