feat: 添加删除全部modal的方法
This commit is contained in:
parent
b138b3f241
commit
e2cfc94482
|
@ -17,6 +17,7 @@ export enum ModelDeploymentStatus {
|
||||||
Running = 'Running', // 运行中
|
Running = 'Running', // 运行中
|
||||||
Stopped = 'Stopped', // 已停止
|
Stopped = 'Stopped', // 已停止
|
||||||
Failed = 'Failed', // 失败
|
Failed = 'Failed', // 失败
|
||||||
|
Pending = 'Pending', // 挂起中
|
||||||
}
|
}
|
||||||
|
|
||||||
export const modelDeploymentStatusOptions = [
|
export const modelDeploymentStatusOptions = [
|
||||||
|
@ -25,4 +26,5 @@ export const modelDeploymentStatusOptions = [
|
||||||
{ label: '运行中', value: ModelDeploymentStatus.Running },
|
{ label: '运行中', value: ModelDeploymentStatus.Running },
|
||||||
{ label: '已停止', value: ModelDeploymentStatus.Stopped },
|
{ label: '已停止', value: ModelDeploymentStatus.Stopped },
|
||||||
{ label: '失败', value: ModelDeploymentStatus.Failed },
|
{ label: '失败', value: ModelDeploymentStatus.Failed },
|
||||||
|
{ label: '挂起中', value: ModelDeploymentStatus.Pending },
|
||||||
];
|
];
|
||||||
|
|
|
@ -126,13 +126,3 @@ export const useResetFormOnCloseModal = (form: FormInstance, open: boolean) => {
|
||||||
}
|
}
|
||||||
}, [form, prevOpen, open]);
|
}, [form, prevOpen, open]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useInputModel = <T>(initialValue: T) => {
|
|
||||||
const [value, setValue] = useState<T>(initialValue);
|
|
||||||
|
|
||||||
const updateValue = useCallback((e: any) => {
|
|
||||||
setValue(e.target?.value);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return [value, updateValue];
|
|
||||||
};
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { to } from '@/utils/promise';
|
||||||
import { type SelectProps } from 'antd';
|
import { type SelectProps } from 'antd';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
// 获取资源规格
|
||||||
export function useComputingResource() {
|
export function useComputingResource() {
|
||||||
const [resourceStandardList, setResourceStandardList] = useState<ComputingResource[]>([]);
|
const [resourceStandardList, setResourceStandardList] = useState<ComputingResource[]>([]);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { getSessionStorageItem, removeSessionStorageItem } from '@/utils/sessionStorage';
|
import { getSessionStorageItem, removeSessionStorageItem } from '@/utils/sessionStorage';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
// 获取缓存数据
|
||||||
export function useSessionStorage<T>(key: string, isObject: boolean, initialValue: T) {
|
export function useSessionStorage<T>(key: string, isObject: boolean, initialValue: T) {
|
||||||
const [storage, setStorage] = useState<T>(initialValue);
|
const [storage, setStorage] = useState<T>(initialValue);
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,11 @@ function AddExperimentModal({
|
||||||
wrapperCol: { span: 20 },
|
wrapperCol: { span: 20 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const paramLayout = {
|
||||||
|
labelCol: { span: 8 },
|
||||||
|
wrapperCol: { span: 16 },
|
||||||
|
};
|
||||||
|
|
||||||
// 除了流水线选择发生变化
|
// 除了流水线选择发生变化
|
||||||
const handleWorkflowChange = (id: string | number) => {
|
const handleWorkflowChange = (id: string | number) => {
|
||||||
const pipeline: Workflow | undefined = workflowList.find((v) => v.id === id);
|
const pipeline: Workflow | undefined = workflowList.find((v) => v.id === id);
|
||||||
|
@ -187,7 +192,7 @@ function AddExperimentModal({
|
||||||
fields.map(({ key, name, ...restField }) => (
|
fields.map(({ key, name, ...restField }) => (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
{...restField}
|
{...restField}
|
||||||
{...layout}
|
{...paramLayout}
|
||||||
key={key}
|
key={key}
|
||||||
label={getParamType(globalParam[name])}
|
label={getParamType(globalParam[name])}
|
||||||
name={[name, 'param_value']}
|
name={[name, 'param_value']}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import SubAreaTitle from '@/components/SubAreaTitle';
|
import SubAreaTitle from '@/components/SubAreaTitle';
|
||||||
import { getComputingResourceReq } from '@/services/pipeline';
|
import { useComputingResource } from '@/hooks/resource';
|
||||||
import { PipelineNodeModelSerialize } from '@/types';
|
import { PipelineNodeModelSerialize } from '@/types';
|
||||||
import { to } from '@/utils/promise';
|
|
||||||
import { Form, Input, Select, type FormProps } from 'antd';
|
import { Form, Input, Select, type FormProps } from 'antd';
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
||||||
|
@ -13,24 +11,7 @@ type ExperimentParameterProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function ExperimentParameter({ form, nodeData }: ExperimentParameterProps) {
|
function ExperimentParameter({ form, nodeData }: ExperimentParameterProps) {
|
||||||
const [resourceStandardList, setResourceStandardList] = useState([]); // 资源规模列表
|
const [resourceStandardList] = useComputingResource(); // 资源规模
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getComputingResource();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 获取资源规格列表数据
|
|
||||||
const getComputingResource = async () => {
|
|
||||||
const params = {
|
|
||||||
page: 0,
|
|
||||||
size: 1000,
|
|
||||||
resource_type: '',
|
|
||||||
};
|
|
||||||
const [res] = await to(getComputingResourceReq(params));
|
|
||||||
if (res && res.data && res.data.content) {
|
|
||||||
setResourceStandardList(res.data.content);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 控制策略
|
// 控制策略
|
||||||
const controlStrategyList = Object.entries(nodeData.control_strategy ?? {}).map(
|
const controlStrategyList = Object.entries(nodeData.control_strategy ?? {}).map(
|
||||||
|
|
|
@ -18,7 +18,7 @@ export enum ExperimentStatus {
|
||||||
export const experimentStatusInfo: Record<ExperimentStatus, StatusInfo | undefined> = {
|
export const experimentStatusInfo: Record<ExperimentStatus, StatusInfo | undefined> = {
|
||||||
Running: {
|
Running: {
|
||||||
label: '运行中',
|
label: '运行中',
|
||||||
color: '#165bff',
|
color: '#1664ff',
|
||||||
icon: '/assets/images/running-icon.png',
|
icon: '/assets/images/running-icon.png',
|
||||||
},
|
},
|
||||||
Succeeded: {
|
Succeeded: {
|
||||||
|
@ -53,7 +53,7 @@ export const experimentStatusInfo: Record<ExperimentStatus, StatusInfo | undefin
|
||||||
},
|
},
|
||||||
Omitted: {
|
Omitted: {
|
||||||
label: '未执行',
|
label: '未执行',
|
||||||
color: '#8a8a8ae',
|
color: '#8a8a8a',
|
||||||
icon: '/assets/images/omitted-icon.png',
|
icon: '/assets/images/omitted-icon.png',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -174,13 +174,14 @@ function MirrorList() {
|
||||||
title: '版本数据',
|
title: '版本数据',
|
||||||
dataIndex: 'version_count',
|
dataIndex: 'version_count',
|
||||||
key: 'version_count',
|
key: 'version_count',
|
||||||
width: 100,
|
width: '15%',
|
||||||
render: CommonTableCell(),
|
render: CommonTableCell(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '镜像描述',
|
title: '镜像描述',
|
||||||
dataIndex: 'description',
|
dataIndex: 'description',
|
||||||
key: 'description',
|
key: 'description',
|
||||||
|
width: '35%',
|
||||||
render: CommonTableCell(true),
|
render: CommonTableCell(true),
|
||||||
ellipsis: { showTitle: false },
|
ellipsis: { showTitle: false },
|
||||||
},
|
},
|
||||||
|
@ -188,7 +189,7 @@ function MirrorList() {
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
dataIndex: 'create_time',
|
dataIndex: 'create_time',
|
||||||
key: 'create_time',
|
key: 'create_time',
|
||||||
width: 200,
|
width: '20%',
|
||||||
render: DateTableCell,
|
render: DateTableCell,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @Author: 赵伟
|
* @Author: 赵伟
|
||||||
* @Date: 2024-04-18 18:35:41
|
* @Date: 2024-04-18 18:35:41
|
||||||
* @Description:
|
* @Description: 镜像状态组件
|
||||||
*/
|
*/
|
||||||
import { MirrorVersionStatus } from '@/enums';
|
import { MirrorVersionStatus } from '@/enums';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
@ -26,7 +26,7 @@ const statusInfo: Record<MirrorVersionStatus, MirrorVersionStatusInfo> = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function MirrorStatusCell(status: MirrorVersionStatus) {
|
function MirrorStatusCell(status?: MirrorVersionStatus | null) {
|
||||||
if (status === null || status === undefined || !statusInfo[status]) {
|
if (status === null || status === undefined || !statusInfo[status]) {
|
||||||
return <span>--</span>;
|
return <span>--</span>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ function ModelDeploymentInfo() {
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={10}>
|
<Col span={10}>
|
||||||
<div className={styles['model-deployment-info__basic__item']}>
|
<div className={styles['model-deployment-info__basic__item']}>
|
||||||
<div className={styles['label']}>资源规格</div>
|
<div className={styles['label']}>资源规格:</div>
|
||||||
<div className={styles['value']}>
|
<div className={styles['value']}>
|
||||||
{modelDeployementInfo?.resource
|
{modelDeployementInfo?.resource
|
||||||
? getResourceDescription(modelDeployementInfo.resource)
|
? getResourceDescription(modelDeployementInfo.resource)
|
||||||
|
@ -174,7 +174,7 @@ function ModelDeploymentInfo() {
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row gutter={40}>
|
<Row gutter={40}>
|
||||||
<Col span={24}>
|
<Col span={18}>
|
||||||
<div className={styles['model-deployment-info__basic__item']}>
|
<div className={styles['model-deployment-info__basic__item']}>
|
||||||
<div className={styles['label']}>描 述:</div>
|
<div className={styles['label']}>描 述:</div>
|
||||||
<div className={styles['value']}>{modelDeployementInfo?.description ?? '--'}</div>
|
<div className={styles['value']}>{modelDeployementInfo?.description ?? '--'}</div>
|
||||||
|
|
|
@ -249,7 +249,8 @@ function ModelDeployment() {
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{(record.status === ModelDeploymentStatus.Running ||
|
{(record.status === ModelDeploymentStatus.Running ||
|
||||||
record.status === ModelDeploymentStatus.Init) && (
|
record.status === ModelDeploymentStatus.Init ||
|
||||||
|
record.status === ModelDeploymentStatus.Pending) && (
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
@ -6,10 +6,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&--stopped {
|
&--stopped {
|
||||||
color: @warning-color;
|
color: @abort-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--error {
|
&--error {
|
||||||
color: @error-color;
|
color: @error-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--pending {
|
||||||
|
color: @warning-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,13 @@ export const statusInfo: Record<ModelDeploymentStatus, ModelDeploymentStatusInfo
|
||||||
classname: styles['model-deployment-status-cell--error'],
|
classname: styles['model-deployment-status-cell--error'],
|
||||||
text: '失败',
|
text: '失败',
|
||||||
},
|
},
|
||||||
|
[ModelDeploymentStatus.Pending]: {
|
||||||
|
classname: styles['model-deployment-status-cell--pending'],
|
||||||
|
text: '挂起中',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function ModelDeploymentStatusCell(status: ModelDeploymentStatus | undefined) {
|
function ModelDeploymentStatusCell(status?: ModelDeploymentStatus | null) {
|
||||||
if (status === null || status === undefined || !statusInfo[status]) {
|
if (status === null || status === undefined || !statusInfo[status]) {
|
||||||
return <span>--</span>;
|
return <span>--</span>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,7 @@ export type ModelDeploymentData = {
|
||||||
|
|
||||||
// 操作类型
|
// 操作类型
|
||||||
export enum ModelDeploymentOperationType {
|
export enum ModelDeploymentOperationType {
|
||||||
Create = 'create',
|
Create = 'Create',
|
||||||
Update = 'update',
|
Update = 'Update',
|
||||||
Restart = 'restart',
|
Restart = 'Restart',
|
||||||
}
|
}
|
||||||
|
|
||||||
// 状态
|
|
||||||
export type ModelDeploymentStatusInfo = {
|
|
||||||
text: string;
|
|
||||||
classname: string;
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import KFIcon from '@/components/KFIcon';
|
import KFIcon from '@/components/KFIcon';
|
||||||
import ParameterInput from '@/components/ParameterInput';
|
import ParameterInput from '@/components/ParameterInput';
|
||||||
import SubAreaTitle from '@/components/SubAreaTitle';
|
import SubAreaTitle from '@/components/SubAreaTitle';
|
||||||
import { getComputingResourceReq } from '@/services/pipeline';
|
import { useComputingResource } from '@/hooks/resource';
|
||||||
import { openAntdModal } from '@/utils/modal';
|
import { openAntdModal } from '@/utils/modal';
|
||||||
import { to } from '@/utils/promise';
|
import { to } from '@/utils/promise';
|
||||||
import { Button, Drawer, Form, Input, Select } from 'antd';
|
import { Button, Drawer, Form, Input, Select } from 'antd';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
import PropsLabel from '../components/PropsLabel';
|
import PropsLabel from '../components/PropsLabel';
|
||||||
import ResourceSelectorModal, { ResourceSelectorType } from '../components/ResourceSelectorModal';
|
import ResourceSelectorModal, {
|
||||||
|
ResourceSelectorType,
|
||||||
|
selectorTypeConfig,
|
||||||
|
} from '../components/ResourceSelectorModal';
|
||||||
import styles from './props.less';
|
import styles from './props.less';
|
||||||
import { canInput, createMenuItems } from './utils';
|
import { canInput, createMenuItems } from './utils';
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
@ -19,26 +22,9 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [selectedModel, setSelectedModel] = useState(undefined); // 选择的模型,为了再次打开时恢复原来的选择
|
const [selectedModel, setSelectedModel] = useState(undefined); // 选择的模型,为了再次打开时恢复原来的选择
|
||||||
const [selectedDataset, setSelectedDataset] = useState(undefined); // 选择的数据集,为了再次打开时恢复原来的选择
|
const [selectedDataset, setSelectedDataset] = useState(undefined); // 选择的数据集,为了再次打开时恢复原来的选择
|
||||||
const [resourceStandardList, setResourceStandardList] = useState([]); // 资源规模列表
|
const [resourceStandardList, filterResourceStandard] = useComputingResource(); // 资源规模
|
||||||
const [menuItems, setMenuItems] = useState([]);
|
const [menuItems, setMenuItems] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getComputingResource();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 获取资源规格列表数据
|
|
||||||
const getComputingResource = async () => {
|
|
||||||
const params = {
|
|
||||||
page: 0,
|
|
||||||
size: 1000,
|
|
||||||
resource_type: '',
|
|
||||||
};
|
|
||||||
const [res] = await to(getComputingResourceReq(params));
|
|
||||||
if (res && res.data && res.data.content) {
|
|
||||||
setResourceStandardList(res.data.content);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const afterOpenChange = () => {
|
const afterOpenChange = () => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
console.log('zzzzz', form.getFieldsValue());
|
console.log('zzzzz', form.getFieldsValue());
|
||||||
|
@ -57,6 +43,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
getFieldsValue: async () => {
|
getFieldsValue: async () => {
|
||||||
const [propsRes, propsError] = await to(form.validateFields());
|
const [propsRes, propsError] = await to(form.validateFields());
|
||||||
|
@ -155,18 +142,16 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
||||||
// 获取选择数据集、模型后面按钮 icon
|
// 获取选择数据集、模型后面按钮 icon
|
||||||
const getSelectBtnIcon = (item) => {
|
const getSelectBtnIcon = (item) => {
|
||||||
const type = item.item_type;
|
const type = item.item_type;
|
||||||
|
let selectorType;
|
||||||
if (type === 'dataset') {
|
if (type === 'dataset') {
|
||||||
return <KFIcon type="icon-xuanzeshujuji" />;
|
selectorType = ResourceSelectorType.Dataset;
|
||||||
} else if (type === 'model') {
|
} else if (type === 'model') {
|
||||||
return <KFIcon type="icon-xuanzemoxing" />;
|
selectorType = ResourceSelectorType.Model;
|
||||||
} else {
|
} else {
|
||||||
return <KFIcon type="icon-xuanzejingxiang" />;
|
selectorType = ResourceSelectorType.Mirror;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// 筛选资源规格
|
return <KFIcon type={selectorTypeConfig[selectorType].buttonIcon} />;
|
||||||
const filterResourceStandard = (input, { computing_resource = '' }) => {
|
|
||||||
return computing_resource.toLocaleLowerCase().includes(input.toLocaleLowerCase());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 参数回填
|
// 参数回填
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* @Date: 2024-03-25 13:52:54
|
* @Date: 2024-03-25 13:52:54
|
||||||
* @Description: 网络请求配置,详情请参考 https://umijs.org/docs/max/request
|
* @Description: 网络请求配置,详情请参考 https://umijs.org/docs/max/request
|
||||||
*/
|
*/
|
||||||
import type { RequestConfig } from '@umijs/max';
|
import type { AxiosRequestConfig, AxiosResponse, RequestConfig } from '@umijs/max';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { clearSessionToken, getAccessToken } from './access';
|
import { clearSessionToken, getAccessToken } from './access';
|
||||||
import { setRemoteMenu } from './services/session';
|
import { setRemoteMenu } from './services/session';
|
||||||
|
@ -16,8 +16,8 @@ import { gotoLoginPage } from './utils/ui';
|
||||||
export const requestConfig: RequestConfig = {
|
export const requestConfig: RequestConfig = {
|
||||||
errorConfig: {},
|
errorConfig: {},
|
||||||
requestInterceptors: [
|
requestInterceptors: [
|
||||||
(url: any, options: { headers: any }) => {
|
(url: string, options: AxiosRequestConfig) => {
|
||||||
const headers = options.headers ? options.headers : [];
|
const headers = options.headers ?? {};
|
||||||
const authHeader = headers['Authorization'];
|
const authHeader = headers['Authorization'];
|
||||||
const isToken = headers['isToken'];
|
const isToken = headers['isToken'];
|
||||||
if (!authHeader && isToken !== false) {
|
if (!authHeader && isToken !== false) {
|
||||||
|
@ -30,7 +30,7 @@ export const requestConfig: RequestConfig = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
responseInterceptors: [
|
responseInterceptors: [
|
||||||
(response: any) => {
|
(response: AxiosResponse) => {
|
||||||
const { status, data } = response || {};
|
const { status, data } = response || {};
|
||||||
if (status >= 200 && status < 300) {
|
if (status >= 200 && status < 300) {
|
||||||
if (data && (data instanceof Blob || data.code === 200)) {
|
if (data && (data instanceof Blob || data.code === 200)) {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
@success-color: #1ace62;
|
@success-color: #1ace62;
|
||||||
@error-color: #c73131;
|
@error-color: #c73131;
|
||||||
@warning-color: #f98e1b;
|
@warning-color: #f98e1b;
|
||||||
|
@abort-color: #8a8a8a;
|
||||||
|
|
||||||
@border-color: rgba(22, 100, 255, 0.3);
|
@border-color: rgba(22, 100, 255, 0.3);
|
||||||
@border-color-secondary: rgba(22, 100, 255, 0.1);
|
@border-color-secondary: rgba(22, 100, 255, 0.1);
|
||||||
|
|
|
@ -29,7 +29,7 @@ export function parseJsonText(text?: string | null): any | null {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Underscore-to-camelCase
|
// underscore-to-camelCase
|
||||||
export function underscoreToCamelCase(obj: Record<string, any>) {
|
export function underscoreToCamelCase(obj: Record<string, any>) {
|
||||||
const newObj: Record<string, any> = {};
|
const newObj: Record<string, any> = {};
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
|
@ -47,6 +47,7 @@ export function underscoreToCamelCase(obj: Record<string, any>) {
|
||||||
return newObj;
|
return newObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// camelCase-to-underscore
|
||||||
export function camelCaseToUnderscore(obj: Record<string, any>) {
|
export function camelCaseToUnderscore(obj: Record<string, any>) {
|
||||||
const newObj: Record<string, any> = {};
|
const newObj: Record<string, any> = {};
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
|
@ -61,3 +62,21 @@ export function camelCaseToUnderscore(obj: Record<string, any>) {
|
||||||
}
|
}
|
||||||
return newObj;
|
return newObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// null 转 undefined
|
||||||
|
export function nullToUndefined(obj: Record<string, any>) {
|
||||||
|
const newObj: Record<string, any> = {};
|
||||||
|
for (const key in obj) {
|
||||||
|
if (obj.hasOwnProperty(key)) {
|
||||||
|
const value = obj[key];
|
||||||
|
if (value === null) {
|
||||||
|
newObj[key] = undefined;
|
||||||
|
} else if (typeof value === 'object' && value !== null) {
|
||||||
|
newObj[key] = nullToUndefined(value);
|
||||||
|
} else {
|
||||||
|
newObj[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newObj;
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import zhCN from 'antd/locale/zh_CN';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
|
const destroyFns: (() => void)[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to open an Ant Design modal.
|
* Function to open an Ant Design modal.
|
||||||
*
|
*
|
||||||
|
@ -16,7 +18,6 @@ import { createRoot } from 'react-dom/client';
|
||||||
* @param modalProps - The modal properties.
|
* @param modalProps - The modal properties.
|
||||||
* @return An object with a destroy method to close the modal.
|
* @return An object with a destroy method to close the modal.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
|
export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
|
||||||
modal: (props: T) => React.ReactNode,
|
modal: (props: T) => React.ReactNode,
|
||||||
modalProps: T,
|
modalProps: T,
|
||||||
|
@ -29,6 +30,11 @@ export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
|
||||||
let timeoutId: ReturnType<typeof setTimeout>;
|
let timeoutId: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
function destroy() {
|
function destroy() {
|
||||||
|
const index = destroyFns.indexOf(close);
|
||||||
|
if (index !== -1) {
|
||||||
|
destroyFns.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
root.unmount();
|
root.unmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +85,8 @@ export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
|
||||||
|
|
||||||
render({ ...modalProps, open: true });
|
render({ ...modalProps, open: true });
|
||||||
|
|
||||||
|
destroyFns.push(close);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
close,
|
close,
|
||||||
};
|
};
|
||||||
|
@ -88,19 +96,23 @@ export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
|
||||||
* Generates a custom hook for managing an Ant Design modal.
|
* Generates a custom hook for managing an Ant Design modal.
|
||||||
*
|
*
|
||||||
* @param modal - The function that renders the modal content.
|
* @param modal - The function that renders the modal content.
|
||||||
* @param key - The key for the modal.
|
* @param defaultProps - The default modal properties.
|
||||||
* @return The modal component, open function, and close function.
|
* @return The modal component, open function, and close function.
|
||||||
*/
|
*/
|
||||||
export const useAntdModal = <T extends ModalProps>(
|
|
||||||
|
export const useModal = <T extends ModalProps>(
|
||||||
modal: (props: T) => React.ReactNode,
|
modal: (props: T) => React.ReactNode,
|
||||||
key: React.Key,
|
defaultProps?: T,
|
||||||
) => {
|
) => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [props, setProps] = useState<T>({} as T);
|
const [props, setProps] = useState<T>(defaultProps || ({} as T));
|
||||||
const CustomModel = modal;
|
const CustomModel = modal;
|
||||||
|
|
||||||
const open = (props: T) => {
|
const open = (props: T) => {
|
||||||
setProps(props);
|
setProps((prev) => ({
|
||||||
|
...prev,
|
||||||
|
...props,
|
||||||
|
}));
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,5 +120,14 @@ export const useAntdModal = <T extends ModalProps>(
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return [<CustomModel key={key} open={visible} {...props} />, open, close] as const;
|
return [<CustomModel key="modal" open={visible} {...props} />, open, close] as const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭没有手动关闭的 Modal
|
||||||
|
export const closeAllModals = () => {
|
||||||
|
let close = destroyFns.pop();
|
||||||
|
while (close) {
|
||||||
|
close();
|
||||||
|
close = destroyFns.pop();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { PageEnum } from '@/enums/pagesEnums';
|
||||||
import themes from '@/styles/theme.less';
|
import themes from '@/styles/theme.less';
|
||||||
import { history } from '@umijs/max';
|
import { history } from '@umijs/max';
|
||||||
import { Modal, message, type ModalFuncProps, type UploadFile } from 'antd';
|
import { Modal, message, type ModalFuncProps, type UploadFile } from 'antd';
|
||||||
|
import { closeAllModals } from './modal';
|
||||||
|
|
||||||
// 自定义 Confirm 弹框
|
// 自定义 Confirm 弹框
|
||||||
export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) {
|
export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) {
|
||||||
|
@ -58,6 +59,7 @@ export const gotoLoginPage = (toHome: boolean = true) => {
|
||||||
console.log('pathname', pathname);
|
console.log('pathname', pathname);
|
||||||
console.log('search', search);
|
console.log('search', search);
|
||||||
if (window.location.pathname !== PageEnum.LOGIN) {
|
if (window.location.pathname !== PageEnum.LOGIN) {
|
||||||
|
closeAllModals();
|
||||||
history.replace({
|
history.replace({
|
||||||
pathname: PageEnum.LOGIN,
|
pathname: PageEnum.LOGIN,
|
||||||
search: newSearch,
|
search: newSearch,
|
||||||
|
|
Loading…
Reference in New Issue