| @@ -29,6 +29,8 @@ export async function getInitialState(): Promise<{ | |||||
| loading?: boolean; | loading?: boolean; | ||||
| fetchUserInfo?: () => Promise<API.CurrentUser | undefined>; | fetchUserInfo?: () => Promise<API.CurrentUser | undefined>; | ||||
| }> { | }> { | ||||
| console.log('getInitialState'); | |||||
| const fetchUserInfo = async () => { | const fetchUserInfo = async () => { | ||||
| try { | try { | ||||
| const response = await getUserInfo({ | const response = await getUserInfo({ | ||||
| @@ -133,22 +135,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => { | |||||
| // 增加一个 loading 的状态 | // 增加一个 loading 的状态 | ||||
| childrenRender: (children) => { | childrenRender: (children) => { | ||||
| // if (initialState?.loading) return <PageLoading />; | // if (initialState?.loading) return <PageLoading />; | ||||
| return ( | |||||
| <> | |||||
| {children} | |||||
| {/* <SettingDrawer | |||||
| disableUrlParams | |||||
| enableDarkTheme | |||||
| settings={initialState?.settings} | |||||
| onSettingChange={(settings) => { | |||||
| setInitialState((preInitialState) => ({ | |||||
| ...preInitialState, | |||||
| settings, | |||||
| })); | |||||
| }} | |||||
| /> */} | |||||
| </> | |||||
| ); | |||||
| return <>{children}</>; | |||||
| }, | }, | ||||
| ...initialState?.settings, | ...initialState?.settings, | ||||
| }; | }; | ||||
| @@ -17,13 +17,8 @@ const HeaderDropdown: React.FC<HeaderDropdownProps> = ({ overlayClassName: cls, | |||||
| }, | }, | ||||
| }; | }; | ||||
| }); | }); | ||||
| return ( | |||||
| <Dropdown | |||||
| overlayClassName={classNames(className, cls)} | |||||
| getPopupContainer={(target) => target.parentElement || document.body} | |||||
| {...restProps} | |||||
| /> | |||||
| ); | |||||
| return <Dropdown overlayClassName={classNames(className, cls)} {...restProps} />; | |||||
| }; | }; | ||||
| export default HeaderDropdown; | export default HeaderDropdown; | ||||
| @@ -1,13 +1,12 @@ | |||||
| import { clearSessionToken } from '@/access'; | import { clearSessionToken } from '@/access'; | ||||
| import { PageEnum } from '@/enums/pagesEnums'; | |||||
| import { setRemoteMenu } from '@/services/session'; | import { setRemoteMenu } from '@/services/session'; | ||||
| import { logout } from '@/services/system/auth'; | import { logout } from '@/services/system/auth'; | ||||
| import { gotoLoginPage } from '@/utils/ui'; | |||||
| import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons'; | import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons'; | ||||
| import { setAlpha } from '@ant-design/pro-components'; | import { setAlpha } from '@ant-design/pro-components'; | ||||
| import { useEmotionCss } from '@ant-design/use-emotion-css'; | import { useEmotionCss } from '@ant-design/use-emotion-css'; | ||||
| import { history, useModel } from '@umijs/max'; | import { history, useModel } from '@umijs/max'; | ||||
| import { Avatar, Spin } from 'antd'; | import { Avatar, Spin } from 'antd'; | ||||
| import { stringify } from 'querystring'; | |||||
| import type { MenuInfo } from 'rc-menu/lib/interface'; | import type { MenuInfo } from 'rc-menu/lib/interface'; | ||||
| import React, { useCallback } from 'react'; | import React, { useCallback } from 'react'; | ||||
| import { flushSync } from 'react-dom'; | import { flushSync } from 'react-dom'; | ||||
| @@ -23,7 +22,7 @@ const Name = () => { | |||||
| const nameClassName = useEmotionCss(({ token }) => { | const nameClassName = useEmotionCss(({ token }) => { | ||||
| return { | return { | ||||
| width: '70px', | |||||
| // width: '70px', | |||||
| height: '48px', | height: '48px', | ||||
| overflow: 'hidden', | overflow: 'hidden', | ||||
| lineHeight: '48px', | lineHeight: '48px', | ||||
| @@ -64,19 +63,7 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => { | |||||
| await logout(); | await logout(); | ||||
| clearSessionToken(); | clearSessionToken(); | ||||
| setRemoteMenu(null); | setRemoteMenu(null); | ||||
| const { search, pathname } = window.location; | |||||
| const urlParams = new URL(window.location.href).searchParams; | |||||
| /** 此方法会跳转到 redirect 参数所在的位置 */ | |||||
| const redirect = urlParams.get('redirect'); | |||||
| // Note: There may be security issues, please note | |||||
| if (window.location.pathname !== PageEnum.LOGIN && !redirect) { | |||||
| history.replace({ | |||||
| pathname: PageEnum.LOGIN, | |||||
| search: stringify({ | |||||
| redirect: pathname + search, | |||||
| }), | |||||
| }); | |||||
| } | |||||
| gotoLoginPage(); | |||||
| }; | }; | ||||
| const actionClassName = useEmotionCss(({ token }) => { | const actionClassName = useEmotionCss(({ token }) => { | ||||
| return { | return { | ||||
| @@ -1,6 +1,5 @@ | |||||
| import { QuestionCircleOutlined } from '@ant-design/icons'; | |||||
| import { useEmotionCss } from '@ant-design/use-emotion-css'; | import { useEmotionCss } from '@ant-design/use-emotion-css'; | ||||
| import { SelectLang, useModel } from '@umijs/max'; | |||||
| import { useModel } from '@umijs/max'; | |||||
| import React from 'react'; | import React from 'react'; | ||||
| import Avatar from './AvatarDropdown'; | import Avatar from './AvatarDropdown'; | ||||
| @@ -17,21 +16,21 @@ const GlobalHeaderRight: React.FC = () => { | |||||
| }; | }; | ||||
| }); | }); | ||||
| const actionClassName = useEmotionCss(({ token }) => { | |||||
| return { | |||||
| display: 'flex', | |||||
| float: 'right', | |||||
| height: '48px', | |||||
| marginLeft: 'auto', | |||||
| overflow: 'hidden', | |||||
| cursor: 'pointer', | |||||
| padding: '0 12px', | |||||
| borderRadius: token.borderRadius, | |||||
| '&:hover': { | |||||
| backgroundColor: token.colorBgTextHover, | |||||
| }, | |||||
| }; | |||||
| }); | |||||
| // const actionClassName = useEmotionCss(({ token }) => { | |||||
| // return { | |||||
| // display: 'flex', | |||||
| // float: 'right', | |||||
| // height: '48px', | |||||
| // marginLeft: 'auto', | |||||
| // overflow: 'hidden', | |||||
| // cursor: 'pointer', | |||||
| // padding: '0 12px', | |||||
| // borderRadius: token.borderRadius, | |||||
| // '&:hover': { | |||||
| // backgroundColor: token.colorBgTextHover, | |||||
| // }, | |||||
| // }; | |||||
| // }); | |||||
| const { initialState } = useModel('@@initialState'); | const { initialState } = useModel('@@initialState'); | ||||
| @@ -41,15 +40,15 @@ const GlobalHeaderRight: React.FC = () => { | |||||
| return ( | return ( | ||||
| <div className={className}> | <div className={className}> | ||||
| <span | |||||
| {/* <span | |||||
| className={actionClassName} | className={actionClassName} | ||||
| onClick={() => { | onClick={() => { | ||||
| window.open('https://pro.ant.design/docs/getting-started'); | window.open('https://pro.ant.design/docs/getting-started'); | ||||
| }} | }} | ||||
| > | > | ||||
| <QuestionCircleOutlined /> | <QuestionCircleOutlined /> | ||||
| </span> | |||||
| <Avatar menu={true} /> | |||||
| </span> */} | |||||
| <Avatar menu={false} /> | |||||
| {/* <SelectLang className={actionClassName} /> */} | {/* <SelectLang className={actionClassName} /> */} | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -1,3 +1,9 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-28 08:47:43 | |||||
| * @Description: 覆盖 antd 样式 | |||||
| */ | |||||
| // 设置 Table 可以滑动 | // 设置 Table 可以滑动 | ||||
| .vertical-scroll-table { | .vertical-scroll-table { | ||||
| .ant-table-wrapper { | .ant-table-wrapper { | ||||
| @@ -9,7 +15,7 @@ | |||||
| height: 100%; | height: 100%; | ||||
| .ant-table { | .ant-table { | ||||
| height: calc(100% - 74px); | |||||
| height: calc(100% - 74px); // 分页控件的高度 | |||||
| .ant-table-container { | .ant-table-container { | ||||
| height: 100%; | height: 100%; | ||||
| @@ -144,8 +144,15 @@ function AddExperimentModal({ | |||||
| label="实验描述" | label="实验描述" | ||||
| name="description" | name="description" | ||||
| rules={[{ required: true, message: '请输入实验描述' }]} | rules={[{ required: true, message: '请输入实验描述' }]} | ||||
| style={{ marginBottom: '48px' }} | |||||
| > | > | ||||
| <Input placeholder="请输入实验描述" maxLength={128} showCount allowClear /> | |||||
| <Input.TextArea | |||||
| placeholder="请输入实验描述" | |||||
| maxLength={128} | |||||
| autoSize={{ minRows: 2, maxRows: 5 }} | |||||
| showCount | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="选择流水线" | label="选择流水线" | ||||
| @@ -380,10 +380,10 @@ const EditPipeline = () => { | |||||
| return ( | return ( | ||||
| cfg.anchorPoints || [ | cfg.anchorPoints || [ | ||||
| // 四个 | // 四个 | ||||
| // [0.5, 0], | |||||
| // [0.5, 1], | |||||
| [0, 0.5], | |||||
| [1, 0.5], | |||||
| [0.5, 0], | |||||
| [0.5, 1], | |||||
| // [0, 0.5], | |||||
| // [1, 0.5], | |||||
| ] | ] | ||||
| ); | ); | ||||
| }, | }, | ||||
| @@ -1,13 +1,13 @@ | |||||
| /* | /* | ||||
| * @Author: 赵伟 | * @Author: 赵伟 | ||||
| * @Date: 2024-03-25 13:52:54 | * @Date: 2024-03-25 13:52:54 | ||||
| * @Description: | |||||
| * @Description: 网络请求配置,详情请参考 https://umijs.org/docs/max/request | |||||
| */ | */ | ||||
| import type { RequestConfig } from '@umijs/max'; | import type { RequestConfig } from '@umijs/max'; | ||||
| import { message } from 'antd'; | import { message } from 'antd'; | ||||
| import { clearSessionToken, getAccessToken, getRefreshToken, getTokenExpireTime } from './access'; | |||||
| const checkRegion = 5 * 60 * 1000; | |||||
| import { clearSessionToken, getAccessToken } from './access'; | |||||
| import { setRemoteMenu } from './services/session'; | |||||
| import { gotoLoginPage } from './utils/ui'; | |||||
| /** | /** | ||||
| * Umi Max 网络请求配置 | * Umi Max 网络请求配置 | ||||
| @@ -21,23 +21,25 @@ export const requestConfig: RequestConfig = { | |||||
| const authHeader = headers['Authorization']; | const authHeader = headers['Authorization']; | ||||
| const isToken = headers['isToken']; | const isToken = headers['isToken']; | ||||
| if (!authHeader && isToken !== false) { | if (!authHeader && isToken !== false) { | ||||
| const expireTime = getTokenExpireTime(); | |||||
| if (expireTime) { | |||||
| const left = Number(expireTime) - new Date().getTime(); | |||||
| const refreshToken = getRefreshToken(); | |||||
| if (left < checkRegion && refreshToken) { | |||||
| if (left < 0) { | |||||
| clearSessionToken(); | |||||
| } | |||||
| } else { | |||||
| const accessToken = getAccessToken(); | |||||
| if (accessToken) { | |||||
| headers['Authorization'] = `Bearer ${accessToken}`; | |||||
| } | |||||
| } | |||||
| } else { | |||||
| clearSessionToken(); | |||||
| const accessToken = getAccessToken(); | |||||
| if (accessToken) { | |||||
| headers['Authorization'] = `Bearer ${accessToken}`; | |||||
| } | } | ||||
| // const expireTime = getTokenExpireTime(); | |||||
| // if (expireTime) { | |||||
| // const left = Number(expireTime) - new Date().getTime(); | |||||
| // const refreshToken = getRefreshToken(); | |||||
| // if (left < 0 && refreshToken) { | |||||
| // clearSessionToken(); | |||||
| // } else { | |||||
| // const accessToken = getAccessToken(); | |||||
| // if (accessToken) { | |||||
| // headers['Authorization'] = `Bearer ${accessToken}`; | |||||
| // } | |||||
| // } | |||||
| // } else { | |||||
| // clearSessionToken(); | |||||
| // } | |||||
| } | } | ||||
| return { url, options }; | return { url, options }; | ||||
| }, | }, | ||||
| @@ -45,15 +47,19 @@ export const requestConfig: RequestConfig = { | |||||
| responseInterceptors: [ | responseInterceptors: [ | ||||
| (response: any) => { | (response: any) => { | ||||
| const { status, data } = response; | const { status, data } = response; | ||||
| // console.log('response', response); | |||||
| if (status >= 200 && status < 300 && data && (data instanceof Blob || data.code === 200)) { | |||||
| return response; | |||||
| } else { | |||||
| if (data && data.msg) { | |||||
| message.error(data.msg); | |||||
| if (status >= 200 && status < 300) { | |||||
| if (data && (data instanceof Blob || data.code === 200)) { | |||||
| return response; | |||||
| } else if (data && data.code === 401) { | |||||
| clearSessionToken(); | |||||
| setRemoteMenu(null); | |||||
| gotoLoginPage(false); | |||||
| } else { | } else { | ||||
| message.error('请求失败'); | |||||
| message.error(data?.msg ?? '请求失败'); | |||||
| return Promise.reject(response); | |||||
| } | } | ||||
| } else { | |||||
| message.error('请求失败'); | |||||
| return Promise.reject(response); | return Promise.reject(response); | ||||
| } | } | ||||
| }, | }, | ||||
| @@ -1,8 +1,7 @@ | |||||
| import { createIcon } from '@/utils/IconUtil'; | |||||
| import { MenuDataItem } from '@ant-design/pro-components'; | import { MenuDataItem } from '@ant-design/pro-components'; | ||||
| import { request } from '@umijs/max'; | import { request } from '@umijs/max'; | ||||
| import React, { lazy } from 'react'; | import React, { lazy } from 'react'; | ||||
| import { createFromIconfontCN } from '@ant-design/icons'; | |||||
| let remoteMenu: any = null; | let remoteMenu: any = null; | ||||
| export function getRemoteMenu() { | export function getRemoteMenu() { | ||||
| @@ -101,7 +100,7 @@ export function convertCompatRouters(childrens: API.RoutersMenuItem[]): any[] { | |||||
| return { | return { | ||||
| path: item.path, | path: item.path, | ||||
| // icon:'icon-a-057_fenlei', | // icon:'icon-a-057_fenlei', | ||||
| icon: 'icon-'+item.meta.icon, | |||||
| icon: 'icon-' + item.meta.icon, | |||||
| // icon: item.meta.icon, | // icon: item.meta.icon, | ||||
| name: item.meta.title, | name: item.meta.title, | ||||
| routes: item.children ? convertCompatRouters(item.children) : undefined, | routes: item.children ? convertCompatRouters(item.children) : undefined, | ||||
| @@ -28,8 +28,8 @@ export async function login(body: API.LoginParams, options?: Record<string, any> | |||||
| /** 退出登录接口 POST /api/login/outLogin */ | /** 退出登录接口 POST /api/login/outLogin */ | ||||
| export async function logout() { | export async function logout() { | ||||
| return request<Record<string, any>>('/api/logout', { | |||||
| method: 'delete', | |||||
| return request<Record<string, any>>('/api/auth/logout', { | |||||
| method: 'DELETE', | |||||
| }); | }); | ||||
| } | } | ||||
| @@ -1,4 +1,10 @@ | |||||
| // 全局颜色变量 | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-28 08:47:43 | |||||
| * @Description: 全局变量,可以直接在 less 文件里使用,无需引入;也可以导入到 js 里使用;为 antd 主题修改提供常量值 | |||||
| */ | |||||
| // 颜色 | |||||
| @primary-color: #1664ff; // 主色调 | @primary-color: #1664ff; // 主色调 | ||||
| @primary-color-hover: #69b1ff; | @primary-color-hover: #69b1ff; | ||||
| @background-color: #f9fafb; // 页面背景颜色 | @background-color: #f9fafb; // 页面背景颜色 | ||||
| @@ -1,3 +1,9 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-08 09:54:39 | |||||
| * @Description: 定义全局类型,比如无关联的页面都需要要的类型 | |||||
| */ | |||||
| // 流水线全局参数 | // 流水线全局参数 | ||||
| export type PipelineGlobalParam = { | export type PipelineGlobalParam = { | ||||
| param_name: string; | param_name: string; | ||||
| @@ -3,7 +3,9 @@ | |||||
| * @Date: 2024-04-19 14:42:51 | * @Date: 2024-04-19 14:42:51 | ||||
| * @Description: UI 公共方法 | * @Description: UI 公共方法 | ||||
| */ | */ | ||||
| import { PageEnum } from '@/enums/pagesEnums'; | |||||
| import themes from '@/styles/theme.less'; | import themes from '@/styles/theme.less'; | ||||
| import { history } from '@umijs/max'; | |||||
| import { Modal, type ModalFuncProps, type UploadFile } from 'antd'; | import { Modal, type ModalFuncProps, type UploadFile } from 'antd'; | ||||
| // 自定义 Confirm 弹框 | // 自定义 Confirm 弹框 | ||||
| @@ -43,3 +45,17 @@ export const getFileListFromEvent = (e: any) => { | |||||
| return item; | return item; | ||||
| }); | }); | ||||
| }; | }; | ||||
| // 去登录页面 | |||||
| export const gotoLoginPage = (toHome: boolean = true) => { | |||||
| const { pathname, search } = window.location; | |||||
| const urlParams = new URLSearchParams(); | |||||
| urlParams.append('redirect', pathname + search); | |||||
| const newSearch = toHome ? '' : urlParams.toString(); | |||||
| if (window.location.pathname !== PageEnum.LOGIN) { | |||||
| history.replace({ | |||||
| pathname: PageEnum.LOGIN, | |||||
| search: newSearch, | |||||
| }); | |||||
| } | |||||
| }; | |||||
| @@ -123,7 +123,7 @@ public class ModelsController extends BaseController { | |||||
| */ | */ | ||||
| @PostMapping | @PostMapping | ||||
| @ApiOperation("添加模型") | @ApiOperation("添加模型") | ||||
| public GenericsAjaxResult<Models> add(@RequestBody Models models) { | |||||
| public GenericsAjaxResult<Models> add(@RequestBody Models models) throws Exception { | |||||
| return genericsSuccess(this.modelsService.insert(models)); | return genericsSuccess(this.modelsService.insert(models)); | ||||
| } | } | ||||
| @@ -2,6 +2,7 @@ package com.ruoyi.platform.domain; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | import com.fasterxml.jackson.databind.PropertyNamingStrategy; | ||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||||
| import com.ruoyi.platform.annotations.CheckDuplicate; | |||||
| import io.swagger.annotations.ApiModel; | import io.swagger.annotations.ApiModel; | ||||
| import io.swagger.annotations.ApiModelProperty; | import io.swagger.annotations.ApiModelProperty; | ||||
| @@ -22,6 +23,7 @@ public class Models implements Serializable { | |||||
| private Integer id; | private Integer id; | ||||
| @ApiModelProperty(value = "模型名称") | @ApiModelProperty(value = "模型名称") | ||||
| @CheckDuplicate | |||||
| private String name; | private String name; | ||||
| @ApiModelProperty(value = "模型描述") | @ApiModelProperty(value = "模型描述") | ||||
| @@ -84,7 +84,8 @@ public interface DatasetVersionDao { | |||||
| List<DatasetVersion> queryByDatasetId(Integer datasetId); | List<DatasetVersion> queryByDatasetId(Integer datasetId); | ||||
| DatasetVersion queryByDatasetVersion(@Param("datasetVersion") DatasetVersion datasetVersion); | |||||
| DatasetVersion | |||||
| queryByDatasetVersion(@Param("datasetVersion") DatasetVersion datasetVersion); | |||||
| List<DatasetVersion> queryAllByDatasetVersion(@Param("datasetId") Integer datasetId, @Param("version") String version); | List<DatasetVersion> queryAllByDatasetVersion(@Param("datasetId") Integer datasetId, @Param("version") String version); | ||||
| @@ -1,10 +1,12 @@ | |||||
| package com.ruoyi.platform.mapper; | package com.ruoyi.platform.mapper; | ||||
| import com.ruoyi.platform.domain.Dataset; | |||||
| import com.ruoyi.platform.domain.Models; | import com.ruoyi.platform.domain.Models; | ||||
| import org.apache.ibatis.annotations.Param; | import org.apache.ibatis.annotations.Param; | ||||
| import org.springframework.data.domain.Pageable; | import org.springframework.data.domain.Pageable; | ||||
| import java.util.List; | import java.util.List; | ||||
| import java.util.Map; | |||||
| /** | /** | ||||
| * (Models)表数据库访问层 | * (Models)表数据库访问层 | ||||
| @@ -22,6 +24,8 @@ public interface ModelsDao { | |||||
| */ | */ | ||||
| Models queryById(Integer id); | Models queryById(Integer id); | ||||
| Models findByName(@Param("name") String name); | |||||
| /** | /** | ||||
| * 查询指定行数据 | * 查询指定行数据 | ||||
| * | * | ||||
| @@ -2,6 +2,7 @@ package com.ruoyi.platform.service; | |||||
| import com.ruoyi.platform.domain.Dataset; | |||||
| import com.ruoyi.platform.domain.Models; | import com.ruoyi.platform.domain.Models; | ||||
| import com.ruoyi.platform.domain.ModelsVersion; | import com.ruoyi.platform.domain.ModelsVersion; | ||||
| import com.ruoyi.platform.vo.ModelsVo; | import com.ruoyi.platform.vo.ModelsVo; | ||||
| @@ -45,7 +46,7 @@ public interface ModelsService { | |||||
| * @param models 实例对象 | * @param models 实例对象 | ||||
| * @return 实例对象 | * @return 实例对象 | ||||
| */ | */ | ||||
| Models insert(Models models); | |||||
| Models insert(Models models) throws Exception; | |||||
| /** | /** | ||||
| * 修改数据 | * 修改数据 | ||||
| @@ -81,5 +82,7 @@ public interface ModelsService { | |||||
| String readFileContent(Integer modelsId, String version) throws Exception; | String readFileContent(Integer modelsId, String version) throws Exception; | ||||
| public void checkDeclaredName(Models insert) throws Exception; | |||||
| List<Map<String, String>> exportModels(String path, String uuid) throws Exception; | List<Map<String, String>> exportModels(String path, String uuid) throws Exception; | ||||
| } | } | ||||
| @@ -240,6 +240,7 @@ public class DatasetServiceImpl implements DatasetService { | |||||
| @Override | @Override | ||||
| public List<Map<String, String>> uploadDataset(MultipartFile[] files, String uuid) throws Exception { | public List<Map<String, String>> uploadDataset(MultipartFile[] files, String uuid) throws Exception { | ||||
| List<Map<String, String>> results = new ArrayList<>(); | List<Map<String, String>> results = new ArrayList<>(); | ||||
| for (MultipartFile file:files){ | for (MultipartFile file:files){ | ||||
| // 构建objectName | // 构建objectName | ||||
| String username = SecurityUtils.getLoginUser().getUsername(); | String username = SecurityUtils.getLoginUser().getUsername(); | ||||
| @@ -259,7 +260,6 @@ public class DatasetServiceImpl implements DatasetService { | |||||
| if (dataset == null) { | if (dataset == null) { | ||||
| throw new Exception("数据集不存在,请检查数据集id"); | throw new Exception("数据集不存在,请检查数据集id"); | ||||
| } | } | ||||
| DatasetVersion version = datasetVersionService.queryByDatasetVersion(datasetVersion); | DatasetVersion version = datasetVersionService.queryByDatasetVersion(datasetVersion); | ||||
| String url = ""; | String url = ""; | ||||
| if (version == null) { | if (version == null) { | ||||
| @@ -221,7 +221,7 @@ public class ImageServiceImpl implements ImageService { | |||||
| if (imageVersionInsert == null) { | if (imageVersionInsert == null) { | ||||
| throw new Exception("新增镜像版本失败"); | throw new Exception("新增镜像版本失败"); | ||||
| } | } | ||||
| // 使用CompletableFuture异步执行不同的镜像构建逻辑 | |||||
| // 使用CompletableFuture异步执行不同的镜像构建逻辑,在构建镜像的同时,更新数据库中的镜像版本状态 | |||||
| CompletableFuture.supplyAsync(() -> { | CompletableFuture.supplyAsync(() -> { | ||||
| Map<String, String> resultMap = new HashMap<>(); | Map<String, String> resultMap = new HashMap<>(); | ||||
| try { | try { | ||||
| @@ -281,6 +281,7 @@ public class ImageServiceImpl implements ImageService { | |||||
| String pushCmd = "docker push " + imageUrl; | String pushCmd = "docker push " + imageUrl; | ||||
| String sizeCmd = "docker inspect --format='{{.Size}}' " + imageUrl; | String sizeCmd = "docker inspect --format='{{.Size}}' " + imageUrl; | ||||
| String s = k8sClientUtil.executeCommand(pod, tagCmd); | String s = k8sClientUtil.executeCommand(pod, tagCmd); | ||||
| if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))){ | if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))){ | ||||
| resultMap.put("url", imageUrl); | resultMap.put("url", imageUrl); | ||||
| //得到镜像文件大小 | //得到镜像文件大小 | ||||
| @@ -1,7 +1,9 @@ | |||||
| package com.ruoyi.platform.service.impl; | package com.ruoyi.platform.service.impl; | ||||
| import com.ruoyi.common.security.utils.SecurityUtils; | import com.ruoyi.common.security.utils.SecurityUtils; | ||||
| import com.ruoyi.platform.annotations.CheckDuplicate; | |||||
| import com.ruoyi.platform.domain.AssetIcon; | import com.ruoyi.platform.domain.AssetIcon; | ||||
| import com.ruoyi.platform.domain.Dataset; | |||||
| import com.ruoyi.platform.domain.Models; | import com.ruoyi.platform.domain.Models; | ||||
| import com.ruoyi.platform.domain.ModelsVersion; | import com.ruoyi.platform.domain.ModelsVersion; | ||||
| import com.ruoyi.platform.mapper.ModelsDao; | import com.ruoyi.platform.mapper.ModelsDao; | ||||
| @@ -34,6 +36,7 @@ import javax.annotation.Resource; | |||||
| import java.io.ByteArrayInputStream; | import java.io.ByteArrayInputStream; | ||||
| import java.io.ByteArrayOutputStream; | import java.io.ByteArrayOutputStream; | ||||
| import java.io.InputStream; | import java.io.InputStream; | ||||
| import java.lang.reflect.Field; | |||||
| import java.net.URLEncoder; | import java.net.URLEncoder; | ||||
| import java.util.*; | import java.util.*; | ||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
| @@ -116,8 +119,9 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| * @return 实例对象 | * @return 实例对象 | ||||
| */ | */ | ||||
| @Override | @Override | ||||
| public Models insert(Models models) { | |||||
| public Models insert(Models models) throws Exception { | |||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| checkDeclaredName(models); | |||||
| models.setCreateBy(loginUser.getUsername()); | models.setCreateBy(loginUser.getUsername()); | ||||
| models.setUpdateBy(loginUser.getUsername()); | models.setUpdateBy(loginUser.getUsername()); | ||||
| models.setUpdateTime(new Date()); | models.setUpdateTime(new Date()); | ||||
| @@ -173,8 +177,9 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| if (!(StringUtils.equals(username,"admin") || StringUtils.equals(username,createdBy))){ | if (!(StringUtils.equals(username,"admin") || StringUtils.equals(username,createdBy))){ | ||||
| throw new Exception("无权限删除该模型"); | throw new Exception("无权限删除该模型"); | ||||
| } | } | ||||
| if (modelsVersionService.queryByModelsId(id).size()>0){ | |||||
| throw new Exception("请先删除该镜像下的版本文件"); | |||||
| //判断是否有版本文件 | |||||
| if (!modelsVersionService.queryByModelsId(id).isEmpty()){ | |||||
| throw new Exception("请先删除该模型下的版本文件"); | |||||
| } | } | ||||
| models.setState(0); | models.setState(0); | ||||
| return this.modelsDao.update(models)>0?"删除成功":"删除失败"; | return this.modelsDao.update(models)>0?"删除成功":"删除失败"; | ||||
| @@ -427,6 +432,31 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| } | } | ||||
| @Override | |||||
| public void checkDeclaredName(Models insert) throws Exception { | |||||
| Models existingModel = modelsDao.findByName(insert.getName()); | |||||
| if (existingModel != null) { | |||||
| // Check if the found models is not the same as the one being inserted | |||||
| // This is important if you are using this method for both insert and update operations | |||||
| // You may need an identifier check here, e.g., if 'insert' has an ID and it's the same as 'existingDataset' | |||||
| if (insert.getId() != null && insert.getId().equals(existingModel.getId())) { | |||||
| // This is the same dataset, no duplicate name issue for update operation | |||||
| return; | |||||
| } | |||||
| // Now we know there's another dataset with the same name | |||||
| Field[] fields = Models.class.getDeclaredFields(); | |||||
| for (Field field : fields) { | |||||
| field.setAccessible(true); // Make private fields accessible | |||||
| if ("name".equals(field.getName()) && field.isAnnotationPresent(CheckDuplicate.class)) { | |||||
| // If the field is 'name' and is marked with CheckDuplicate annotation | |||||
| CheckDuplicate annotation = field.getAnnotation(CheckDuplicate.class); | |||||
| throw new Exception("重复的模型名称: " + insert.getName() + ". " + annotation.message()); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @Override | @Override | ||||
| public List<Map<String, String>> exportModels(String path, String uuid) throws Exception { | public List<Map<String, String>> exportModels(String path, String uuid) throws Exception { | ||||
| List<Map<String, String>> results = new ArrayList<>(); | List<Map<String, String>> results = new ArrayList<>(); | ||||
| @@ -31,6 +31,7 @@ | |||||
| from dataset | from dataset | ||||
| where name = #{name} and state = 1 limit 1 | where name = #{name} and state = 1 limit 1 | ||||
| </select> | </select> | ||||
| <!--查询指定行数据--> | <!--查询指定行数据--> | ||||
| <select id="queryAllByLimit" resultMap="DatasetMap"> | <select id="queryAllByLimit" resultMap="DatasetMap"> | ||||
| select | select | ||||
| @@ -24,6 +24,14 @@ | |||||
| where id = #{id} and state = 1 | where id = #{id} and state = 1 | ||||
| </select> | </select> | ||||
| <!--查询单个--> | |||||
| <select id="findByName" resultMap="ModelsMap"> | |||||
| select | |||||
| id, name, description,available_range, model_type,model_tag, create_by, create_time, update_by, update_time, state | |||||
| from models | |||||
| where name = #{name} and state = 1 limit 1 | |||||
| </select> | |||||
| <!--查询指定行数据--> | <!--查询指定行数据--> | ||||
| <select id="queryAllByLimit" resultMap="ModelsMap"> | <select id="queryAllByLimit" resultMap="ModelsMap"> | ||||
| select | select | ||||