| @@ -0,0 +1,7 @@ | |||||
| .kf-confirm-modal { | |||||
| &__content { | |||||
| width: 100%; | |||||
| font-size: 18px; | |||||
| text-align: center; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,37 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-10-10 10:54:25 | |||||
| * @Description: 自定义 Confirm Modal | |||||
| */ | |||||
| import classNames from 'classnames'; | |||||
| import KFModal, { KFModalProps } from '../KFModal'; | |||||
| import './index.less'; | |||||
| export interface KFConfirmModalProps extends KFModalProps { | |||||
| content: string; | |||||
| } | |||||
| function KFConfirmModal({ | |||||
| title, | |||||
| image, | |||||
| className = '', | |||||
| centered, | |||||
| maskClosable, | |||||
| content, | |||||
| ...rest | |||||
| }: KFConfirmModalProps) { | |||||
| return ( | |||||
| <KFModal | |||||
| className={classNames(['kf-confirm-modal', className])} | |||||
| {...rest} | |||||
| centered={centered ?? true} | |||||
| maskClosable={maskClosable ?? false} | |||||
| title={title} | |||||
| image={image ?? require('@/assets/img/edit-experiment.png')} | |||||
| > | |||||
| <div className="kf-confirm-modal__content">{content}</div> | |||||
| </KFModal> | |||||
| ); | |||||
| } | |||||
| export default KFConfirmModal; | |||||
| @@ -80,7 +80,7 @@ export enum ServiceType { | |||||
| export const serviceTypeOptions = [ | export const serviceTypeOptions = [ | ||||
| { label: '视频', value: ServiceType.Video }, | { label: '视频', value: ServiceType.Video }, | ||||
| { label: '图像', value: ServiceType.Image }, | |||||
| { label: '图片', value: ServiceType.Image }, | |||||
| { label: '音频', value: ServiceType.Audio }, | { label: '音频', value: ServiceType.Audio }, | ||||
| { label: '文本', value: ServiceType.Text }, | { label: '文本', value: ServiceType.Text }, | ||||
| ]; | ]; | ||||
| @@ -18,7 +18,7 @@ import { useNavigate } from '@umijs/max'; | |||||
| import { App, Button, Col, Form, Input, Row, Select } from 'antd'; | import { App, Button, Col, Form, Input, Row, Select } from 'antd'; | ||||
| import { pick } from 'lodash'; | import { pick } from 'lodash'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| import { ServiceData, ServiceOperationType } from '../types'; | |||||
| import { ServiceData, ServiceOperationType, createServiceVersionMessage } from '../types'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| // 表单数据 | // 表单数据 | ||||
| @@ -59,9 +59,12 @@ function CreateService() { | |||||
| ...formData, | ...formData, | ||||
| }; | }; | ||||
| const [res] = await to(request(params)); | const [res] = await to(request(params)); | ||||
| if (res) { | |||||
| if (res && res.data) { | |||||
| message.success('操作成功'); | message.success('操作成功'); | ||||
| navigate(-1); | navigate(-1); | ||||
| setTimeout(() => { | |||||
| window.postMessage({ type: createServiceVersionMessage, payload: res.data.id }); | |||||
| }, 500); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -31,7 +31,12 @@ import { useNavigate, useParams } from '@umijs/max'; | |||||
| import { App, Button, Col, Flex, Form, Input, Row, Select } from 'antd'; | import { App, Button, Col, Flex, Form, Input, Row, Select } from 'antd'; | ||||
| import { omit, pick } from 'lodash'; | import { omit, pick } from 'lodash'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| import { ServiceData, ServiceOperationType, ServiceVersionData } from '../types'; | |||||
| import { | |||||
| CreateServiceVersionFrom, | |||||
| ServiceData, | |||||
| ServiceOperationType, | |||||
| ServiceVersionData, | |||||
| } from '../types'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| // 表单数据 | // 表单数据 | ||||
| @@ -53,6 +58,7 @@ function CreateServiceVersion() { | |||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const [resourceStandardList, filterResourceStandard] = useComputingResource(); | const [resourceStandardList, filterResourceStandard] = useComputingResource(); | ||||
| const [operationType, setOperationType] = useState(ServiceOperationType.Create); | const [operationType, setOperationType] = useState(ServiceOperationType.Create); | ||||
| const [lastPage, setLastPage] = useState(CreateServiceVersionFrom.ServiceInfo); | |||||
| const { message } = App.useApp(); | const { message } = App.useApp(); | ||||
| const [serviceInfo, setServiceInfo] = useState<ServiceData | undefined>(undefined); | const [serviceInfo, setServiceInfo] = useState<ServiceData | undefined>(undefined); | ||||
| const [versionInfo, setVersionInfo] = useState<ServiceVersionData | undefined>(undefined); | const [versionInfo, setVersionInfo] = useState<ServiceVersionData | undefined>(undefined); | ||||
| @@ -60,10 +66,15 @@ function CreateServiceVersion() { | |||||
| const id = params.id; | const id = params.id; | ||||
| useEffect(() => { | useEffect(() => { | ||||
| const res: (ServiceVersionData & { operationType: ServiceOperationType }) | undefined = | |||||
| getSessionStorageItem(serviceVersionInfoKey, true); | |||||
| const res: | |||||
| | (ServiceVersionData & { | |||||
| operationType: ServiceOperationType; | |||||
| lastPage: CreateServiceVersionFrom; | |||||
| }) | |||||
| | undefined = getSessionStorageItem(serviceVersionInfoKey, true); | |||||
| if (res) { | if (res) { | ||||
| setOperationType(res.operationType); | setOperationType(res.operationType); | ||||
| setLastPage(res.lastPage); | |||||
| setVersionInfo(res); | setVersionInfo(res); | ||||
| let model, codeConfig, envVariables; | let model, codeConfig, envVariables; | ||||
| if (res.model && typeof res.model === 'object') { | if (res.model && typeof res.model === 'object') { | ||||
| @@ -156,7 +167,11 @@ function CreateServiceVersion() { | |||||
| const [res] = await to(request(params)); | const [res] = await to(request(params)); | ||||
| if (res) { | if (res) { | ||||
| message.success('操作成功'); | message.success('操作成功'); | ||||
| navigate(-1); | |||||
| if (lastPage === CreateServiceVersionFrom.ServiceInfo) { | |||||
| navigate(-1); | |||||
| } else { | |||||
| navigate(`/modelDeployment/serviceInfo/${serviceInfo?.id}`, { replace: true }); | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -401,7 +416,8 @@ function CreateServiceVersion() { | |||||
| }, | }, | ||||
| { | { | ||||
| pattern: /^\/[a-zA-Z0-9._/-]+$/, | pattern: /^\/[a-zA-Z0-9._/-]+$/, | ||||
| message: '请输入正确的挂载绝对路径', | |||||
| message: | |||||
| '请输入正确的挂载路径,以 / 开头,只支持字母、数字、点、下划线、横杠、斜杠', | |||||
| }, | }, | ||||
| ]} | ]} | ||||
| > | > | ||||
| @@ -12,7 +12,11 @@ import { useCacheState } from '@/hooks/pageCacheState'; | |||||
| import { deleteServiceReq, getServiceListReq } from '@/services/modelDeployment'; | import { deleteServiceReq, getServiceListReq } from '@/services/modelDeployment'; | ||||
| import themes from '@/styles/theme.less'; | import themes from '@/styles/theme.less'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { serviceInfoKey, setSessionStorageItem } from '@/utils/sessionStorage'; | |||||
| import { | |||||
| serviceInfoKey, | |||||
| serviceVersionInfoKey, | |||||
| setSessionStorageItem, | |||||
| } from '@/utils/sessionStorage'; | |||||
| import { modalConfirm } from '@/utils/ui'; | import { modalConfirm } from '@/utils/ui'; | ||||
| import { useNavigate } from '@umijs/max'; | import { useNavigate } from '@umijs/max'; | ||||
| import { | import { | ||||
| @@ -28,7 +32,12 @@ import { | |||||
| import { type SearchProps } from 'antd/es/input'; | import { type SearchProps } from 'antd/es/input'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| import { ServiceData, ServiceOperationType } from '../types'; | |||||
| import { | |||||
| CreateServiceVersionFrom, | |||||
| ServiceData, | |||||
| ServiceOperationType, | |||||
| createServiceVersionMessage, | |||||
| } from '../types'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const allServiceTypeOptions = [{ label: '全部', value: '' }, ...serviceTypeOptions]; | const allServiceTypeOptions = [{ label: '全部', value: '' }, ...serviceTypeOptions]; | ||||
| @@ -49,6 +58,13 @@ function ModelDeployment() { | |||||
| }, | }, | ||||
| ); | ); | ||||
| useEffect(() => { | |||||
| window.addEventListener('message', handleMessage); | |||||
| return () => { | |||||
| window.removeEventListener('message', handleMessage); | |||||
| }; | |||||
| }, []); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| getServiceList(); | getServiceList(); | ||||
| }, [pagination, searchText, serviceType]); | }, [pagination, searchText, serviceType]); | ||||
| @@ -137,6 +153,35 @@ function ModelDeployment() { | |||||
| navigate(`/modelDeployment/serviceInfo/${record.id}`); | navigate(`/modelDeployment/serviceInfo/${record.id}`); | ||||
| }; | }; | ||||
| const handleMessage = (e: MessageEvent) => { | |||||
| const { type, payload } = e.data; | |||||
| if (type === createServiceVersionMessage) { | |||||
| modalConfirm({ | |||||
| title: '创建服务成功', | |||||
| content: '是否创建服务版本?', | |||||
| isDelete: false, | |||||
| cancelText: '稍后创建', | |||||
| onOk: () => { | |||||
| gotoCreateServiceVersion(payload); | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }; | |||||
| // 去创建服务版本 | |||||
| const gotoCreateServiceVersion = (serviceId: number) => { | |||||
| setSessionStorageItem( | |||||
| serviceVersionInfoKey, | |||||
| { | |||||
| operationType: ServiceOperationType.Create, | |||||
| lastPage: CreateServiceVersionFrom.CreateService, | |||||
| }, | |||||
| true, | |||||
| ); | |||||
| navigate(`/modelDeployment/addVersion/${serviceId}`); | |||||
| }; | |||||
| // 分页切换 | // 分页切换 | ||||
| const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => { | const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => { | ||||
| if (action === 'paginate') { | if (action === 'paginate') { | ||||
| @@ -38,7 +38,12 @@ import { type SearchProps } from 'antd/es/input'; | |||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| import ServiceRunStatusCell from '../components/ModelDeployStatusCell'; | import ServiceRunStatusCell from '../components/ModelDeployStatusCell'; | ||||
| import { ServiceData, ServiceOperationType, ServiceVersionData } from '../types'; | |||||
| import { | |||||
| CreateServiceVersionFrom, | |||||
| ServiceData, | |||||
| ServiceOperationType, | |||||
| ServiceVersionData, | |||||
| } from '../types'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const allServiceStatusOptions = [{ label: '全部', value: '' }, ...serviceStatusOptions]; | const allServiceStatusOptions = [{ label: '全部', value: '' }, ...serviceStatusOptions]; | ||||
| @@ -171,13 +176,14 @@ function ServiceInfo() { | |||||
| }); | }); | ||||
| }; | }; | ||||
| // 创建、更新、重启模型部署 | |||||
| // 创建、更新、重启服务版本 | |||||
| const createServiceVersion = (type: ServiceOperationType, record?: ServiceVersionData) => { | const createServiceVersion = (type: ServiceOperationType, record?: ServiceVersionData) => { | ||||
| setSessionStorageItem( | setSessionStorageItem( | ||||
| serviceVersionInfoKey, | serviceVersionInfoKey, | ||||
| { | { | ||||
| ...record, | ...record, | ||||
| operationType: type, | operationType: type, | ||||
| lastPage: CreateServiceVersionFrom.ServiceInfo, | |||||
| }, | }, | ||||
| true, | true, | ||||
| ); | ); | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * @Author: 赵伟 | * @Author: 赵伟 | ||||
| * @Date: 2024-04-18 18:35:41 | * @Date: 2024-04-18 18:35:41 | ||||
| * @Description: 模型部署状态 | |||||
| * @Description: 服务运行状态 | |||||
| */ | */ | ||||
| import { ServiceRunStatus } from '@/enums'; | import { ServiceRunStatus } from '@/enums'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| @@ -57,7 +57,7 @@ function ServerLog({ info }: ServerLogProps) { | |||||
| getModelDeploymentLog(); | getModelDeploymentLog(); | ||||
| }, [info, logTime]); | }, [info, logTime]); | ||||
| // 获取模型部署日志 | |||||
| // 获取服务日志 | |||||
| const getModelDeploymentLog = async () => { | const getModelDeploymentLog = async () => { | ||||
| if (info && logTime && logTime.length === 2) { | if (info && logTime && logTime.length === 2) { | ||||
| const params = { | const params = { | ||||
| @@ -14,7 +14,7 @@ function UserGuide({ info }: UserGuideProps) { | |||||
| getModelDeploymentDocs(); | getModelDeploymentDocs(); | ||||
| }, [info]); | }, [info]); | ||||
| // 获取模型部署文档 | |||||
| // 获取服务文档 | |||||
| const getModelDeploymentDocs = async () => { | const getModelDeploymentDocs = async () => { | ||||
| if (info) { | if (info) { | ||||
| const [res] = await to(getServiceVersionDocsReq(info.id)); | const [res] = await to(getServiceVersionDocsReq(info.id)); | ||||
| @@ -57,3 +57,12 @@ export enum ServiceOperationType { | |||||
| Update = 'Update', // 更新 | Update = 'Update', // 更新 | ||||
| Restart = 'Restart', // 重启 | Restart = 'Restart', // 重启 | ||||
| } | } | ||||
| // 操作类型 | |||||
| export enum CreateServiceVersionFrom { | |||||
| CreateService = 'CreateService', // 来自创建服务 | |||||
| ServiceInfo = 'ServiceInfo', // 来自服务详情 | |||||
| } | |||||
| // 去创建服务版本消息 | |||||
| export const createServiceVersionMessage = 'createServiceVersion'; | |||||
| @@ -10,8 +10,20 @@ 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'; | import { closeAllModals } from './modal'; | ||||
| // 自定义 Confirm 弹框 | |||||
| export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) { | |||||
| type ModalConfirmProps = ModalFuncProps & { | |||||
| isDelete?: boolean; | |||||
| }; | |||||
| // 自定义删除 Confirm 弹框 | |||||
| export function modalConfirm({ | |||||
| title, | |||||
| content, | |||||
| okText = '确认', | |||||
| cancelText = '取消', | |||||
| isDelete = true, | |||||
| onOk, | |||||
| ...rest | |||||
| }: ModalConfirmProps) { | |||||
| Modal.confirm({ | Modal.confirm({ | ||||
| ...rest, | ...rest, | ||||
| width: 600, | width: 600, | ||||
| @@ -19,7 +31,11 @@ export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) | |||||
| title: ( | title: ( | ||||
| <div> | <div> | ||||
| <img | <img | ||||
| src={require('@/assets/img/delete-icon.png')} | |||||
| src={ | |||||
| isDelete | |||||
| ? require('@/assets/img/delete-icon.png') | |||||
| : require('@/assets/img/comfirm-icon.png') | |||||
| } | |||||
| style={{ width: '120px', marginBottom: '24px' }} | style={{ width: '120px', marginBottom: '24px' }} | ||||
| draggable={false} | draggable={false} | ||||
| alt="" | alt="" | ||||
| @@ -28,8 +44,8 @@ export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) | |||||
| </div> | </div> | ||||
| ), | ), | ||||
| content: content && <div style={{ color: themes.textColor, fontSize: '15px' }}>{content}</div>, | content: content && <div style={{ color: themes.textColor, fontSize: '15px' }}>{content}</div>, | ||||
| okText: '确认', | |||||
| cancelText: '取消', | |||||
| okText: okText, | |||||
| cancelText: cancelText, | |||||
| onOk: onOk, | onOk: onOk, | ||||
| }); | }); | ||||
| } | } | ||||