diff --git a/.gitignore b/.gitignore index 5510490a..54c883c5 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,8 @@ mvnw **/node_modules *storybook.log + +/react-ui/docs +/react-ui/types/tsconfig.tsbuildinfo +/react-ui/storybook-static +/react-ui/.storybook/scripts diff --git a/k8s/build_and_deploy.sh b/k8s/build_and_deploy.sh index 6e561cdd..dcf6c1b9 100755 --- a/k8s/build_and_deploy.sh +++ b/k8s/build_and_deploy.sh @@ -61,7 +61,7 @@ if [[ ! " ${valid_services[@]} " =~ " $service " ]]; then exit 1 fi -valid_envs=("dev" "test") +valid_envs=("dev" "test" "test1") if [[ ! " ${valid_envs[@]} " =~ " $env " ]]; then echo "Invalid environment: $env" >&2 echo "Valid environments are: ${valid_envs[*]}" diff --git a/k8s/deploy.sh b/k8s/deploy.sh index 2dffc04f..6e9d2974 100755 --- a/k8s/deploy.sh +++ b/k8s/deploy.sh @@ -34,7 +34,7 @@ if [[ ! " ${valid_services[@]} " =~ " $service " ]]; then exit 1 fi -valid_envs=("dev" "test") +valid_envs=("dev" "test" "test1") if [[ ! " ${valid_envs[@]} " =~ " $env " ]]; then echo "Invalid environment: $env" >&2 echo "Valid environments are: ${valid_envs[*]}" @@ -46,6 +46,8 @@ if [ "$env" == "dev" ]; then remote_ip="172.20.32.197" elif [ "$env" == "test" ]; then remote_ip="172.20.32.185" +elif [ "$env" == "test1" ]; then + remote_ip="172.20.32.235" else echo "Invalid environment - $env" exit 1 diff --git a/k8s/template-yaml/k8s-6system.yaml b/k8s/template-yaml/k8s-6system.yaml index cc17e5ea..3691116c 100644 --- a/k8s/template-yaml/k8s-6system.yaml +++ b/k8s/template-yaml/k8s-6system.yaml @@ -18,7 +18,11 @@ spec: image: ${k8s-6system-image} ports: - containerPort: 9201 - + env: + - name: TZ + value: Asia/Shanghai + - name: JAVA_TOOL_OPTIONS + value: "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005" --- apiVersion: v1 kind: Service @@ -28,9 +32,15 @@ metadata: spec: type: NodePort ports: - - port: 9201 + - name: http + port: 9201 nodePort: 31207 protocol: TCP + - name: debug + nodePort: 31220 + port: 5005 + protocol: TCP + targetPort: 5005 selector: app: ci4s-system diff --git a/react-ui/.storybook/babel-plugin-auto-css-modules.js b/react-ui/.storybook/babel-plugin-auto-css-modules.js index 9c7709ff..660744b4 100644 --- a/react-ui/.storybook/babel-plugin-auto-css-modules.js +++ b/react-ui/.storybook/babel-plugin-auto-css-modules.js @@ -4,7 +4,6 @@ export default function(babel) { visitor: { ImportDeclaration(path) { const source = path.node.source.value; - // console.log("zzzz", source); if (source.endsWith('.less')) { if (path.node.specifiers.length > 0) { path.node.source.value += "?modules"; diff --git a/react-ui/.storybook/main.ts b/react-ui/.storybook/main.ts index 820a0eeb..c21ab45b 100644 --- a/react-ui/.storybook/main.ts +++ b/react-ui/.storybook/main.ts @@ -16,7 +16,11 @@ const config: StorybookConfig = { name: '@storybook/react-webpack5', options: {}, }, - staticDirs: ['../public'], + staticDirs: [ + '../public', + { from: '../docs', to: '/docs' }, + { from: '../docs/index.html', to: '/docs/index.html' }, + ], docs: { defaultName: 'Documentation', }, diff --git a/react-ui/Dockerfile b/react-ui/Dockerfile new file mode 100644 index 00000000..077c862f --- /dev/null +++ b/react-ui/Dockerfile @@ -0,0 +1,3 @@ +# Dockerfile +FROM nginx:alpine +COPY storybook-static/ /usr/share/nginx/html \ No newline at end of file diff --git a/react-ui/README.md b/react-ui/README.md index 2cf4d673..7d8b3af5 100644 --- a/react-ui/README.md +++ b/react-ui/README.md @@ -1,133 +1 @@ -Language : 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇵🇹](./README.pt-BR.md) | [🇸🇦](./README.ar-DZ.md) - -

Ant Design Pro

- -
- -An out-of-box UI solution for enterprise applications as a React boilerplate. - -[![Build Status](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=master) ![Github Action](https://github.com/ant-design/ant-design-pro/workflows/Node%20CI/badge.svg) ![Deploy](https://github.com/ant-design/ant-design-pro/workflows/Deploy%20CI/badge.svg) - -[![Gitter](https://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Join the chat at https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label) - -![](https://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png) - -
- -- Preview: http://preview.pro.ant.design -- Home Page: http://pro.ant.design -- Documentation: http://pro.ant.design/docs/getting-started -- ChangeLog: http://pro.ant.design/docs/changelog -- FAQ: http://pro.ant.design/docs/faq -- Mirror Site in China: http://ant-design-pro.gitee.io - -## 5.0 is out! 🎉🎉🎉 - -[Ant Design Pro 5.0.0](https://github.com/ant-design/ant-design-pro/issues/8656) - -## Translation Recruitment :loudspeaker: - -We need your help: https://github.com/ant-design/ant-design-pro/issues/120 - -## Features - -- :bulb: **TypeScript**: A language for application-scale JavaScript -- :scroll: **Blocks**: Build page with block template -- :gem: **Neat Design**: Follow [Ant Design specification](http://ant.design/) -- :triangular_ruler: **Common Templates**: Typical templates for enterprise applications -- :rocket: **State of The Art Development**: Newest development stack of React/umi/dva/antd -- :iphone: **Responsive**: Designed for variable screen sizes -- :art: **Theming**: Customizable theme with simple config -- :globe_with_meridians: **International**: Built-in i18n solution -- :gear: **Best Practices**: Solid workflow to make your code healthy -- :1234: **Mock development**: Easy to use mock development solution -- :white_check_mark: **UI Test**: Fly safely with unit and e2e tests - -## Templates - -``` -- Dashboard - - Analytic - - Monitor - - Workspace -- Form - - Basic Form - - Step Form - - Advanced From -- List - - Standard Table - - Standard List - - Card List - - Search List (Project/Applications/Article) -- Profile - - Simple Profile - - Advanced Profile -- Account - - Account Center - - Account Settings -- Result - - Success - - Failed -- Exception - - 403 - - 404 - - 500 -- User - - Login - - Register - - Register Result -``` - -## Usage - -### Use bash - -We provide pro-cli to quickly initialize scaffolding. - -```bash -# use npm -npm i @ant-design/pro-cli -g -pro create myapp -``` - -select umi version - -```shell -🐂 Use umi@4 or umi@3 ? (Use arrow keys) -❯ umi@4 - umi@3 -``` - -> If the umi@4 version is selected, full blocks are not yet supported. - -If you choose umi@3, you can also choose the pro template. Pro is the basic template, which only provides the basic content of the framework operation. Complete contains all blocks, which is not suitable for secondary development as a basic template. - -```shell -? 🚀 Full or a simple scaffold? (Use arrow keys) -❯ simple - complete -``` - -Install dependencies: - -```shell -$ cd myapp && tyarn -// or -$ cd myapp && npm install -``` - -## Browsers support - -Modern browsers. - -| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | -| --- | --- | --- | --- | --- | -| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions | - -## Contributing - -Any type of contribution is welcome, here are some examples of how you may contribute to this project: - -- Use Ant Design Pro in your daily work. -- Submit [issues](http://github.com/ant-design/ant-design-pro/issues) to report bugs or ask questions. -- Propose [pull requests](http://github.com/ant-design/ant-design-pro/pulls) to improve our code. +# Documentation \ No newline at end of file diff --git a/react-ui/config/routes.ts b/react-ui/config/routes.ts index b2c41f14..bf012a65 100644 --- a/react-ui/config/routes.ts +++ b/react-ui/config/routes.ts @@ -143,6 +143,11 @@ export default [ path: 'compare', component: './Experiment/Comparison/index', }, + { + name: '实验可视化对比', + path: 'compare-visual', + component: './Experiment/Aim/index', + }, ], }, { @@ -271,7 +276,18 @@ export default [ { name: '镜像详情', path: 'info/:id', - component: './Mirror/Info', + routes: [ + { + name: '镜像详情', + path: '', + component: './Mirror/Info', + }, + { + name: '新增镜像版本', + path: 'add-version', + component: './Mirror/Create', + }, + ], }, { name: '创建镜像', @@ -345,7 +361,6 @@ export default [ }, ], }, - { name: '应用开发', path: '/appsDeployment', @@ -498,6 +513,18 @@ export default [ }, ], }, + { + name: '算力积分', + path: '/points', + routes: [ + { + name: '算力积分', + path: '', + key: 'points', + component: './Points/index', + }, + ], + }, { path: '*', layout: false, diff --git a/react-ui/package.json b/react-ui/package.json index fbc014d1..c614d920 100644 --- a/react-ui/package.json +++ b/react-ui/package.json @@ -1,8 +1,8 @@ { - "name": "ant-design-pro", - "version": "6.0.0", + "name": "cl-model", + "version": "1.0.0", "private": true, - "description": "An out-of-box UI solution for enterprise applications", + "description": "", "scripts": { "analyze": "cross-env ANALYZE=1 max build", "build": "max build", @@ -16,6 +16,7 @@ "docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up", "docker:push": "npm run docker-hub:build && npm run docker:tag && docker push antdesign/ant-design-pro", "docker:tag": "docker tag ant-design-pro antdesign/ant-design-pro", + "docs": "typedoc", "gh-pages": "gh-pages -d dist", "i18n-remove": "pro i18n-remove --locale=zh-CN --write", "postinstall": "max setup", @@ -39,6 +40,7 @@ "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev", "storybook": "storybook dev -p 6006", "storybook-build": "storybook build", + "storybook-deploy": "./.storybook/scripts/upload-deploy.sh", "storybook-docs": "storybook dev --docs", "storybook-docs-build": "storybook build --docs", "test": "jest", @@ -66,6 +68,7 @@ "@types/crypto-js": "^4.2.2", "@umijs/route-utils": "^4.0.1", "antd": "~5.21.4", + "caniuse-lite": "~1.0.30001707", "classnames": "^2.3.2", "crypto-js": "^4.2.0", "echarts": "^5.5.0", @@ -132,6 +135,7 @@ "swagger-ui-dist": "^4.18.2", "ts-loader": "~9.5.2", "ts-node": "^10.9.1", + "typedoc": "~0.28.1", "typescript": "^5.0.4", "umi-presets-pro": "^2.0.0" }, diff --git a/react-ui/public/fonts/DingTalk-JinBuTi.ttf b/react-ui/public/fonts/DingTalk-JinBuTi.ttf new file mode 100644 index 00000000..c4efa55a Binary files /dev/null and b/react-ui/public/fonts/DingTalk-JinBuTi.ttf differ diff --git a/react-ui/public/fonts/DingTalk-JinBuTi.woff b/react-ui/public/fonts/DingTalk-JinBuTi.woff new file mode 100644 index 00000000..5a8efa8e Binary files /dev/null and b/react-ui/public/fonts/DingTalk-JinBuTi.woff differ diff --git a/react-ui/public/fonts/DingTalk-JinBuTi.woff2 b/react-ui/public/fonts/DingTalk-JinBuTi.woff2 new file mode 100644 index 00000000..c8d272a5 Binary files /dev/null and b/react-ui/public/fonts/DingTalk-JinBuTi.woff2 differ diff --git a/react-ui/public/fonts/font.css b/react-ui/public/fonts/font.css index ea5ffc5c..012b9f59 100644 --- a/react-ui/public/fonts/font.css +++ b/react-ui/public/fonts/font.css @@ -1,5 +1,13 @@ @font-face { - font-family: Alibaba; - src: url('./ALIBABA-PUHUITI-MEDIUM.TTF'); - font-display: swap; - } \ No newline at end of file + font-family: Alibaba; + src: url('./ALIBABA-PUHUITI-MEDIUM.TTF'); + font-display: swap; +} + +@font-face { + font-family: 'DingTalk-JinBuTi'; + src: url('./DingTalk-JinBuTi.woff2') format('woff2'), /* 最优先使用 woff2 */ + url('./DingTalk-JinBuTi.woff') format('woff'), /* 兼容性较好的 woff */ + url('./DingTalk-JinBuTi.ttf') format('truetype'); /* ttf 作为备选 */ + font-display: swap; /* 优化页面加载时的字体显示 */ +} \ No newline at end of file diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx index 7c026d3d..6ef5c5b8 100644 --- a/react-ui/src/app.tsx +++ b/react-ui/src/app.tsx @@ -1,13 +1,16 @@ import RightContent from '@/components/RightContent'; import themes from '@/styles/theme.less'; +import { type GlobalInitialState } from '@/types'; +import { menuItemRender } from '@/utils/menuRender'; import type { Settings as LayoutSettings } from '@ant-design/pro-components'; import { RuntimeConfig, history } from '@umijs/max'; import { RuntimeAntdConfig } from 'umi'; import defaultSettings from '../config/defaultSettings'; import '../public/fonts/font.css'; import { getAccessToken } from './access'; +import ErrorBoundary from './components/ErrorBoundary'; import './dayjsConfig'; -import { removeAllPageCacheState } from './hooks/pageCacheState'; +import { removeAllPageCacheState } from './hooks/useCacheState'; import { getRemoteMenu, getRoutersInfo, @@ -16,14 +19,9 @@ import { setRemoteMenu, } from './services/session'; import './styles/menu.less'; -export { requestConfig as request } from './requestConfig'; -// const isDev = process.env.NODE_ENV === 'development'; -import { type GlobalInitialState } from '@/types'; -// import '@/utils/clipboard'; -import { menuItemRender } from '@/utils/menuRender'; -import ErrorBoundary from './components/ErrorBoundary'; import { needAuth } from './utils'; import { gotoLoginPage } from './utils/ui'; +export { requestConfig as request } from './requestConfig'; /** * @see https://umijs.org/zh-CN/plugins/plugin-initial-state @@ -139,7 +137,6 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => { onClick: () => { // 点击菜单项,删除所有的页面 state 缓存 removeAllPageCacheState(); - // console.log('click menu'); }, }, ...initialState?.settings, diff --git a/react-ui/src/assets/img/confirm-icon.png b/react-ui/src/assets/img/confirm-icon.png new file mode 100644 index 00000000..6865b719 Binary files /dev/null and b/react-ui/src/assets/img/confirm-icon.png differ diff --git a/react-ui/src/assets/img/comfirm-icon.png b/react-ui/src/assets/img/copy-icon.png similarity index 100% rename from react-ui/src/assets/img/comfirm-icon.png rename to react-ui/src/assets/img/copy-icon.png diff --git a/react-ui/src/assets/img/user-points-bg.png b/react-ui/src/assets/img/user-points-bg.png new file mode 100644 index 00000000..3f25b128 Binary files /dev/null and b/react-ui/src/assets/img/user-points-bg.png differ diff --git a/react-ui/src/assets/img/workspace-experiment.png b/react-ui/src/assets/img/workspace-experiment.png index bcd69981..0bca4327 100644 Binary files a/react-ui/src/assets/img/workspace-experiment.png and b/react-ui/src/assets/img/workspace-experiment.png differ diff --git a/react-ui/src/assets/img/workspace-pipeline.png b/react-ui/src/assets/img/workspace-pipeline.png index fbbc3ed7..f551cb9c 100644 Binary files a/react-ui/src/assets/img/workspace-pipeline.png and b/react-ui/src/assets/img/workspace-pipeline.png differ diff --git a/react-ui/src/components/CodeConfigItem/index.tsx b/react-ui/src/components/CodeConfigItem/index.tsx index 673bca40..ff48368c 100644 --- a/react-ui/src/components/CodeConfigItem/index.tsx +++ b/react-ui/src/components/CodeConfigItem/index.tsx @@ -2,6 +2,7 @@ import { AvailableRange } from '@/enums'; import { type CodeConfigData } from '@/pages/CodeConfig/List'; import { Flex, Typography } from 'antd'; import classNames from 'classnames'; +import { useState } from 'react'; import styles from './index.less'; type CodeConfigItemProps = { @@ -10,6 +11,7 @@ type CodeConfigItemProps = { }; function CodeConfigItem({ item, onClick }: CodeConfigItemProps) { + const [isEllipsis, setIsEllipsis] = useState(false); return (
onClick?.(item)}> @@ -32,11 +34,20 @@ function CodeConfigItem({ item, onClick }: CodeConfigItemProps) { setIsEllipsis(ellipsis), + }} > {item.git_url} -
{item.git_branch}
+ + {item.git_branch} +
); } diff --git a/react-ui/src/utils/clipboard.js b/react-ui/src/components/CopyingText/clipboard.js similarity index 100% rename from react-ui/src/utils/clipboard.js rename to react-ui/src/components/CopyingText/clipboard.js diff --git a/react-ui/src/pages/AutoML/components/CopyingText/index.less b/react-ui/src/components/CopyingText/index.less similarity index 100% rename from react-ui/src/pages/AutoML/components/CopyingText/index.less rename to react-ui/src/components/CopyingText/index.less diff --git a/react-ui/src/components/CopyingText/index.tsx b/react-ui/src/components/CopyingText/index.tsx new file mode 100644 index 00000000..5a87ebe3 --- /dev/null +++ b/react-ui/src/components/CopyingText/index.tsx @@ -0,0 +1,26 @@ +import KFIcon from '@/components/KFIcon'; +import { Tooltip } from 'antd'; +import styles from './index.less'; + +export type CopyingTextProps = { + text: string; +}; + +function CopyingText({ text }: CopyingTextProps) { + return ( +
+ {text} + + + +
+ ); +} + +export default CopyingText; diff --git a/react-ui/src/components/IFramePage/index.tsx b/react-ui/src/components/IFramePage/index.tsx index aa292d47..cd08c7b7 100644 --- a/react-ui/src/components/IFramePage/index.tsx +++ b/react-ui/src/components/IFramePage/index.tsx @@ -3,6 +3,7 @@ import KFSpin from '@/components/KFSpin'; import { getLabelStudioUrl } from '@/services/developmentEnvironment'; import { to } from '@/utils/promise'; import SessionStorage from '@/utils/sessionStorage'; +import { FloatButton } from 'antd'; import classNames from 'classnames'; import { useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; @@ -13,6 +14,7 @@ export enum IframePageType { AppDevelopment = 'AppDevelopment', // 应用开发 DevEnv = 'DevEnv', // 开发环境 GitLink = 'GitLink', // git link + Aim = 'Aim', // 实验对比 } const getRequestAPI = (type: IframePageType): (() => Promise) => { @@ -29,12 +31,20 @@ const getRequestAPI = (type: IframePageType): (() => Promise) => { }); case IframePageType.GitLink: // git link return () => Promise.resolve({ code: 200, data: 'http://172.20.32.201:4000' }); + case IframePageType.Aim: // Aim + return () => + Promise.resolve({ + code: 200, + data: SessionStorage.getItem(SessionStorage.aimUrlKey) || '', + }); } }; type IframePageProps = { /** 子系统 */ type: IframePageType; + /** 是否可以在页签上打开 */ + openInTab?: boolean; /** 自定义样式类名 */ className?: string; /** 自定义样式 */ @@ -42,18 +52,15 @@ type IframePageProps = { }; /** 系统内嵌 iframe,目前系统有数据标注、应用开发、开发环境、GitLink 四个子系统,使用时可以添加其他子系统 */ -function IframePage({ type, className, style }: IframePageProps) { +function IframePage({ type, openInTab = false, className, style }: IframePageProps) { const [iframeUrl, setIframeUrl] = useState(''); const [loading, setLoading] = useState(false); useEffect(() => { const requestIframeUrl = async () => { - setLoading(true); const [res] = await to(getRequestAPI(type)()); if (res && res.data) { setIframeUrl(res.data); - } else { - setLoading(false); } }; @@ -68,6 +75,7 @@ function IframePage({ type, className, style }: IframePageProps) {
{loading && createPortal(, document.body)} + {openInTab && window.open(iframeUrl, '_blank')} />}
); } diff --git a/react-ui/src/components/ParameterInput/index.less b/react-ui/src/components/ParameterInput/index.less index fff69eb1..ff0a21f7 100644 --- a/react-ui/src/components/ParameterInput/index.less +++ b/react-ui/src/components/ParameterInput/index.less @@ -22,7 +22,7 @@ border-radius: 4px; &__value { - .singleLine(); + //.singleLine(); margin-right: 8px; font-size: @font-size-input; line-height: 1.5714285714285714; diff --git a/react-ui/src/components/ParameterInput/index.tsx b/react-ui/src/components/ParameterInput/index.tsx index 32672b98..08cf8649 100644 --- a/react-ui/src/components/ParameterInput/index.tsx +++ b/react-ui/src/components/ParameterInput/index.tsx @@ -6,7 +6,7 @@ import { CommonTabKeys } from '@/enums'; import { CloseOutlined } from '@ant-design/icons'; -import { ConfigProvider, Form, Input } from 'antd'; +import { ConfigProvider, Form, Input, Typography } from 'antd'; import { RuleObject } from 'antd/es/form'; import classNames from 'classnames'; import './index.less'; @@ -120,7 +120,12 @@ function ParameterInput({ > {valueObj?.showValue ? (
- {valueObj?.showValue} + + {valueObj.showValue} + void; } @@ -32,6 +36,7 @@ function ParameterSelect({ dataType, display = false, value, + isPipeline = false, onChange, ...rest }: ParameterSelectProps) { @@ -39,6 +44,12 @@ function ParameterSelect({ const propsConfig = paramSelectConfig[dataType]; const valueText = typeof value === 'object' && value !== null ? value.value : value; const [resourceStandardList] = useComputingResource(); + const computingResource = isPipeline + ? resourceStandardList.map((v) => ({ + ...v, + id: String(v.id), + })) + : resourceStandardList; useEffect(() => { // 获取下拉数据 @@ -56,7 +67,7 @@ function ParameterSelect({ getSelectOptions(); }, [propsConfig]); - const selectOptions = dataType === 'resource' ? resourceStandardList : options; + const selectOptions = dataType === 'resource' ? computingResource : options; const handleChange = (text: string) => { if (typeof value === 'object' && value !== null) { diff --git a/react-ui/src/components/ResourceSelect/index.tsx b/react-ui/src/components/ResourceSelect/index.tsx index a7e02ce3..ccec75f1 100644 --- a/react-ui/src/components/ResourceSelect/index.tsx +++ b/react-ui/src/components/ResourceSelect/index.tsx @@ -6,7 +6,7 @@ import KFIcon from '@/components/KFIcon'; import ResourceSelectorModal, { - ResourceSelectorResponse, + type ResourceSelectorResponse, ResourceSelectorType, selectorTypeConfig, } from '@/components/ResourceSelectorModal'; diff --git a/react-ui/src/components/ResourceSelectorModal/config.tsx b/react-ui/src/components/ResourceSelectorModal/config.tsx index 80e3ab3c..5dc7b961 100644 --- a/react-ui/src/components/ResourceSelectorModal/config.tsx +++ b/react-ui/src/components/ResourceSelectorModal/config.tsx @@ -224,6 +224,8 @@ export class MirrorSelector implements SelectorTypeInfo { image_id: parentKey, page: 0, size: 2000, + status: 'available', + state: 1, }); if (res && res.data) { const list = res.data.content || []; diff --git a/react-ui/src/components/RightContent/AvatarDropdown.tsx b/react-ui/src/components/RightContent/AvatarDropdown.tsx index d93d4f74..fc1fceeb 100644 --- a/react-ui/src/components/RightContent/AvatarDropdown.tsx +++ b/react-ui/src/components/RightContent/AvatarDropdown.tsx @@ -3,7 +3,7 @@ import { setRemoteMenu } from '@/services/session'; import { logout } from '@/services/system/auth'; import { ClientInfo } from '@/types'; import SessionStorage from '@/utils/sessionStorage'; -import { gotoLoginPage } from '@/utils/ui'; +import { gotoLoginPage, oauthLogout } from '@/utils/ui'; import { LogoutOutlined, UserOutlined } from '@ant-design/icons'; import { setAlpha } from '@ant-design/pro-components'; import { useEmotionCss } from '@ant-design/use-emotion-css'; @@ -62,6 +62,7 @@ const AvatarDropdown: React.FC = ({ menu }) => { * 退出登录,并且将当前的 url 保存 */ const loginOut = async () => { + oauthLogout('http://172.20.32.197:31209/oauth/logout'); await logout(); clearSessionToken(); setRemoteMenu(null); diff --git a/react-ui/src/global.less b/react-ui/src/global.less index 9944c70e..df79e9f7 100644 --- a/react-ui/src/global.less +++ b/react-ui/src/global.less @@ -160,3 +160,8 @@ ol { input:-webkit-autofill { transition: background-color 5000s ease-in-out 0s; } + +.ant-typography { + color: inherit; + font-size: inherit; +} diff --git a/react-ui/src/hooks/index.ts b/react-ui/src/hooks/index.ts deleted file mode 100644 index 59ba1d6e..00000000 --- a/react-ui/src/hooks/index.ts +++ /dev/null @@ -1,202 +0,0 @@ -/* - * @Author: 赵伟 - * @Date: 2024-04-15 10:01:29 - * @Description: 自定义 hooks - */ -import { FormInstance } from 'antd'; -import { debounce } from 'lodash'; -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -/** - * 生成具有初始值的状态引用 - * - * @param initialValue - 状态的初始值 - * @return 包含状态值、状态设置函数和可变引用对象的数组 - */ -export function useStateRef(initialValue: T) { - const [value, setValue] = useState(initialValue); - - const ref = useRef(value); - - useEffect(() => { - ref.current = value; - }, [value]); - - return [value, setValue, ref] as const; -} - -/** - * 生成一个自定义钩子,用于管理模态框的可见性状态。 - * - * @param initialValue - 模态框的初始可见性状态。 - * @return 一个数组,包含可见性状态和打开和关闭模态框的函数。 - */ -export function useVisible(initialValue: boolean) { - const [visible, setVisible] = useState(initialValue); - const ref = useRef(initialValue); - - const open = useCallback(() => { - setVisible(true); - }, []); - - const close = useCallback(() => { - setVisible(false); - }, []); - - useEffect(() => { - ref.current = visible; - }, [visible]); - - return [visible, open, close, ref] as const; -} - -type Callback = (state: T) => void; - -/** - * 生成一个具有回调机制的可变状态值和更新它的函数。 - * - * @param initialValue - 初始状态值。 - * @return 一个元组,包含当前状态值和用于更新状态的函数。 - */ -export function useCallbackState(initialValue: T) { - const [state, _setState] = useState(initialValue); - const callbackQueue = useRef[]>([]); - useEffect(() => { - callbackQueue.current.forEach((cb) => cb(state)); - callbackQueue.current = []; - }, [state]); - const setState = (newValue: T | ((prevState: T) => T), callback?: Callback) => { - _setState(newValue); - if (callback && typeof callback === 'function') { - callbackQueue.current.push(callback); - } - }; - return [state, setState] as const; -} - -/** - * 用于追踪 DOM 元素尺寸的 hook。 - * - * @param initialWidth - 初始宽度。 - * @param initialHeight - 初始高度。 - * @param deps - 依赖列表。 - * @return 一个元组,包含 DOM 元素的 ref、当前宽度和当前高度。 - */ -export function useDomSize( - initialWidth: number, - initialHeight: number, - deps: React.DependencyList = [], -) { - const domRef = useRef(null); - const [width, setWidth] = useState(initialWidth); - const [height, setHeight] = useState(initialHeight); - - useEffect(() => { - const setDomHeight = () => { - if (domRef.current) { - setHeight(domRef.current.offsetHeight); - setWidth(domRef.current.offsetWidth); - } - }; - const debounceFunc = debounce(setDomHeight, 100); - - setDomHeight(); - window.addEventListener('resize', debounceFunc); - - return () => { - window.removeEventListener('resize', debounceFunc); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [domRef, ...deps]); - - return [domRef, { width, height }] as const; -} - -/** - * 用于在 modal 关闭时重置 Form 表单的 hook。 - * - * @param form - Ant Design Form 表单实例 - * @param open - modal 是否打开 - */ -export const useResetFormOnCloseModal = (form: FormInstance, open: boolean) => { - const prevOpenRef = useRef(); - - useEffect(() => { - prevOpenRef.current = open; - }, [open]); - - const prevOpen = prevOpenRef.current; - - useEffect(() => { - if (!open && prevOpen) { - form.resetFields(); - } - }, [form, prevOpen, open]); -}; - -/** - * Executes the effect function when the specified condition is true. - * - * @param effect - The effect function to execute. - * @param when - The condition to trigger the effect. - * @param deps - The dependencies for the effect. - */ -export const useEffectWhen = (effect: () => void, when: boolean, deps: React.DependencyList) => { - const requestFns = useRef<(() => void)[]>([]); - useEffect(() => { - if (when) { - effect(); - } else { - requestFns.current.splice(0, 1, effect); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps); - - useEffect(() => { - if (when) { - const fn = requestFns.current.pop(); - fn?.(); - } - }, [when]); -}; - -// 选择、全选操作 -export const useCheck = (list: T[]) => { - const [selected, setSelected] = useState([]); - - const checked = useMemo(() => { - return selected.length === list.length && selected.length > 0; - }, [selected, list]); - - const indeterminate = useMemo(() => { - return selected.length > 0 && selected.length < list.length; - }, [selected, list]); - - const checkAll = useCallback(() => { - setSelected(checked ? [] : list); - }, [list, checked]); - - const isSingleChecked = useCallback((item: T) => selected.includes(item), [selected]); - - const checkSingle = useCallback( - (item: T) => { - setSelected((prev) => { - if (isSingleChecked(item)) { - return prev.filter((i) => i !== item); - } else { - return [...prev, item]; - } - }); - }, - [isSingleChecked], - ); - - return [ - selected, - setSelected, - checked, - indeterminate, - checkAll, - isSingleChecked, - checkSingle, - ] as const; -}; diff --git a/react-ui/src/hooks/pageCacheState.ts b/react-ui/src/hooks/useCacheState.ts similarity index 94% rename from react-ui/src/hooks/pageCacheState.ts rename to react-ui/src/hooks/useCacheState.ts index e320b0a6..78b16fa7 100644 --- a/react-ui/src/hooks/pageCacheState.ts +++ b/react-ui/src/hooks/useCacheState.ts @@ -29,13 +29,18 @@ const removeCacheState = (key: string) => { } }; -// 移除所有页面 state 缓存 +/** + * 移除所有页面 state 缓存 + */ export const removeAllPageCacheState = () => { pageKeys.forEach((key) => { sessionStorage.removeItem(key); }); }; +/** + * 缓存页面数据 + */ export const useCacheState = () => { const { pathname } = window.location; const key = 'pagecache:' + pathname; diff --git a/react-ui/src/hooks/useCallbackState.ts b/react-ui/src/hooks/useCallbackState.ts new file mode 100644 index 00000000..820e770b --- /dev/null +++ b/react-ui/src/hooks/useCallbackState.ts @@ -0,0 +1,25 @@ +import { useEffect, useRef, useState } from 'react'; + +type Callback = (state: T) => void; + +/** + * 生成一个具有回调机制的可变状态值和更新它的函数。谨慎使用 + * + * @param initialValue - 初始状态值。 + * @return 一个元组,包含当前状态值和用于更新状态的函数。 + */ +export function useCallbackState(initialValue: T) { + const [state, _setState] = useState(initialValue); + const callbackQueue = useRef[]>([]); + useEffect(() => { + callbackQueue.current.forEach((cb) => cb(state)); + callbackQueue.current = []; + }, [state]); + const setState = (newValue: T | ((prevState: T) => T), callback?: Callback) => { + _setState(newValue); + if (callback && typeof callback === 'function') { + callbackQueue.current.push(callback); + } + }; + return [state, setState] as const; +} diff --git a/react-ui/src/hooks/useCheck.ts b/react-ui/src/hooks/useCheck.ts new file mode 100644 index 00000000..3c9c985b --- /dev/null +++ b/react-ui/src/hooks/useCheck.ts @@ -0,0 +1,47 @@ +import { useCallback, useMemo, useState } from 'react'; + +/** + * 选择、全选操作 + * @param list - 需要进行选择的列表 + * @return [选中的项, 设置选中的方法, 是否全选, 是否部分选中, 全选方法,是否单个选中,选中单个方法] + */ +export const useCheck = (list: T[]) => { + const [selected, setSelected] = useState([]); + + const checked = useMemo(() => { + return selected.length === list.length && selected.length > 0; + }, [selected, list]); + + const indeterminate = useMemo(() => { + return selected.length > 0 && selected.length < list.length; + }, [selected, list]); + + const checkAll = useCallback(() => { + setSelected(checked ? [] : list); + }, [list, checked]); + + const isSingleChecked = useCallback((item: T) => selected.includes(item), [selected]); + + const checkSingle = useCallback( + (item: T) => { + setSelected((prev) => { + if (isSingleChecked(item)) { + return prev.filter((i) => i !== item); + } else { + return [...prev, item]; + } + }); + }, + [isSingleChecked], + ); + + return [ + selected, + setSelected, + checked, + indeterminate, + checkAll, + isSingleChecked, + checkSingle, + ] as const; +}; diff --git a/react-ui/src/hooks/resource.ts b/react-ui/src/hooks/useComputingResource.ts similarity index 95% rename from react-ui/src/hooks/resource.ts rename to react-ui/src/hooks/useComputingResource.ts index e1e27506..b2239247 100644 --- a/react-ui/src/hooks/resource.ts +++ b/react-ui/src/hooks/useComputingResource.ts @@ -12,7 +12,7 @@ import { useCallback, useEffect, useState } from 'react'; const computingResource: ComputingResource[] = []; -// 过滤资源规格 +/** 过滤资源规格 */ export const filterResourceStandard: SelectProps['filterOption'] = ( input: string, option?: ComputingResource, @@ -22,13 +22,13 @@ export const filterResourceStandard: SelectProps['fil ); }; -// 资源规格字段 +/** 资源规格字段 */ export const resourceFieldNames = { label: 'description', value: 'id', }; -// 获取资源规格 +/** 获取资源规格 */ export function useComputingResource() { const [resourceStandardList, setResourceStandardList] = useState([]); diff --git a/react-ui/src/hooks/useDomSize.ts b/react-ui/src/hooks/useDomSize.ts new file mode 100644 index 00000000..ba1992ea --- /dev/null +++ b/react-ui/src/hooks/useDomSize.ts @@ -0,0 +1,40 @@ +import { debounce } from 'lodash'; +import { useEffect, useRef, useState } from 'react'; + +/** + * 用于追踪 DOM 元素尺寸的 hook。 + * + * @param initialWidth - 初始宽度。 + * @param initialHeight - 初始高度。 + * @param deps - 依赖列表。 + * @return 一个元组,包含 DOM 元素的 ref、当前宽度和当前高度。 + */ +export function useDomSize( + initialWidth: number, + initialHeight: number, + deps: React.DependencyList = [], +) { + const domRef = useRef(null); + const [width, setWidth] = useState(initialWidth); + const [height, setHeight] = useState(initialHeight); + + useEffect(() => { + const setDomHeight = () => { + if (domRef.current) { + setHeight(domRef.current.offsetHeight); + setWidth(domRef.current.offsetWidth); + } + }; + const debounceFunc = debounce(setDomHeight, 100); + + setDomHeight(); + window.addEventListener('resize', debounceFunc); + + return () => { + window.removeEventListener('resize', debounceFunc); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, deps); + + return [domRef, { width, height }] as const; +} diff --git a/react-ui/src/hooks/draggable.ts b/react-ui/src/hooks/useDraggable.ts similarity index 91% rename from react-ui/src/hooks/draggable.ts rename to react-ui/src/hooks/useDraggable.ts index b093ea6f..121aaafa 100644 --- a/react-ui/src/hooks/draggable.ts +++ b/react-ui/src/hooks/useDraggable.ts @@ -1,6 +1,8 @@ -// 处理 react-draggable 组件拖动结束时,响应了点击事件的 import { useState } from 'react'; +/** + * 处理 react-draggable 组件拖动结束时,响应了点击事件的 + */ export const useDraggable = (onClick: () => void) => { const [isDragging, setIsDragging] = useState(false); diff --git a/react-ui/src/hooks/useEffectWhen.ts b/react-ui/src/hooks/useEffectWhen.ts new file mode 100644 index 00000000..12f1aad0 --- /dev/null +++ b/react-ui/src/hooks/useEffectWhen.ts @@ -0,0 +1,24 @@ +import { useEffect, useRef } from 'react'; + +/** + * 当指定的条件为真时执行 Effect 函数。 + * + * @param effect - The effect function to execute. + * @param when - The condition to trigger the effect. + * @param deps - The dependencies for the effect. + */ +export const useEffectWhen = (effect: () => void, when: boolean, deps: React.DependencyList) => { + const requestFn = useRef<(() => void) | undefined>(effect); + useEffect(() => { + requestFn.current = effect; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [...deps, effect]); + + useEffect(() => { + if (when && requestFn.current) { + requestFn.current(); + requestFn.current = undefined; + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [...deps, when]); +}; diff --git a/react-ui/src/hooks/useResetForm.ts b/react-ui/src/hooks/useResetForm.ts new file mode 100644 index 00000000..acefd84e --- /dev/null +++ b/react-ui/src/hooks/useResetForm.ts @@ -0,0 +1,24 @@ +import { FormInstance } from 'antd'; +import { useEffect, useRef } from 'react'; + +/** + * 用于在 modal 关闭时重置 Form 表单的 hook。 + * + * @param form - Ant Design Form 表单实例 + * @param open - modal 是否打开 + */ +export const useResetForm = (form: FormInstance, open: boolean) => { + const prevOpenRef = useRef(); + + useEffect(() => { + prevOpenRef.current = open; + }, [open]); + + const prevOpen = prevOpenRef.current; + + useEffect(() => { + if (!open && prevOpen) { + form.resetFields(); + } + }, [form, prevOpen, open]); +}; diff --git a/react-ui/src/hooks/useSSE.ts b/react-ui/src/hooks/useSSE.ts new file mode 100644 index 00000000..5e278675 --- /dev/null +++ b/react-ui/src/hooks/useSSE.ts @@ -0,0 +1,46 @@ +import { parseJsonText } from '@/utils'; +import { useCallback, useRef } from 'react'; + +export const useSSE = (onMessage: (data: any) => void) => { + const evtSourceRef = useRef(null); + + const setupSSE = useCallback( + (name: string, namespace: string) => { + const { origin } = location; + const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); + const evtSource = new EventSource( + `${origin}/api/v1/realtimeStatus?listOptions.fieldSelector=${params}`, + { withCredentials: false }, + ); + evtSource.onmessage = (event) => { + const data = event?.data; + if (!data) { + return; + } + const dataJson = parseJsonText(data); + if (dataJson) { + const nodes = dataJson?.result?.object?.status?.nodes; + if (nodes) { + onMessage(nodes); + } + } + }; + + evtSource.onerror = (error) => { + console.error('SSE error: ', error); + }; + + evtSourceRef.current = evtSource; + }, + [onMessage], + ); + + const closeSSE = useCallback(() => { + if (evtSourceRef.current) { + evtSourceRef.current.close(); + evtSourceRef.current = null; + } + }, []); + + return [setupSSE, closeSSE]; +}; diff --git a/react-ui/src/hooks/useStateRef.ts b/react-ui/src/hooks/useStateRef.ts new file mode 100644 index 00000000..5cc260b3 --- /dev/null +++ b/react-ui/src/hooks/useStateRef.ts @@ -0,0 +1,19 @@ +import { useEffect, useRef, useState } from 'react'; + +/** + * 生成具有初始值的状态引用 + * + * @param initialValue - 状态的初始值 + * @return 包含状态值、状态设置函数和可变引用对象的数组 + */ +export function useStateRef(initialValue: T) { + const [value, setValue] = useState(initialValue); + + const ref = useRef(value); + + useEffect(() => { + ref.current = value; + }, [value]); + + return [value, setValue, ref] as const; +} diff --git a/react-ui/src/hooks/useVisible.ts b/react-ui/src/hooks/useVisible.ts new file mode 100644 index 00000000..461fa3c8 --- /dev/null +++ b/react-ui/src/hooks/useVisible.ts @@ -0,0 +1,26 @@ +import { useCallback, useEffect, useRef, useState } from 'react'; + +/** + * 生成一个自定义钩子,用于管理模态框的可见性状态。 + * + * @param initialValue - 模态框的初始可见性状态。 + * @return 一个数组,包含 visible、打开函数、关闭函数和 visible ref。 + */ +export function useVisible(initialValue: boolean) { + const [visible, setVisible] = useState(initialValue); + const ref = useRef(initialValue); + + const open = useCallback(() => { + setVisible(true); + }, []); + + const close = useCallback(() => { + setVisible(false); + }, []); + + useEffect(() => { + ref.current = visible; + }, [visible]); + + return [visible, open, close, ref] as const; +} diff --git a/react-ui/src/overrides.less b/react-ui/src/overrides.less index 4709a97c..e129b4a7 100644 --- a/react-ui/src/overrides.less +++ b/react-ui/src/overrides.less @@ -261,8 +261,3 @@ } } } - -.ant-typography { - color: inherit; - font-size: inherit; -} diff --git a/react-ui/src/pages/AutoML/Instance/index.tsx b/react-ui/src/pages/AutoML/Instance/index.tsx index 60cc2142..933b496e 100644 --- a/react-ui/src/pages/AutoML/Instance/index.tsx +++ b/react-ui/src/pages/AutoML/Instance/index.tsx @@ -28,7 +28,6 @@ function AutoMLInstance() { const [autoMLInfo, setAutoMLInfo] = useState(undefined); const [instanceInfo, setInstanceInfo] = useState(undefined); const params = useParams(); - // const autoMLId = safeInvoke(Number)(params.autoMLId); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(null); @@ -187,6 +186,7 @@ function AutoMLInstance() { icon: , children: ( diff --git a/react-ui/src/pages/AutoML/components/CopyingText/index.tsx b/react-ui/src/pages/AutoML/components/CopyingText/index.tsx deleted file mode 100644 index 586de40b..00000000 --- a/react-ui/src/pages/AutoML/components/CopyingText/index.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import KFIcon from '@/components/KFIcon'; -import { Typography } from 'antd'; -import styles from './index.less'; - -export type CopyingTextProps = { - text: string; -}; - -function CopyingText({ text }: CopyingTextProps) { - return ( -
- - {text} - - -
- ); -} - -export default CopyingText; diff --git a/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx index 09d0cd6e..0441a623 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx @@ -8,8 +8,9 @@ import TrialStatusCell from '../TrialStatusCell'; import styles from './index.less'; type ExperimentHistoryProps = { - fileUrl?: string; - isClassification: boolean; + calcMetrics?: string; // 计算指标 + fileUrl?: string; // 文件url + isClassification: boolean; // 是否是分类 }; type TableData = { @@ -22,7 +23,7 @@ type TableData = { althorithm?: string; }; -function ExperimentHistory({ fileUrl, isClassification }: ExperimentHistoryProps) { +function ExperimentHistory({ calcMetrics, fileUrl, isClassification }: ExperimentHistoryProps) { const [tableData, setTableData] = useState([]); useEffect(() => { // 获取实验运行历史记录 @@ -33,7 +34,7 @@ function ExperimentHistory({ fileUrl, isClassification }: ExperimentHistoryProps const list: TableData[] = data.map((item) => { return { id: item[0]?.[0], - accuracy: item[1]?.[5]?.accuracy, + accuracy: calcMetrics ? item[1]?.[5]?.[calcMetrics] : undefined, duration: item[1]?.[5]?.duration, train_loss: item[1]?.[5]?.train_loss, status: item[1]?.[2]?.['__enum__']?.split('.')?.[1], @@ -64,12 +65,6 @@ function ExperimentHistory({ fileUrl, isClassification }: ExperimentHistoryProps width: 80, render: tableCellRender(false), }, - { - title: '准确率', - dataIndex: 'accuracy', - key: 'accuracy', - render: tableCellRender(true), - }, { title: '耗时', dataIndex: 'duration', @@ -103,6 +98,15 @@ function ExperimentHistory({ fileUrl, isClassification }: ExperimentHistoryProps }, ]; + if (calcMetrics) { + columns.splice(0, 0, { + title: `指标:${calcMetrics}`, + dataIndex: 'accuracy', + key: 'accuracy', + render: tableCellRender(true), + }); + } + return (
diff --git a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx index aded5f2a..9b27862d 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx @@ -1,6 +1,6 @@ import KFIcon from '@/components/KFIcon'; import { ExperimentStatus } from '@/enums'; -import { useCheck } from '@/hooks'; +import { useCheck } from '@/hooks/useCheck'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import themes from '@/styles/theme.less'; import { type ExperimentInstance } from '@/types'; @@ -58,7 +58,8 @@ function ExperimentInstanceComponent({ // 删除实验实例确认 const handleRemove = (instance: ExperimentInstance) => { modalConfirm({ - title: '确定删除该条实例吗?', + title: '删除后,该实验实例将不可恢复', + content: '是否确认删除?', onOk: () => { deleteExperimentInstance(instance.id); }, @@ -96,6 +97,18 @@ function ExperimentInstanceComponent({ } }; + // 终止实验实例 + const handleTerminate = (instance: ExperimentInstance) => { + modalConfirm({ + title: '终止后,该次实验运行将不可恢复', + content: '是否确认终止?', + isDelete: false, + onOk: () => { + terminateExperimentInstance(instance); + }, + }); + }; + // 终止实验实例 const terminateExperimentInstance = async (instance: ExperimentInstance) => { const request = config.stopInsReq; @@ -107,7 +120,7 @@ function ExperimentInstanceComponent({ }; if (!experimentInsList || experimentInsList.length === 0) { - return
暂无实验实例
; + return
暂无数据
; } return ( @@ -188,7 +201,7 @@ function ExperimentInstanceComponent({ item.status === ExperimentStatus.Terminated } icon={} - onClick={() => terminateExperimentInstance(item)} + onClick={() => handleTerminate(item)} > 终止 diff --git a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx index b4e7f24b..d4628c24 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx @@ -7,7 +7,7 @@ import KFIcon from '@/components/KFIcon'; import PageTitle from '@/components/PageTitle'; import { ExperimentStatus } from '@/enums'; -import { useCacheState } from '@/hooks/pageCacheState'; +import { useCacheState } from '@/hooks/useCacheState'; import { AutoMLData } from '@/pages/AutoML/types'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import themes from '@/styles/theme.less'; @@ -93,17 +93,14 @@ function ExperimentList({ type }: ExperimentListProps) { const [res] = await to(request(record.id)); if (res) { message.success('删除成功'); - // 如果是一页的唯一数据,删除时,请求第一页的数据 + // 如果是一页的唯一数据,删除后,请求第一页的数据 // 否则直接刷新这一页的数据 - // 避免回到第一页 - if (tableData.length > 1) { - setPagination((prev) => ({ + setPagination((prev) => { + return { ...prev, - current: 1, - })); - } else { - getAutoMLList(); - } + current: tableData.length === 1 ? Math.max(1, prev.current! - 1) : prev.current, + }; + }); } }; @@ -188,6 +185,7 @@ function ExperimentList({ type }: ExperimentListProps) { if (expanded) { setExpandedRowKeys([record.id]); getExperimentInsList(record.id, 0); + refreshExperimentList(); } else { setExpandedRowKeys([]); } diff --git a/react-ui/src/pages/CodeConfig/List/index.tsx b/react-ui/src/pages/CodeConfig/List/index.tsx index 3f567465..a1ccd09c 100644 --- a/react-ui/src/pages/CodeConfig/List/index.tsx +++ b/react-ui/src/pages/CodeConfig/List/index.tsx @@ -75,8 +75,15 @@ function CodeConfigList() { const deleteRecord = async (id: number) => { const [res] = await to(deleteCodeConfigReq(id)); if (res) { - getDataList(); message.success('删除成功'); + // 如果是一页的唯一数据,删除后,请求第一页的数据 + // 否则直接刷新这一页的数据 + setPagination((prev) => { + return { + ...prev, + current: dataList!.length === 1 ? Math.max(1, prev.current! - 1) : prev.current, + }; + }); } }; diff --git a/react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.tsx b/react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.tsx index de903f47..fd9c967d 100644 --- a/react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.tsx +++ b/react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.tsx @@ -70,7 +70,12 @@ function CodeConfigItem({ item, onClick, onEdit, onRemove }: CodeConfigItemProps > {item.git_url} -
{item.git_branch}
+ + {item.git_branch} +
diff --git a/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx b/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx index db05393e..624ef833 100644 --- a/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx +++ b/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx @@ -4,7 +4,12 @@ import KFModal from '@/components/KFModal'; import { CategoryData, DataSource, ResourceType, resourceConfig } from '@/pages/Dataset/config'; import { addDataset } from '@/services/dataset/index.js'; import { to } from '@/utils/promise'; -import { getFileListFromEvent, limitUploadFileType, validateUploadFiles } from '@/utils/ui'; +import { + getFileListFromEvent, + limitUploadFileType, + removeUploadedFile, + validateUploadFiles, +} from '@/utils/ui'; import { Button, Form, @@ -29,11 +34,6 @@ interface AddDatasetModalProps extends Omit { function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalProps) { const [uuid] = useState(Date.now()); - // const [clusterOptions, setClusterOptions] = useState([]); - - // useEffect(() => { - // getClusterOptions(); - // }, []); // 上传组件参数 const uploadProps: UploadProps = { @@ -44,16 +44,9 @@ function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalPr defaultFileList: [], accept: '.zip,.tgz', beforeUpload: limitUploadFileType('zip,tgz'), + onRemove: removeUploadedFile, }; - // 获取集群版本数据 - // const getClusterOptions = async () => { - // const [res] = await to(getDictSelectOption('available_cluster')); - // if (res) { - // setClusterOptions(res); - // } - // }; - // 上传请求 const createDataset = async (params: any) => { const [res] = await to(addDataset(params)); @@ -113,7 +106,7 @@ function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalPr }, ]} > - + - {/* - + + + + { onOk: () => { getVersionList(true); close(); + window.postMessage({ type: VersionChangedMessage }); }, }); }; @@ -170,6 +172,7 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { if (res) { message.success('删除成功'); getVersionList(true); + window.postMessage({ type: VersionChangedMessage }); } }; diff --git a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx index 10d7d9d2..947ef228 100644 --- a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx @@ -21,7 +21,7 @@ const getDatasetDatas = (data: DatasetData): BasicInfoData[] => [ value: data.name, }, { - label: '版本', + label: '数据集版本', value: data.version, }, { @@ -64,7 +64,7 @@ const getModelDatas = (data: ModelData): BasicInfoData[] => [ ellipsis: true, }, { - label: '版本', + label: '模型版本', value: data.version, ellipsis: true, }, diff --git a/react-ui/src/pages/Dataset/components/ResourceList/index.tsx b/react-ui/src/pages/Dataset/components/ResourceList/index.tsx index 6549b9c1..2f1e8d4e 100644 --- a/react-ui/src/pages/Dataset/components/ResourceList/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceList/index.tsx @@ -107,8 +107,15 @@ function ResourceList( const request = config.deleteRecord; const [res] = await to(request(params)); if (res) { - getDataList(); message.success('删除成功'); + // 如果是一页的唯一数据,删除后,请求第一页的数据 + // 否则直接刷新这一页的数据 + setPagination((prev) => { + return { + ...prev, + current: dataList!.length === 1 ? Math.max(1, prev.current! - 1) : prev.current, + }; + }); } }; diff --git a/react-ui/src/pages/Dataset/components/ResourcePage/index.tsx b/react-ui/src/pages/Dataset/components/ResourcePage/index.tsx index f8a22729..fce95046 100644 --- a/react-ui/src/pages/Dataset/components/ResourcePage/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourcePage/index.tsx @@ -1,5 +1,5 @@ import { CommonTabKeys } from '@/enums'; -import { useCacheState } from '@/hooks/pageCacheState'; +import { useCacheState } from '@/hooks/useCacheState'; import { getAssetIcon } from '@/services/dataset/index.js'; import { to } from '@/utils/promise'; import { Flex, Tabs, type TabsProps } from 'antd'; diff --git a/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx b/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx index 3dbb3c40..18fbc3ee 100644 --- a/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx @@ -1,3 +1,9 @@ +/* + * @Author: 赵伟 + * @Date: 2025-03-24 15:41:42 + * @Description: 版本文件列表 + */ + import KFIcon from '@/components/KFIcon'; import { ResourceData, diff --git a/react-ui/src/pages/Dataset/components/VersionCompareModal/index.less b/react-ui/src/pages/Dataset/components/VersionCompareModal/index.less index f1935eb2..4a1c0d94 100644 --- a/react-ui/src/pages/Dataset/components/VersionCompareModal/index.less +++ b/react-ui/src/pages/Dataset/components/VersionCompareModal/index.less @@ -11,7 +11,6 @@ text-align: center; background: @background; border-radius: 4px 4px 0 0; - .singleLine(); } .text() { @@ -20,7 +19,6 @@ font-size: 13px; line-height: 22px; word-break: break-all; - .singleLine(); } .version-container(@background) { diff --git a/react-ui/src/pages/Dataset/components/VersionCompareModal/index.tsx b/react-ui/src/pages/Dataset/components/VersionCompareModal/index.tsx index 10660221..5e2292f8 100644 --- a/react-ui/src/pages/Dataset/components/VersionCompareModal/index.tsx +++ b/react-ui/src/pages/Dataset/components/VersionCompareModal/index.tsx @@ -88,7 +88,7 @@ function VersionCompareModal({ format: formatProject, }, { - key: 'description', + key: 'version_desc', text: '版本描述', }, ] @@ -123,7 +123,7 @@ function VersionCompareModal({ format: formatTrainTask, }, { - key: 'description', + key: 'version_desc', text: '版本描述', }, ], @@ -193,7 +193,14 @@ function VersionCompareModal({ ))}
-
{v1.version}
+
+ + {v1.version} + +
{fields.map(({ key, format }) => { const text = getValue(v1, key as keyof typeof v1, format); return ( @@ -203,7 +210,7 @@ function VersionCompareModal({ [styles['version-compare__left__text--different']]: isDifferent(key), })} > - + {isEmpty(text) ? '--' : text}
@@ -211,7 +218,14 @@ function VersionCompareModal({ })}
-
{v2.version}
+
+ + {v2.version} + +
{fields.map(({ key, format }) => { const text = getValue(v2, key as keyof typeof v2, format); return ( @@ -221,7 +235,7 @@ function VersionCompareModal({ [styles['version-compare__right__text--different']]: isDifferent(key), })} > - + {isEmpty(text) ? '--' : text}
diff --git a/react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx b/react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx index 6469c5af..e713b295 100644 --- a/react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx +++ b/react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx @@ -104,16 +104,16 @@ function EditorCreate() { - + @@ -137,7 +137,7 @@ function EditorCreate() { { @@ -66,6 +74,10 @@ function EditorList() { const [res] = await to(getEditorListReq(params)); if (res && res.data) { const { content = [], totalElements = 0 } = res.data; + content.forEach((item: EditorData) => { + item.dataset = typeof item.dataset === 'string' ? parseJsonText(item.dataset) : null; + item.model = typeof item.model === 'string' ? parseJsonText(item.model) : null; + }); setTableData(content); setTotal(totalElements); } @@ -80,17 +92,14 @@ function EditorList() { const [res] = await to(deleteEditorReq(id)); if (res) { message.success('删除成功'); - // 如果是一页的唯一数据,删除时,请求第一页的数据 + // 如果是一页的唯一数据,删除后,请求第一页的数据 // 否则直接刷新这一页的数据 - // 避免回到第一页 - if (tableData.length > 1) { - setPagination((prev) => ({ + setPagination((prev) => { + return { ...prev, - current: 1, - })); - } else { - getEditorList(); - } + current: tableData.length === 1 ? Math.max(1, prev.current! - 1) : prev.current, + }; + }); } }; @@ -105,11 +114,18 @@ function EditorList() { // 停止编辑器 const stopEditor = async (id: number) => { - const [res] = await to(stopEditorReq(id)); - if (res) { - message.success('操作成功'); - getEditorList(); - } + modalConfirm({ + title: '停止后,该编辑器将不可使用', + content: '是否确认停止?', + isDelete: false, + onOk: async () => { + const [res] = await to(stopEditorReq(id)); + if (res) { + message.success('操作成功'); + getEditorList(); + } + }, + }); }; // 制作镜像 @@ -168,44 +184,72 @@ function EditorList() { title: '编辑器名称', dataIndex: 'name', key: 'name', - width: '30%', - render: (text, record) => - record.url && record.status === DevEditorStatus.Running ? ( - gotoEditorPage(e, record)}> - {text} - - ) : ( - {text ?? '--'} - ), - }, - { - title: '状态', - dataIndex: 'status', - key: 'status', - width: '10%', - render: EditorStatusCell, + width: '20%', + render: (text, record, index) => + record.url && record.status === DevEditorStatus.Running + ? tableCellRender(true, TableCellValueType.Link, { + onClick: (record, e) => gotoEditorPage(e, record), + })(text, record, index) + : tableCellRender(true, TableCellValueType.Text)(text, record, index), }, { - title: '资源', + title: '计算资源', dataIndex: 'computing_resource', key: 'computing_resource', - width: '20%', + width: 100, render: tableCellRender(), }, + { + title: '资源规格', + dataIndex: 'computing_resource_id', + key: 'computing_resource_id', + width: '20%', + render: tableCellRender(true, TableCellValueType.Custom, { + format: getResourceDescription, + }), + }, + { + title: '数据集', + dataIndex: ['dataset', 'showValue'], + key: 'dataset', + width: '15%', + render: tableCellRender(true), + }, + { + title: '模型', + dataIndex: ['model', 'showValue'], + key: 'model', + width: '15%', + render: tableCellRender(true), + }, + { + title: '镜像', + dataIndex: ['image'], + key: 'image', + width: '15%', + render: tableCellRender(true), + }, { title: '创建者', dataIndex: 'update_by', key: 'update_by', - width: '20%', - render: tableCellRender(), + width: '15%', + render: tableCellRender(true), }, { title: '创建时间', dataIndex: 'create_time', key: 'create_time', - width: '20%', + width: 180, render: tableCellRender(false, TableCellValueType.Date), }, + { + title: '状态', + dataIndex: 'status', + key: 'status', + width: 80, + render: EditorStatusCell, + }, { title: '操作', dataIndex: 'operation', diff --git a/react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx b/react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx index 8d2b27fa..7155bc30 100644 --- a/react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx +++ b/react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx @@ -20,7 +20,7 @@ function CreateMirrorModal({ envId, onOk, ...rest }: CreateMirrorModalProps) { }), ); if (res) { - message.success('创建成功,请到 “AI资产” - “个人镜像” 中查看'); + message.success('创建成功,请到 “多形态资源库” - “个人镜像” 中查看'); onOk?.(); } }; @@ -51,20 +51,20 @@ function CreateMirrorModal({ envId, onOk, ...rest }: CreateMirrorModalProps) { message: '请输入镜像名称', }, { - pattern: /^[a-z0-9/_-]*$/, - message: '只支持小写字母、数字、下划线(_)、中横线(-)、斜杠(/)', + pattern: /^[a-z0-9/._-]*$/, + message: '只支持小写字母、数字、点(.)、下划线(_)、中横线(-)、斜杠(/)', }, ]} > - + diff --git a/react-ui/src/pages/Experiment/Aim/index.tsx b/react-ui/src/pages/Experiment/Aim/index.tsx new file mode 100644 index 00000000..3a8d1d0d --- /dev/null +++ b/react-ui/src/pages/Experiment/Aim/index.tsx @@ -0,0 +1,12 @@ +/* + * @Author: 赵伟 + * @Date: 2025-03-31 16:38:59 + * @Description: 实验对比 Aim + */ + +import IframePage, { IframePageType } from '@/components/IFramePage'; + +function AimPage() { + return ; +} +export default AimPage; diff --git a/react-ui/src/pages/Experiment/Comparison/index.tsx b/react-ui/src/pages/Experiment/Comparison/index.tsx index 4b2d6d5b..200b4ba1 100644 --- a/react-ui/src/pages/Experiment/Comparison/index.tsx +++ b/react-ui/src/pages/Experiment/Comparison/index.tsx @@ -12,8 +12,9 @@ import { } from '@/services/experiment'; import { tableSorter } from '@/utils'; import { to } from '@/utils/promise'; +import SessionStorage from '@/utils/sessionStorage'; import tableCellRender, { TableCellValueType } from '@/utils/table'; -import { useSearchParams } from '@umijs/max'; +import { useNavigate, useSearchParams } from '@umijs/max'; import { App, Button, Table, TablePaginationConfig, TableProps } from 'antd'; import classNames from 'classnames'; import { useEffect, useMemo, useState } from 'react'; @@ -46,6 +47,7 @@ function ExperimentComparison() { }); const { message } = App.useApp(); + const navigate = useNavigate(); const config = comparisonConfig[comparisonType]; useEffect(() => { @@ -73,7 +75,9 @@ function ExperimentComparison() { const [res] = await to(getExpMetricsReq(selectedRowKeys)); if (res && res.data) { const url = res.data; - window.open(url, '_blank'); + // window.open(url, '_blank'); + SessionStorage.setItem(SessionStorage.aimUrlKey, url); + navigate('../compare-visual'); } }; diff --git a/react-ui/src/pages/Experiment/Info/index.jsx b/react-ui/src/pages/Experiment/Info/index.jsx index f0cf9ae6..fd795873 100644 --- a/react-ui/src/pages/Experiment/Info/index.jsx +++ b/react-ui/src/pages/Experiment/Info/index.jsx @@ -1,5 +1,6 @@ import { ExperimentStatus } from '@/enums'; -import { useStateRef, useVisible } from '@/hooks'; +import { useStateRef } from '@/hooks/useStateRef'; +import { useVisible } from '@/hooks/useVisible'; import { getExperimentIns } from '@/services/experiment/index.js'; import { getWorkflowById } from '@/services/pipeline/index.js'; import themes from '@/styles/theme.less'; @@ -179,11 +180,12 @@ function ExperimentText() { if (!statusNode) { return; } - const { finishedAt, startedAt, phase, id } = statusNode; + const { finishedAt, startedAt, phase, id, message } = statusNode; workflowNode.experimentStartTime = startedAt; workflowNode.experimentEndTime = finishedAt; workflowNode.experimentStatus = phase; workflowNode.workflowId = id; + workflowNode.message = message; workflowNode.img = phase ? `${workflowNode.imgName}-${phase}.png` : `${workflowNode.imgName}.png`; diff --git a/react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx b/react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx index 38a88b3a..710a4df4 100644 --- a/react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx +++ b/react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx @@ -3,7 +3,7 @@ import editExperimentIcon from '@/assets/img/edit-experiment.png'; import KFModal from '@/components/KFModal'; import { type PipelineGlobalParam } from '@/types'; import { to } from '@/utils/promise'; -import { Button, Form, Input, Radio, Select, type FormRule } from 'antd'; +import { Button, Form, Input, Radio, Select, Typography, type FormRule } from 'antd'; import { useState } from 'react'; import styles from './index.less'; @@ -63,13 +63,14 @@ export const getParamRules = (paramType: number, required: boolean = false): For }; // 根据参数设置 label -export const getParamType = (param: PipelineGlobalParam): string => { +export const getParamLabel = (param: PipelineGlobalParam): React.ReactNode => { const paramTypes: Readonly> = { 1: '字符串', 2: '整型', 3: '布尔类型', }; - return param.param_name + `(${paramTypes[param.param_type]})`; + const label = param.param_name + `(${paramTypes[param.param_type]})`; + return {label}; }; function AddExperimentModal({ @@ -99,8 +100,8 @@ function AddExperimentModal({ }; const paramLayout = { - labelCol: { span: 8 }, - wrapperCol: { span: 16 }, + labelCol: { span: 6 }, + wrapperCol: { span: 18 }, }; // 除了流水线选择发生变化 @@ -157,7 +158,6 @@ function AddExperimentModal({ form={form} {...layout} labelAlign="left" - labelWrap > {getParamComponent( globalParam[name]['param_type'], diff --git a/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.less b/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.less index e524a987..41cb8a19 100644 --- a/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.less +++ b/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.less @@ -13,7 +13,6 @@ } &__tabs { - height: calc(100% - 169px); :global { .ant-tabs-nav { padding-left: 24px; @@ -35,7 +34,7 @@ display: flex; align-items: center; margin-bottom: 15px; - padding-left: 24px; + padding: 0 24px; color: @text-color; font-size: 15px; } diff --git a/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx b/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx index c1a70141..3ee726e5 100644 --- a/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx +++ b/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx @@ -3,7 +3,7 @@ import { experimentStatusInfo } from '@/pages/Experiment/status'; import { PipelineNodeModelSerialize } from '@/types'; import { elapsedTime, formatDate } from '@/utils/date'; import { CloseOutlined, DatabaseOutlined, ProfileOutlined } from '@ant-design/icons'; -import { Drawer, Tabs } from 'antd'; +import { Drawer, Tabs, Typography } from 'antd'; import { useMemo } from 'react'; import ExperimentParameter from '../ExperimentParameter'; import ExperimentResult from '../ExperimentResult'; @@ -129,6 +129,14 @@ const ExperimentDrawer = ({ '--' )}
+ {instanceNodeData.message && ( +
+
消息:
+ + {instanceNodeData.message ?? '--'} + +
+ )}
启动时间:{formatDate(instanceNodeStartTime)}
@@ -137,7 +145,14 @@ const ExperimentDrawer = ({ {elapsedTime(instanceNodeStartTime, instanceNodeEndTime)} - + ); }; diff --git a/react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx b/react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx index d184deee..362cf995 100644 --- a/react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx +++ b/react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx @@ -1,6 +1,6 @@ import KFIcon from '@/components/KFIcon'; import { ExperimentStatus } from '@/enums'; -import { useCheck } from '@/hooks'; +import { useCheck } from '@/hooks/useCheck'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import { deleteManyExperimentIns, @@ -62,7 +62,8 @@ function ExperimentInstanceComponent({ // 删除实验实例确认 const handleRemove = (instance: ExperimentInstance) => { modalConfirm({ - title: '确定删除该条实例吗?', + title: '删除后,该实验实例将不可恢复', + content: '是否确认删除?', onOk: () => { deleteExperimentInstance(instance.id); }, @@ -101,7 +102,8 @@ function ExperimentInstanceComponent({ // 终止实验实例 const handleTerminate = (instance: ExperimentInstance) => { modalConfirm({ - title: '确定要终止此次实验运行吗?', + title: '终止后,该次实验运行将不可恢复', + content: '是否确认终止?', isDelete: false, onOk: () => { terminateExperimentInstance(instance); diff --git a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx index 3bc1b566..f64f23c4 100644 --- a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx +++ b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx @@ -5,7 +5,7 @@ */ import { ExperimentStatus } from '@/enums'; -import { useStateRef } from '@/hooks'; +import { useStateRef } from '@/hooks/useStateRef'; import { getExperimentPodsLog } from '@/services/experiment/index.js'; import { DoubleRightOutlined, DownOutlined, UpOutlined } from '@ant-design/icons'; import { Button } from 'antd'; diff --git a/react-ui/src/pages/Experiment/components/ViewParamsModal/index.less b/react-ui/src/pages/Experiment/components/ViewParamsModal/index.less index a2b0ded5..06c5a4f0 100644 --- a/react-ui/src/pages/Experiment/components/ViewParamsModal/index.less +++ b/react-ui/src/pages/Experiment/components/ViewParamsModal/index.less @@ -1,31 +1,14 @@ -.params_container { - max-height: 230px; - padding: 15px 15px 0; +.params-container { + max-height: calc(100vh - 300px); + padding: 24px 24px 0; overflow-y: auto; border: 1px solid #e6e6e6; border-radius: 8px; - - &_line { - display: flex; - align-items: center; - margin-bottom: 15px; - - &_label { - width: 180px; - color: @text-color; - font-size: 15px; - } - &_value { - flex: 1; - width: 100px; - margin-left: 15px; - padding: 10px 20px; - color: @text-color; - font-size: @font-size; - line-height: 20px; - background: #f6f6f6; - border: 1px solid #e0e0e1; - border-radius: 4px; +} +.params-empty { + :global { + .kf-empty__image { + width: 300px; } } } diff --git a/react-ui/src/pages/Experiment/components/ViewParamsModal/index.tsx b/react-ui/src/pages/Experiment/components/ViewParamsModal/index.tsx index f860135a..8bd49817 100644 --- a/react-ui/src/pages/Experiment/components/ViewParamsModal/index.tsx +++ b/react-ui/src/pages/Experiment/components/ViewParamsModal/index.tsx @@ -4,9 +4,11 @@ * @Description: 查看实验使用的参数 */ import parameterImg from '@/assets/img/modal-parameter.png'; +import KFEmpty, { EmptyType } from '@/components/KFEmpty'; import KFModal from '@/components/KFModal'; import { type PipelineGlobalParam } from '@/types'; -import { getParamType } from '../AddExperimentModal'; +import { Form } from 'antd'; +import { getParamComponent, getParamLabel } from '../AddExperimentModal'; import styles from './index.less'; type ParamsModalProps = { @@ -26,14 +28,44 @@ function ParamsModal({ open, onCancel, globalParam = [] }: ParamsModalProps) { cancelButtonProps={{ style: { display: 'none' } }} width={825} > -
- {globalParam?.map((item) => ( -
- {getParamType(item)} - {item.param_value} -
- ))} -
+ {Array.isArray(globalParam) && globalParam.length > 0 ? ( +
+
+ + {(fields) => + fields.map(({ key, name, ...restField }) => ( + + {getParamComponent( + globalParam[name]['param_type'], + globalParam[name]['is_sensitive'], + )} + + )) + } + +
+
+ ) : ( + + )} ); } diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index 9b7cab84..b0006ce0 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -1,7 +1,7 @@ import KFIcon from '@/components/KFIcon'; import PageTitle from '@/components/PageTitle'; import { ExperimentStatus, TensorBoardStatus } from '@/enums'; -import { useCacheState } from '@/hooks/pageCacheState'; +import { useCacheState } from '@/hooks/useCacheState'; import { deleteExperimentById, getExperiment, @@ -206,6 +206,7 @@ function Experiment() { setExpandedRowKeys(null); } else { getQueryByExperiment(record.id, 0); + refreshExperimentList(); } }; @@ -285,8 +286,6 @@ function Experiment() { message.success('运行成功'); refreshExperimentList(); refreshExperimentIns(id); - } else { - message.error('运行失败'); } }; @@ -377,6 +376,31 @@ function Experiment() { getQueryByExperiment(expandedRowKeys, page); }; + // 处理删除 + const handleExperimentDelete = (record) => { + modalConfirm({ + title: '删除后,该实验将不可恢复', + content: '是否确认删除?', + onOk: () => { + deleteExperimentById(record.id).then((ret) => { + if (ret.code === 200) { + message.success('删除成功'); + // 如果是一页的唯一数据,删除后,请求第一页的数据 + // 否则直接刷新这一页的数据 + setPagination((prev) => { + return { + ...prev, + current: experimentList.length === 1 ? Math.max(1, prev.current - 1) : prev.current, + }; + }); + } else { + message.error(ret.msg); + } + }); + }, + }); + }; + const columns = [ { title: '实验名称', @@ -475,22 +499,7 @@ function Experiment() { size="small" key="batchRemove" icon={} - onClick={() => { - modalConfirm({ - title: '删除后,该实验将不可恢复', - content: '是否确认删除?', - onOk: () => { - deleteExperimentById(record.id).then((ret) => { - if (ret.code === 200) { - message.success('删除成功'); - getExperimentList(); - } else { - message.error(ret.msg); - } - }); - }, - }); - }} + onClick={() => handleExperimentDelete(record)} > 删除 @@ -499,6 +508,7 @@ function Experiment() { ), }, ]; + return (
diff --git a/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx index feb72d48..77cbff36 100644 --- a/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx +++ b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx @@ -1,6 +1,6 @@ import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; import { hyperParameterOptimizedMode } from '@/enums'; -import { useComputingResource } from '@/hooks/resource'; +import { useComputingResource } from '@/hooks/useComputingResource'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import { schedulerAlgorithms, diff --git a/react-ui/src/pages/Mirror/Create/index.tsx b/react-ui/src/pages/Mirror/Create/index.tsx index 7db2f4d0..a32e99a1 100644 --- a/react-ui/src/pages/Mirror/Create/index.tsx +++ b/react-ui/src/pages/Mirror/Create/index.tsx @@ -44,7 +44,7 @@ const mirrorRadioItems: KFRadioItem[] = [ function MirrorCreate() { const navigate = useNavigate(); const [form] = Form.useForm(); - const [nameDisabled, setNameDisabled] = useState(false); + const [isAddVersion, setIsAddVersion] = useState(false); // 是制作镜像还是新增镜像版本 const { message } = App.useApp(); const uploadProps: UploadProps = { @@ -60,7 +60,7 @@ function MirrorCreate() { const name = SessionStorage.getItem(SessionStorage.mirrorNameKey); if (name) { form.setFieldValue('name', name); - setNameDisabled(true); + setIsAddVersion(true); } return () => { SessionStorage.removeItem(SessionStorage.mirrorNameKey); @@ -70,32 +70,37 @@ function MirrorCreate() { // 创建公网、本地镜像 const createPublicMirror = async (formData: FormData) => { const upload_type = formData['upload_type']; - let params; + if (upload_type === CommonTabKeys.Public) { - params = { + const params = { ...omit(formData, ['upload_type']), upload_type: 0, image_type: 0, }; + const [res] = await to(createMirrorReq(params)); + if (res) { + message.success('创建成功'); + navigate(-1); + } } else { const fileList = formData['fileList'] ?? []; if (validateUploadFiles(fileList)) { const file = fileList[0]; - params = { + const params = { ...omit(formData, ['fileList', 'upload_type']), path: file.response.data.url, file_size: file.response.data.fileSize, + file_name: file.response.data.fileName, upload_type: 1, image_type: 0, }; + const [res] = await to(createMirrorReq(params)); + if (res) { + message.success('创建成功'); + navigate(-1); + } } } - - const [res] = await to(createMirrorReq(params)); - if (res) { - message.success('创建成功'); - navigate(-1); - } }; // 提交 @@ -118,14 +123,16 @@ function MirrorCreate() { return true; }; + const descTitle = isAddVersion ? '版本描述' : '镜像描述'; + return (
- +
@@ -174,33 +181,33 @@ function MirrorCreate() { rules={[ { required: true, - message: '请输入镜像Tag', + message: '请输入镜像版本', }, { pattern: /^[a-zA-Z0-9._-]+$/, - message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)', + message: '镜像版本只支持字母、数字、点(.)、下划线(_)、中横线(-)', }, ]} > - + @@ -303,7 +310,7 @@ function MirrorCreate() { )} @@ -238,28 +257,7 @@ const Pipeline = () => { size="small" key="batchRemove" icon={} - onClick={() => { - modalConfirm({ - title: '删除后,该流水线将不可恢复', - content: '是否确认删除?', - onOk: () => { - removeWorkflow(record.id).then((ret) => { - if (ret.code === 200) { - message.success('删除成功'); - getList(); - } else { - message.error(ret.msg); - } - }); - - // if (success) { - // if (actionRef.current) { - // actionRef.current.reload(); - // } - // } - }, - }); - }} + onClick={() => handlePipelineDelete(record)} > 删除 diff --git a/react-ui/src/pages/Points/components/Statistics/index.less b/react-ui/src/pages/Points/components/Statistics/index.less new file mode 100644 index 00000000..4ca97f96 --- /dev/null +++ b/react-ui/src/pages/Points/components/Statistics/index.less @@ -0,0 +1,31 @@ +.statistics { + display: flex; + align-items: center; + width: 100%; + padding: 20px 0; + background-color: @background-color; + border-radius: 8px; + + &__item { + display: flex; + flex: 1; + flex-direction: column; + align-items: center; + + &--border { + border-right: 1px solid @border-color; + } + + &__value { + margin-bottom: 8px; + color: @text-color; + font-weight: bold; + font-size: 30px; + } + + &__title { + color: #999999; + font-size: @font-size-input; + } + } +} diff --git a/react-ui/src/pages/Points/components/Statistics/index.tsx b/react-ui/src/pages/Points/components/Statistics/index.tsx new file mode 100644 index 00000000..e979b99d --- /dev/null +++ b/react-ui/src/pages/Points/components/Statistics/index.tsx @@ -0,0 +1,38 @@ +import classNames from 'classnames'; +import styles from './index.less'; + +type StatisticsProps = { + remaining?: number; + consuming?: number; +}; + +function Statistics({ remaining, consuming }: StatisticsProps) { + const items = [ + { + title: '当前可用算力积分(分)', + value: remaining ?? '-', + }, + { + title: '总消耗算力积分(分)', + value: consuming ?? '-', + }, + ]; + + return ( +
+ {items.map((item, index) => ( +
+ {item.value} + {item.title} +
+ ))} +
+ ); +} + +export default Statistics; diff --git a/react-ui/src/pages/Points/index.less b/react-ui/src/pages/Points/index.less new file mode 100644 index 00000000..e97785e2 --- /dev/null +++ b/react-ui/src/pages/Points/index.less @@ -0,0 +1,19 @@ +.points-detail { + height: 100%; + &__content { + height: calc(100% - 60px); + margin-top: 10px; + padding: 20px 30px 0; + background-color: white; + border-radius: 10px; + + &__top { + width: 100%; + } + + &__table { + height: calc(100% - 117px - 28px); + margin-top: 28px; + } + } +} diff --git a/react-ui/src/pages/Points/index.tsx b/react-ui/src/pages/Points/index.tsx new file mode 100644 index 00000000..a20570c7 --- /dev/null +++ b/react-ui/src/pages/Points/index.tsx @@ -0,0 +1,261 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-16 13:58:08 + * @Description: 模型部署服务列表 + */ +import PageTitle from '@/components/PageTitle'; +import { getPointsConsumptionReq, getPointsStatisticsReq } from '@/services/points'; +import themes from '@/styles/theme.less'; +import { to } from '@/utils/promise'; +import statusTableCell from '@/utils/statusTableCell'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; +import { Link } from '@umijs/max'; +import { Table, type TablePaginationConfig, type TableProps } from 'antd'; +import classNames from 'classnames'; +import { useEffect, useState } from 'react'; +import Statistics from './components/Statistics'; +import styles from './index.less'; + +enum TaskType { + DevEnvironment = 'dev_environment', + Workflow = 'workflow', + Ray = 'ray', + Service = 'service', +} + +const taskTypeOptions = [ + { + value: TaskType.DevEnvironment, + label: '开发环境', + }, + { + value: TaskType.Workflow, + label: '实验', + }, + { + value: TaskType.Ray, + label: '超参数自动寻优', + }, + { + value: TaskType.Service, + label: '服务', + }, +]; + +export type PointsData = { + computing_resource_id: number; + credit_per_hour: number; // 每小时消耗的积分 + deduce_credit: number; + deduce_last_time: string; + description: string; + id: number; + node_id: string; + start_time: string; + state: number; + workflow_id?: number; // 流水线id + task_id: number; // 实验id + task_ins_id: number; // 实例id + task_type: string; + user_id: number; +}; + +export type PointsStatistics = { + deduceCredit: number; + userCredit: number; +}; + +// 格式化任务 +const formatTask = (value: string, record: PointsData) => { + let url; + switch (record.task_type) { + case TaskType.DevEnvironment: + url = `/developmentEnvironment`; + break; + case TaskType.Workflow: + if (record.workflow_id && record.task_ins_id) { + url = `/pipeline/experiment/instance/${record.workflow_id}/${record.task_ins_id}`; + } + break; + case TaskType.Ray: + if (record.task_id && record.task_ins_id) { + url = `/pipeline/hyperparameter/instance/${record.task_id}/${record.task_ins_id}`; + } + break; + case TaskType.Service: + if (record.task_id && record.task_ins_id) { + url = `/dataset/modelDeployment/serviceInfo/${record.task_id}/versionInfo/${record.task_ins_id}`; + } + break; + default: + break; + } + + if (url) { + return {value}; + } else { + return {value}; + } +}; + +function PointsDetail() { + const [tableData, setTableData] = useState([]); + const [total, setTotal] = useState(0); + const [statistics, setStatistics] = useState(); + const [pagination, setPagination] = useState({ + current: 1, + pageSize: 10, + }); + + useEffect(() => { + // 获取积分统计 + const getPointsStatistics = async () => { + const [res] = await to(getPointsStatisticsReq()); + if (res && res.data) { + setStatistics(res.data); + } + }; + + getPointsStatistics(); + }, []); + + useEffect(() => { + // 获取积分消费明细 + const getPointsConsumption = async () => { + const params: Record = { + page: pagination.current! - 1, + size: pagination.pageSize, + }; + const [res] = await to(getPointsConsumptionReq(params)); + if (res && res.data) { + const { content = [], totalElements = 0 } = res.data; + setTableData(content); + setTotal(totalElements); + } + }; + + getPointsConsumption(); + }, [pagination]); + + // 分页切换 + const handleTableChange: TableProps['onChange'] = ( + pagination, + _filters, + _sorter, + { action }, + ) => { + if (action === 'paginate') { + setPagination(pagination); + } + }; + + const columns: TableProps['columns'] = [ + { + title: '序号', + dataIndex: 'index', + key: 'index', + width: 80, + render: tableCellRender(false, TableCellValueType.Index, { + page: pagination.current! - 1, + pageSize: pagination.pageSize!, + }), + }, + { + title: '任务', + dataIndex: 'task_name', + key: 'task_name', + width: '15%', + render: formatTask, + }, + { + title: '任务类型', + dataIndex: 'task_type', + key: 'task_type', + width: '10%', + render: statusTableCell(taskTypeOptions), + }, + { + title: '积分/小时', + dataIndex: 'credit_per_hour', + key: 'credit_per_hour', + width: '10%', + render: tableCellRender(), + }, + { + title: '消耗的积分(分)', + dataIndex: 'deduce_credit', + key: 'deduce_credit', + width: '12%', + render: tableCellRender(), + }, + { + title: '资源规格', + dataIndex: 'description', + key: 'description', + render: tableCellRender(true), + }, + { + title: '开始时间', + dataIndex: 'start_time', + key: 'start_time', + width: '15%', + render: tableCellRender(false, TableCellValueType.Date), + }, + { + title: '状态', + dataIndex: 'state', + key: 'state', + width: '8%', + render: statusTableCell([ + { + value: 0, + label: '已结束', + color: themes['textColor'], + }, + { + value: 1, + label: '进行中', + color: themes['primaryColor'], + }, + { + value: 2, + label: '准备中', + color: themes['pendingColor'], + }, + ]), + }, + ]; + + return ( +
+ +
+
+ +
+
+ `共${total}条`, + }} + onChange={handleTableChange} + rowKey="id" + /> + + + + ); +} + +export default PointsDetail; diff --git a/react-ui/src/pages/System/User/components/ResetPwd.tsx b/react-ui/src/pages/System/User/components/ResetPwd.tsx index 07bd8c03..33581242 100644 --- a/react-ui/src/pages/System/User/components/ResetPwd.tsx +++ b/react-ui/src/pages/System/User/components/ResetPwd.tsx @@ -17,6 +17,7 @@ const UpdateForm: React.FC = (props) => { const [form] = Form.useForm(); const loginPassword = Form.useWatch('password', form); const userId = props.values.userId; + const originPassword = props.values.originPassword; const intl = useIntl(); const handleOk = () => { @@ -26,7 +27,7 @@ const UpdateForm: React.FC = (props) => { props.onCancel(); }; const handleFinish = async (values: Record) => { - props.onSubmit({ ...values, userId } as FormValueType); + props.onSubmit({ password: values.password, userId, originPassword } as FormValueType); }; const checkPassword = (rule: any, value: string) => { diff --git a/react-ui/src/pages/System/User/edit.tsx b/react-ui/src/pages/System/User/edit.tsx index dd23b6e0..820de8eb 100644 --- a/react-ui/src/pages/System/User/edit.tsx +++ b/react-ui/src/pages/System/User/edit.tsx @@ -2,6 +2,7 @@ import { DictValueEnumObj } from '@/components/DictTag'; import KFModal from '@/components/KFModal'; import { ProForm, + ProFormDigit, ProFormRadio, ProFormSelect, ProFormText, @@ -62,8 +63,9 @@ const UserForm: React.FC = (props) => { loginIp: props.values.loginIp, loginDate: props.values.loginDate, remark: props.values.remark, - gitLinkUsername: props.values.gitLinkUsername, - gitLinkPassword: props.values.gitLinkPassword, + // gitLinkUsername: props.values.gitLinkUsername, + // gitLinkPassword: props.values.gitLinkPassword, + credit: props.values.credit, }); }, [form, props, statusOptions]); @@ -78,6 +80,7 @@ const UserForm: React.FC = (props) => { const params = { ...values, userId: props.values.userId, + originPassword: props.values.originPassword, }; props.onSubmit(params as UserFormData); }; @@ -148,7 +151,7 @@ const UserForm: React.FC = (props) => { colProps={{ md: 12, xl: 12 }} rules={[ { - required: false, + required: true, message: , }, { @@ -172,7 +175,7 @@ const UserForm: React.FC = (props) => { colProps={{ md: 12, xl: 12 }} rules={[ { - required: false, + required: true, message: , }, { @@ -192,7 +195,7 @@ const UserForm: React.FC = (props) => { id: 'system.user.user_name', defaultMessage: '用户账号', })} - hidden={userId} + disabled={!!props.values.userId} placeholder="请输入用户账号" colProps={{ md: 12, xl: 12 }} rules={[ @@ -200,9 +203,9 @@ const UserForm: React.FC = (props) => { required: true, }, { - pattern: /^[a-zA-Z0-9](?:[a-zA-Z0-9_.-]*[a-zA-Z0-9])?$/, + pattern: /^[a-zA-Z](?:[a-zA-Z0-9_.-]*[a-zA-Z0-9])?$/, message: - '只能包含数字,字母,下划线(_),中横线(-),英文句号(.),且必须以数字或字母开头与结尾', + '只能包含数字,字母,下划线(_),中横线(-),英文句号(.),且必须以字母开头,数字或字母结尾', }, ]} /> @@ -212,19 +215,23 @@ const UserForm: React.FC = (props) => { id: 'system.user.password', defaultMessage: '密码', })} - hidden={userId} placeholder="请输入密码" colProps={{ md: 12, xl: 12 }} fieldProps={{ autoComplete: 'new-password', }} allowClear - rules={[ - { - required: true, - message: , - }, - ]} + rules={ + props.values.userId + ? [] + : [ + { required: true, message: '请输入密码!' }, + { + pattern: /^[A-Za-z0-9!"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]{8,16}$/, + message: '密码长度为8 ~ 16位,只支持字母数字和符号', + }, + ] + } /> = (props) => { colProps={{ md: 12, xl: 12 }} rules={[{ required: true, message: '请选择角色!' }]} /> - = (props) => { autoComplete: 'new-password', }} rules={props.values.userId ? [] : [{ required: true, message: '请输入 Git 密码!' }]} + /> */} + { /** * 导出数据 - * - * */ -const handleExport = async () => { +const handleExport = async (deptId: string) => { const hide = message.loading('正在导出'); try { - await exportUser(); + await downloadXlsx('/api/system/user/export', 'POST', { data: { deptId: deptId } }); hide(); - message.success('导出成功'); return true; } catch (error) { hide(); @@ -259,6 +256,11 @@ const UserTableList: React.FC = () => { dataIndex: 'phonenumber', valueType: 'text', }, + { + title: , + dataIndex: 'credit', + valueType: 'text', + }, { title: , dataIndex: 'status', @@ -465,7 +467,7 @@ const UserTableList: React.FC = () => { key="export" hidden={!access.hasPerms('system:user:export')} onClick={async () => { - handleExport(); + handleExport(selectDept.id); }} > {' '} @@ -558,7 +560,7 @@ const UserTableList: React.FC = () => { /> { - const success = await resetUserPwd(values.userId, values.password); + const success = await resetUserPwd(values); if (success) { setResetPwdModalVisible(false); setSelectedRows([]); @@ -576,7 +578,7 @@ const UserTableList: React.FC = () => { /> { - const success = await updateAuthRole(values); + const success = await updateAuthRole(currentRow!.userId, values.roleIds); if (success) { setAuthRoleModalVisible(false); setSelectedRows([]); diff --git a/react-ui/src/pages/Workspace/components/ExperimentChart/index.less b/react-ui/src/pages/Workspace/components/ExperimentChart/index.less index a723c650..3af052da 100644 --- a/react-ui/src/pages/Workspace/components/ExperimentChart/index.less +++ b/react-ui/src/pages/Workspace/components/ExperimentChart/index.less @@ -1,4 +1,5 @@ .experiment-chart { + flex: none; width: 295px; min-width: 295px; height: 140px; diff --git a/react-ui/src/pages/Workspace/components/ExperimentTable/index.less b/react-ui/src/pages/Workspace/components/ExperimentTable/index.less index fc83b21d..4b692883 100644 --- a/react-ui/src/pages/Workspace/components/ExperimentTable/index.less +++ b/react-ui/src/pages/Workspace/components/ExperimentTable/index.less @@ -1,8 +1,8 @@ .experiment-table { flex: 1; - min-width: 500px; + min-width: 378px; height: 140px; - padding: 12px 24px; + padding: 12px; background: @workspace-background; border-radius: 4px; @@ -32,15 +32,15 @@ } &__status { - width: 20%; + width: 15%; } &__duration { - width: 30%; + width: 25%; } &__date { - width: calc(50% - 60px); + width: calc(60% - 60px); } &__operation { diff --git a/react-ui/src/pages/Workspace/components/TotalStatistics/index.less b/react-ui/src/pages/Workspace/components/TotalStatistics/index.less index d8943328..8a409b82 100644 --- a/react-ui/src/pages/Workspace/components/TotalStatistics/index.less +++ b/react-ui/src/pages/Workspace/components/TotalStatistics/index.less @@ -2,15 +2,17 @@ display: flex; align-items: center; justify-content: center; - width: 400px; height: 140px; - background: @workspace-background; - border-radius: 4px; + padding: 0 16px; + + // 媒体查询 + @media screen and (max-width: 1600px) { + flex: auto; + } &__icon { - width: 85px; - height: 80px; - margin-right: 40px; + width: 63px; + margin-right: 16px; } &__title { @@ -20,18 +22,9 @@ font-size: @font-size-content; } - &__title-shadow { - position: absolute; - bottom: 6px; - left: 0; - width: 79px; - height: 6px; - background: linear-gradient(87.07deg, rgba(22, 100, 255, 0.6) 0%, rgba(22, 100, 255, 0) 100%); - } - &__count { color: @text-color; - font-weight: 700; - font-size: 25px; + font-size: 26px; + font-family: DingTalk-JinBuTi; } } diff --git a/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx b/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx index c6834cfb..ef7f79de 100644 --- a/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx +++ b/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx @@ -1,3 +1,4 @@ +import { Flex } from 'antd'; import styles from './index.less'; type TotalStatisticsProps = { @@ -11,13 +12,12 @@ function TotalStatistics({ icon = '', title = '', count = 0, style }: TotalStati return (
-
+
{title} -
{count ?? '--'}
-
+
); } diff --git a/react-ui/src/pages/Workspace/components/UserPoints/index.less b/react-ui/src/pages/Workspace/components/UserPoints/index.less new file mode 100644 index 00000000..e8f9b750 --- /dev/null +++ b/react-ui/src/pages/Workspace/components/UserPoints/index.less @@ -0,0 +1,39 @@ +.user-points { + display: flex; + flex: none; + flex-direction: column; + align-items: center; + width: 326px; + height: 228px; + padding: 0 20px; + .backgroundFullImage(url(@/assets/img/user-points-bg.png)); + + &__label { + margin-top: 60px; + color: @text-color; + font-size: @font-size-title; + font-family: DingTalk-JinBuTi; + } + + &__value { + width: 100%; + margin-top: 8px; + margin-bottom: 12px; + color: @primary-color; + font-size: 36px; + font-family: DingTalk-JinBuTi; + line-height: 43px; + text-align: center; + .singleLine(); + } + + &__button { + padding: 8px 20px; + color: @primary-color; + font-size: @font-size-content; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #ffffff; + border-radius: 8px; + cursor: pointer; + } +} diff --git a/react-ui/src/pages/Workspace/components/UserPoints/index.tsx b/react-ui/src/pages/Workspace/components/UserPoints/index.tsx new file mode 100644 index 00000000..98e63cbf --- /dev/null +++ b/react-ui/src/pages/Workspace/components/UserPoints/index.tsx @@ -0,0 +1,46 @@ +import { PointsStatistics } from '@/pages/Points/index'; +import { getPointsStatisticsReq } from '@/services/points'; +import { to } from '@/utils/promise'; +import { useNavigate } from '@umijs/max'; +import { Typography } from 'antd'; +import { useEffect, useState } from 'react'; +import styles from './index.less'; + +function UserPoints() { + const [statistics, setStatistics] = useState(); + const navigate = useNavigate(); + + useEffect(() => { + // 获取积分统计 + const getPointsStatistics = async () => { + const [res] = await to(getPointsStatisticsReq()); + if (res && res.data) { + setStatistics(res.data); + } + }; + + getPointsStatistics(); + }, []); + + return ( +
+
当前可用算力积分
+ + {statistics?.userCredit ?? '--'} + +
{ + navigate('/points'); + }} + > + 查看详情 +
+
+ ); +} + +export default UserPoints; diff --git a/react-ui/src/pages/Workspace/index.less b/react-ui/src/pages/Workspace/index.less index 3fbcc8e8..addf2fcd 100644 --- a/react-ui/src/pages/Workspace/index.less +++ b/react-ui/src/pages/Workspace/index.less @@ -6,8 +6,8 @@ background: linear-gradient(#ecf2fe, #f9fafb); &__overview { + flex: 1; gap: 15px; - margin-bottom: 16px; padding: 20px 30px; background-color: white; border-radius: 4px; @@ -21,11 +21,24 @@ &__content { display: flex; + flex-wrap: wrap; gap: 15px; align-items: center; - @media screen and (max-width: 1800px) { - flex-wrap: wrap; + &__statistics { + flex: none; + min-width: 431px; + background: linear-gradient( + 123.08deg, + rgba(138, 138, 138, 0.06) 1.32%, + rgba(22, 100, 255, 0.02) 58.35% + ); + border-radius: 4px; + + // 媒体查询 + @media screen and (max-width: 1600px) { + flex: 1; + } } } } @@ -35,6 +48,7 @@ gap: 15px; align-items: flex-start; width: 100%; + margin-top: 16px; } &__user { diff --git a/react-ui/src/pages/Workspace/index.tsx b/react-ui/src/pages/Workspace/index.tsx index 691ca550..0546f22a 100644 --- a/react-ui/src/pages/Workspace/index.tsx +++ b/react-ui/src/pages/Workspace/index.tsx @@ -1,7 +1,8 @@ -import { useDraggable } from '@/hooks/draggable'; +import { useDraggable } from '@/hooks/useDraggable'; import { getWorkspaceOverviewReq } from '@/services/workspace'; import { ExperimentInstance } from '@/types'; import { to } from '@/utils/promise'; +import { Divider, Flex } from 'antd'; import { useEffect, useState } from 'react'; import Draggable from 'react-draggable'; import AssetsManagement from './components/AssetsManagement'; @@ -10,6 +11,7 @@ import ExperitableTable from './components/ExperimentTable'; import QuickStart from './components/QuickStart'; import RobotFrame from './components/RobotFrame'; import TotalStatistics from './components/TotalStatistics'; +import UserPoints from './components/UserPoints'; import UserSpace from './components/UserSpace'; import WorkspaceIntro from './components/WorkspaceIntro'; import styles from './index.less'; @@ -28,6 +30,7 @@ function Workspace() { setRobotFrameVisible((prev) => !prev), ); const users: number[] = new Array(8).fill(0); + useEffect(() => { getWorkspaceOverview(); }, []); @@ -43,27 +46,38 @@ function Workspace() { return (
-
-
运行概览
-
- - - - {overviewData?.experimentInsStatus && ( - - )} + +
+
运行概览
+
+ + + + + + + + {overviewData?.experimentInsStatus && ( + + )} +
-
+ +
diff --git a/react-ui/src/requestConfig.ts b/react-ui/src/requestConfig.ts index 06dd26b8..1b496981 100644 --- a/react-ui/src/requestConfig.ts +++ b/react-ui/src/requestConfig.ts @@ -53,7 +53,7 @@ export const requestConfig: RequestConfig = { ], responseInterceptors: [ [ - (response: AxiosResponse) => { + async (response: AxiosResponse) => { const { status, data, config } = response || {}; const options = config as RequestOptions; const skipErrorHandler = options?.skipErrorHandler; @@ -63,20 +63,45 @@ export const requestConfig: RequestConfig = { Loading.hide(); } if (status >= 200 && status < 300) { - if (status === 204) { + // 无内容或者无需验证 + if (status === 204 || skipValidating) { return response; - } else if (data && (skipValidating || data instanceof Blob || data.code === 200)) { + } + + if (data && data.code === 200) { + return response; + } + + // Blob 数据 + if (data && data instanceof Blob && data.size > 0) { + // 下载文件失败时,返回的是 JSON 数据,格式为:{code: 500, msg: "xxx"} + if (data.type === 'application/json') { + try { + const text = await data.text(); + const json = JSON.parse(text); + + if (json.code === 500) { + popupError(json.msg || '请求失败', skipErrorHandler); + return Promise.reject(json); + } + } catch (error) { + console.error('JSON 解析失败', error); + } + } return response; - } else if (data && data.code === 401) { + } + + // Token 失效 + if (data && data.code === 401) { clearSessionToken(); setRemoteMenu(null); gotoLoginPage(false); popupError('请重新登录'); return Promise.reject(response); - } else { - popupError(data?.msg ?? '请求失败', skipErrorHandler); - return Promise.reject(response); } + + popupError(data?.msg ?? '请求失败', skipErrorHandler); + return Promise.reject(response); } else { popupError('请求失败', skipErrorHandler); return Promise.reject(response); diff --git a/react-ui/src/services/dataset/index.js b/react-ui/src/services/dataset/index.js index 9ddeba2e..25cc8b16 100644 --- a/react-ui/src/services/dataset/index.js +++ b/react-ui/src/services/dataset/index.js @@ -181,4 +181,13 @@ export function compareModelVersion(data) { method: 'POST', data, }); -} \ No newline at end of file +} + + +// 删除上传的文件 +export function deleteUploadFileReq(params) { + return request(`/api/mmp/newdataset/deleteFile`, { + method: 'DELETE', + params, + }); +} diff --git a/react-ui/src/services/points/index.ts b/react-ui/src/services/points/index.ts new file mode 100644 index 00000000..6b5cc0d4 --- /dev/null +++ b/react-ui/src/services/points/index.ts @@ -0,0 +1,22 @@ +/* + * @Author: 赵伟 + * @Date: 2025-03-20 13:48:53 + * @Description: 积分 + */ + +import { request } from '@umijs/max'; + +// 分页查询积分消费明细 +export function getPointsConsumptionReq(params: any) { + return request(`/api/mmp/computingResource/resouceOccupy`, { + method: 'GET', + params, + }); +} + +// 分页查询积分消费明细 +export function getPointsStatisticsReq() { + return request(`/api/mmp/computingResource/credit`, { + method: 'GET', + }); +} diff --git a/react-ui/src/services/system/user.ts b/react-ui/src/services/system/user.ts index eb3cfeb8..fbd34f32 100644 --- a/react-ui/src/services/system/user.ts +++ b/react-ui/src/services/system/user.ts @@ -60,8 +60,9 @@ export async function removeUser(ids: string, options?: { [key: string]: any }) // 导出用户信息 export function exportUser(params?: API.System.UserListParams, options?: { [key: string]: any }) { return request(`/api/system/user/export`, { - method: 'GET', - params, + method: 'POST', + data: params, + skipValidating: true, ...(options || {}), }); } @@ -93,11 +94,7 @@ export function updateUserProfile(data: API.CurrentUser) { } // 用户密码重置 -export function resetUserPwd(userId: number, password: string) { - const data = { - userId, - password, - }; +export function resetUserPwd(data: any) { return request('/api/system/user/resetPwd', { method: 'put', data: data, @@ -126,16 +123,19 @@ export function uploadAvatar(data: any) { // 查询授权角色 export function getAuthRole(userId: number) { - return request('/system/user/authRole/' + userId, { + return request('/api/system/user/authRole/' + userId, { method: 'get', }); } // 保存授权角色 -export function updateAuthRole(data: Record) { - return request('/system/user/authRole', { - method: 'put', - params: data, +export function updateAuthRole(userId: number, data: Record) { + return request(`/api/system/user/authRole/${userId}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json;charset=UTF-8', + }, + data: data, }); } diff --git a/react-ui/src/stories/FullScreenFrame.stories.tsx b/react-ui/src/stories/FullScreenFrame.stories.tsx index 74dae50a..93ce8891 100644 --- a/react-ui/src/stories/FullScreenFrame.stories.tsx +++ b/react-ui/src/stories/FullScreenFrame.stories.tsx @@ -4,7 +4,7 @@ import { fn } from '@storybook/test'; // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta = { - title: 'Components/FullScreenFrame 全屏iframe', + title: 'Components/FullScreenFrame 全屏 iframe', component: FullScreenFrame, parameters: { // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout diff --git a/react-ui/src/stories/IFramePage.stories.tsx b/react-ui/src/stories/IFramePage.stories.tsx index d5c6725b..2b40330f 100644 --- a/react-ui/src/stories/IFramePage.stories.tsx +++ b/react-ui/src/stories/IFramePage.stories.tsx @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react'; // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta = { - title: 'Components/IFramePage iframe页面', + title: 'Components/IFramePage iframe 页面', component: IFramePage, parameters: { // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout diff --git a/react-ui/src/stories/ParameterInput.stories.tsx b/react-ui/src/stories/ParameterInput.stories.tsx index 3ca116c8..ba4407d0 100644 --- a/react-ui/src/stories/ParameterInput.stories.tsx +++ b/react-ui/src/stories/ParameterInput.stories.tsx @@ -76,6 +76,45 @@ export const Select: Story = { }, }; +export const Ellipse: Story = { + args: { + placeholder: '请输入工作目录', + style: { width: 300 }, + canInput: true, + size: 'large', + }, + render: function Render(args) { + const [value, setValue] = useState(''); + + const onClick = () => { + const value = { + value: 'storybook', + showValue: + 'storybookstorybookstorybookstorybookstorybookstorybookstorybookstorybookstorybookstorybook', + fromSelect: true, + otherValue: 'others', + }; + setValue(value); + action('onChange')(value); + }; + return ( + <> + { + setValue(value); + action('onChange')(value); + }} + > + + + ); + }, +}; + export const Disabled: Story = { args: { placeholder: '请输入工作目录', diff --git a/react-ui/src/stories/docs/Utils.mdx b/react-ui/src/stories/docs/Utils.mdx new file mode 100644 index 00000000..5ff56f10 --- /dev/null +++ b/react-ui/src/stories/docs/Utils.mdx @@ -0,0 +1,5 @@ +import { Meta } from '@storybook/blocks'; + + + +工具栏文档 \ No newline at end of file diff --git a/react-ui/src/styles/theme.less b/react-ui/src/styles/theme.less index d044889f..89b955c8 100644 --- a/react-ui/src/styles/theme.less +++ b/react-ui/src/styles/theme.less @@ -69,6 +69,14 @@ -webkit-line-clamp: @line; } +// 背景 +.backgroundFullImage(@url) { + background-image: @url; + background-repeat: no-repeat; + background-position: top center; + background-size: 100% 100%; +} + // 导出变量 :export { primaryColor: @primary-color; diff --git a/react-ui/src/types.ts b/react-ui/src/types.ts index f9d1734b..c3906e29 100644 --- a/react-ui/src/types.ts +++ b/react-ui/src/types.ts @@ -71,6 +71,7 @@ export type PipelineNodeModel = { component_label: string; icon_path: string; workflowId?: string; + message?: string; }; // 流水线节点模型数据 @@ -135,3 +136,17 @@ export type NodeStatus = { startedAt: string; finishedAt: string; }; + +// 应用响应 +export type AppResponse = { + code: number; + msg: string; + data: T; +}; + +// 上传文件的响应 +export type UploadFileRes = { + fileName: string; + fileSize: number; + url: string; +}; diff --git a/react-ui/src/types/system/user.d.ts b/react-ui/src/types/system/user.d.ts index a74ee0e8..c129130c 100644 --- a/react-ui/src/types/system/user.d.ts +++ b/react-ui/src/types/system/user.d.ts @@ -21,6 +21,8 @@ declare namespace API.System { remark: string; gitLinkUsername?: string; gitLinkPassword?: string; + credit?: number; + originPassword?: string; } export interface UserListParams { diff --git a/react-ui/src/utils/constant.ts b/react-ui/src/utils/constant.ts index 4fe1ea9b..4f3ec89c 100644 --- a/react-ui/src/utils/constant.ts +++ b/react-ui/src/utils/constant.ts @@ -1,3 +1,19 @@ -export const xlCols = { span: 12 }; -export const xllCols = { span: 10 }; -export const formCols = { xl: xlCols, xxl: xllCols }; +/* + * @Author: 赵伟 + * @Date: 2025-02-21 09:52:50 + * @Description: 通用表单项输入控件宽度 + */ + +const xlCols = { span: 12 }; +const xllCols = { span: 10 }; + +/** + * 输入控件宽度,xl: 12, xll: 10 + */ +export const FormCols = { xl: xlCols, xxl: xllCols }; + +// 数据集、模型新增和删除版本消息 +export const VersionChangedMessage = 'versionChanged'; + +// 创建服务成功消息,去创建服务版本 +export const ServiceCreatedMessage = 'serviceCreated'; diff --git a/react-ui/src/utils/date.ts b/react-ui/src/utils/date.ts index fbc83e35..02734886 100644 --- a/react-ui/src/utils/date.ts +++ b/react-ui/src/utils/date.ts @@ -1,7 +1,7 @@ import dayjs from 'dayjs'; /** - * Calculates the elapsed time between two dates and returns a formatted string representing the duration. + * 计算两个日期之间经过的时间,如 "3分12秒" * * @param {string | null | undefined} begin - The starting date. * @param {string | null | undefined} end - The ending date. @@ -29,19 +29,30 @@ export const elapsedTime = (begin?: string | null, end?: string | null): string const hours = duration.hours(); const minutes = duration.minutes(); const seconds = duration.seconds(); + const elspsedArray = []; if (years !== 0) { - return `${years}年${months}个月`; + elspsedArray.push(`${years}年`); } if (months !== 0) { - return `${months}个月${days}天`; + elspsedArray.push(`${months}个月`); } if (days !== 0) { - return `${days}天${hours}小时`; + elspsedArray.push(`${days}天`); } if (hours !== 0) { - return `${hours}小时${minutes}分`; + elspsedArray.push(`${hours}小时`); } - return `${minutes}分${seconds}秒`; + if (minutes !== 0) { + elspsedArray.push(`${minutes}分`); + } + if (seconds !== 0) { + elspsedArray.push(`${seconds}秒`); + } + + if (elspsedArray.length === 0) { + return '0秒'; + } + return elspsedArray.slice(0, 2).join(''); }; /** diff --git a/react-ui/src/utils/downloadfile.ts b/react-ui/src/utils/downloadfile.ts index ee56962e..7d4e46cd 100644 --- a/react-ui/src/utils/downloadfile.ts +++ b/react-ui/src/utils/downloadfile.ts @@ -1,19 +1,21 @@ import { request } from '@umijs/max'; -const mimeMap = { +/** MimeType */ +export const mimeMap = { xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', zip: 'application/zip', }; /** * 解析blob响应内容并下载 - * @param {*} res blob响应内容 - * @param {String} mimeType MIME类型 + * @param res - blob响应内容 + * @param mimeType - MIME类型 */ export function resolveBlob(res: any, mimeType: string) { const aLink = document.createElement('a'); const blob = new Blob([res.data], { type: mimeType }); - // //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名; + // 从response的headers中获取filename, + // 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名; const patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*'); // console.log(res); const contentDisposition = decodeURI(res.headers['content-disposition']); @@ -29,6 +31,11 @@ export function resolveBlob(res: any, mimeType: string) { document.body.removeChild(aLink); } +/** + * 下载 Zip 文件 + * @param url - url 地址 + * @param options - 请求参数 + */ export function downLoadZip(url: string, params?: any) { request(url, { method: 'GET', @@ -40,24 +47,30 @@ export function downLoadZip(url: string, params?: any) { }); } -export async function downLoadXlsx(url: string, params: any, fileName: string) { +/** + * 下载 XLSX 文件 + * @param url - url 地址 + * @param method - 请求方式 + * @param options - 请求选项 + */ +export async function downloadXlsx( + url: string, + method: string = 'GET', + options?: Record, +) { return request(url, { - ...params, - method: 'POST', + method: method, + ...options, responseType: 'blob', - }).then((data) => { - const aLink = document.createElement('a'); - const blob = data as any; // new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); - aLink.style.display = 'none'; - aLink.href = URL.createObjectURL(blob); - aLink.setAttribute('download', fileName); // 设置下载文件名称 - document.body.appendChild(aLink); - aLink.click(); - URL.revokeObjectURL(aLink.href); // 清除引用 - document.body.removeChild(aLink); + getResponse: true, + }).then((res) => { + resolveBlob(res, mimeMap.xlsx); }); } +/** + * @deprecated 无效 + */ export function download(fileName: string) { window.location.href = `/api/common/download?fileName=${encodeURI(fileName)}&delete=${true}`; } diff --git a/react-ui/src/utils/format.ts b/react-ui/src/utils/format.ts index 9c1d327d..32e7d7d4 100644 --- a/react-ui/src/utils/format.ts +++ b/react-ui/src/utils/format.ts @@ -1,3 +1,4 @@ +import { BasicInfoLink } from '@/components/BasicInfo/types'; import { ResourceSelectorResponse } from '@/components/ResourceSelectorModal'; import { ResourceInfoTabKeys } from '@/pages/Dataset/components/ResourceInfo'; import { @@ -18,8 +19,13 @@ type SelectedCodeConfig = { show_value?: string; // 后端使用的 }; -// 格式化数据集数组 -export const formatDatasets = (datasets?: DatasetData[]) => { +/** + * 格式化数据集数组 + * + * @param datasets - 数据集数组 + * @return 基本信息链接对象数组 + */ +export const formatDatasets = (datasets?: DatasetData[]): BasicInfoLink[] | undefined => { if (!datasets || datasets.length === 0) { return undefined; } @@ -29,8 +35,13 @@ export const formatDatasets = (datasets?: DatasetData[]) => { })); }; -// 格式化数据集 -export const formatDataset = (dataset?: DatasetData) => { +/** + * 格式化数据集 + * + * @param dataset - 数据集 + * @return 基本信息链接对象 + */ +export const formatDataset = (dataset?: DatasetData): BasicInfoLink | undefined => { if (!dataset) { return undefined; } @@ -40,8 +51,13 @@ export const formatDataset = (dataset?: DatasetData) => { }; }; -// 格式化模型 -export const formatModel = (model: ModelData) => { +/** + * 格式化模型 + * + * @param model - 模型 + * @return 基本信息链接对象 + */ +export const formatModel = (model: ModelData): BasicInfoLink | undefined => { if (!model) { return undefined; } @@ -51,16 +67,28 @@ export const formatModel = (model: ModelData) => { }; }; -// 格式化镜像 -export const formatMirror = (mirror: ResourceSelectorResponse) => { +/** + * 格式化镜像 + * + * @param mirror - 选择的镜像 + * @return 镜像地址 + */ +export const formatMirror = (mirror: ResourceSelectorResponse): string | undefined => { if (!mirror) { return undefined; } return mirror.path; }; -// 格式化代码配置 -export const formatCodeConfig = (project?: ProjectDependency | SelectedCodeConfig) => { +/** + * 格式化代码配置 + * + * @param project - 代码配置或者选择的代码配置 + * @return 基本信息链接对象 + */ +export const formatCodeConfig = ( + project?: ProjectDependency | SelectedCodeConfig, +): BasicInfoLink | undefined => { if (!project) { return undefined; } @@ -81,7 +109,12 @@ export const formatCodeConfig = (project?: ProjectDependency | SelectedCodeConfi } }; -// 格式化训练任务(实验实例) +/** + * 格式化训练任务(实验实例) + * + * @param task - 训练任务 + * @return 基本信息链接对象 + */ export const formatTrainTask = (task?: TrainTask) => { if (!task) { return undefined; @@ -92,8 +125,13 @@ export const formatTrainTask = (task?: TrainTask) => { }; }; -// 格式化数据来源 -export const formatSource = (source?: string) => { +/** + * 格式化数据来源 + * + * @param source - 数据来源枚举值 + * @return 数据来源中文名称 + */ +export const formatSource = (source?: string): string | undefined => { if (source === DataSource.Create) { return '用户上传'; } else if (source === DataSource.HandExport) { @@ -106,7 +144,12 @@ export const formatSource = (source?: string) => { return source; }; -// 格式化字符串数组,以逗号分隔 +/** + * 格式化字符串数组,以逗号分隔 + * + * @param value - 字符串数组 + * @return 字符串,以逗号分隔 + */ export const formatList = (value: string[] | null | undefined): string => { if ( value === undefined || @@ -119,14 +162,24 @@ export const formatList = (value: string[] | null | undefined): string => { return value.join(','); }; -// 格式化布尔值 +/** + * 格式化布尔值 + * + * @param value - 布尔值 + * @return true 为 "是",false 为 "否" + */ export const formatBoolean = (value: boolean): string => { return value ? '是' : '否'; }; type FormatEnumFunc = (value: string | number) => React.ReactNode; -// 格式化枚举 +/** + * 格式化枚举 + * + * @param options - 枚举选项数组 + * @return 一个函数,参数是枚举值,从选项数组中找到对应的项,然后返回该项的 label + */ export const formatEnum = ( options: { value?: string | number | null; label?: React.ReactNode }[], ): FormatEnumFunc => { diff --git a/react-ui/src/utils/functional.ts b/react-ui/src/utils/functional.ts index 6128c897..0c806998 100644 --- a/react-ui/src/utils/functional.ts +++ b/react-ui/src/utils/functional.ts @@ -5,14 +5,10 @@ */ /** - * Safely invokes a function with a given value, returning the result of the - * function or the provided value if it is `undefined` or `null`. + * 安全调用函数,如果参数是 `undefined` 或 `null`,直接返回 `undefined` 或 `null`,而不会导致异常 * - * @template T - The type of the input value. - * @template M - The type of the output value. - * @param {function} fn - The function to be invoked with the input value. - * @returns {function} A function that takes a value, invokes `fn` with it if - * it's not `undefined` or `null`, and returns the result or the original value. + * @param fn - 要调用的函数 + * @returns 封装后的函数,该函数的参数如果是 `undefined` 或 `null`,结果直接返回 `undefined` 或 `null`,而不会导致异常 */ export function safeInvoke( fn: (value: T) => M | undefined | null, diff --git a/react-ui/src/utils/index.ts b/react-ui/src/utils/index.ts index 4df48c1c..3113c8ea 100644 --- a/react-ui/src/utils/index.ts +++ b/react-ui/src/utils/index.ts @@ -7,7 +7,10 @@ import { PageEnum } from '@/enums/pagesEnums'; import G6 from '@antv/g6'; -// 生成 8 位随机数 +/** + * 生成 8 位随机数 + * @returns 8 位随机数 + */ export function s8() { return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1); } @@ -20,7 +23,12 @@ export function getNameByCode(list: any[], code: any) { return name; } -// 解析 json 字符串 +/** + * 完全解析 json 字符串,不会抛异常 + * + * @param text - the string to be parsed + * @returns the parsed JSON object if the string is a valid JSON text, null otherwise + */ export function parseJsonText(text?: string | null): any | null { if (text === undefined || text === null || text === '') { return null; @@ -32,8 +40,17 @@ export function parseJsonText(text?: string | null): any | null { } } -// 判断是否为一般对象 -function isPlainObject(value: any) { +/** + * Checks if a given value is a plain object. + * + * A plain object is an object that is created using the Object constructor. + * It does not have any special properties or methods that are not part of the + * standard Object prototype. + * + * @param {any} value - The value to be checked. + * @returns {boolean} true if the value is a plain object, false otherwise. + */ +function isPlainObject(value: any): boolean { if (value === null || typeof value !== 'object') return false; let proto = Object.getPrototypeOf(value); while (proto !== null) { @@ -43,7 +60,14 @@ function isPlainObject(value: any) { return true; } -// underscore to camelCase +/** + * Converts all property names in an object from underscore notation to camelCase. + * + * If the object is not a plain object, it is returned as is. + * + * @param obj - The object whose property names need to be converted. + * @returns The object with all property names converted to camelCase. + */ export function underscoreToCamelCase(obj: Record) { if (!isPlainObject(obj)) { return obj; @@ -66,7 +90,14 @@ export function underscoreToCamelCase(obj: Record) { return newObj; } -// camelCase to underscore +/** + * Converts all property names in an object from camelCase to underscore notation. + * + * If the object is not a plain object, it is returned as is. + * + * @param obj - The object whose property names need to be converted. + * @returns The object with all property names converted to underscore notation. + */ export function camelCaseToUnderscore(obj: Record) { if (!isPlainObject(obj)) { return obj; @@ -87,7 +118,14 @@ export function camelCaseToUnderscore(obj: Record) { return newObj; } -// null to undefined +/** + * Recursively converts all null values in an object to undefined. + * + * If the given value is not an object, it is returned as is. + * + * @param obj - The object whose null values need to be converted. + * @returns The object with all null values converted to undefined. + */ export function nullToUndefined(obj: Record | null) { if (obj === null) { return undefined; @@ -113,7 +151,15 @@ export function nullToUndefined(obj: Record | null) { return newObj; } -// undefined to null +/** + * Recursively converts all undefined values in an object to null. + * + * If the given value is not an object, it is returned as is. + * + * @param obj - The object whose undefined values need to be converted. + * @returns The object with all undefined values converted to null. + */ + export function undefinedToNull(obj?: Record) { if (obj === undefined) { return null; @@ -204,10 +250,20 @@ export const fittingString = (str: string, maxWidth: number, fontSize: number): * @param {any} str - the string to be checked * @return {boolean} true if the string is empty, undefined, or null, false otherwise */ -export const isEmpty = (str: any): boolean => { +export const isEmpty = (str?: any | null): boolean => { return str === '' || str === undefined || str === null; }; +/** + * Checks if a given value is undefined or null. + * + * @param {any} value - the value to be checked + * @return {boolean} true if the value is undefined or null, false otherwise + */ +export const hasNoValue = (value?: any | null): boolean => { + return value === undefined || value === null; +}; + /** * 获取 git 仓库的 url * @@ -226,12 +282,30 @@ export const getGitUrl = (url: string, branch: string): string => { return branch ? `${gitUrl}/tree/${branch}` : gitUrl; }; -// 判断是否需要登录 -export const needAuth = (pathname: string) => { +/** + * 判断是否需要登录 + * + * @param {string} pathname - the pathname to be checked + * @return {boolean} true if the pathname needs to be authorized, false otherwise + */ +export const needAuth = (pathname: string): boolean => { return pathname !== PageEnum.LOGIN && pathname !== PageEnum.Authorize; }; -// 表格排序 +/** + * 表格排序 + * + * @param {any} a - the first value to be compared + * @param {any} b - the second value to be compared + * @returns {number} -1 if a is less than b, 1 if a is greater than b, 0 if a is equal to b + * + * The sorter function compares two values and returns a number indicating their relative order. + * The function first checks if either value is null or undefined. If so, it returns -1 if b is null or undefined, + * and 1 if a is null or undefined. + * If both values are numbers, it returns the difference between the two numbers. + * If both values are strings, it returns the result of the localeCompare() method. + * Otherwise, it returns 0. + */ export const tableSorter = (a: any, b: any) => { if (b === null || b === undefined) { return -1; diff --git a/react-ui/src/utils/loading.tsx b/react-ui/src/utils/loading.tsx index 8486a6b9..0180a243 100644 --- a/react-ui/src/utils/loading.tsx +++ b/react-ui/src/utils/loading.tsx @@ -28,7 +28,7 @@ export class Loading { } const container = document.createElement('div'); container.id = 'loading'; - const rootContainer = document.body; //document.getElementsByTagName('main')[0]; + const rootContainer = document.body; // document.getElementsByTagName('main')[0]; rootContainer?.appendChild(container); const root = createRoot(container); const global = globalConfig(); @@ -69,10 +69,9 @@ export class Loading { static removeLoading() { this.clearRemoveTimeout(); - const rootContainer = document.body; //document.getElementsByTagName('main')[0]; const container = document.getElementById('loading'); if (container) { - rootContainer?.removeChild(container); + container.parentNode?.removeChild(container); } this.isShowing = false; } diff --git a/react-ui/src/utils/localStorage.ts b/react-ui/src/utils/localStorage.ts index 4d224465..bb583ba7 100644 --- a/react-ui/src/utils/localStorage.ts +++ b/react-ui/src/utils/localStorage.ts @@ -6,6 +6,11 @@ export default class LocalStorage { // 记住密码 static readonly rememberPasswordKey = 'login-remember-password'; + /** + * 获取 LocalStorage 值 + * @param key - LocalStorage key + * @param isObject - 是不是对象 + */ static getItem(key: string, isObject: boolean = false) { const jsonStr = localStorage.getItem(key); if (!isObject) { @@ -17,12 +22,22 @@ export default class LocalStorage { return null; } + /** + * 设置 LocalStorage 值 + * @param key - LocalStorage key + * @param state - SessionStorage state + * @param isObject - 是不是对象 + */ static setItem(key: string, state?: any, isObject: boolean = false) { if (state) { localStorage.setItem(key, isObject ? JSON.stringify(state) : state); } } + /** + * 移除 LocalStorage 值 + * @param key - LocalStorage key + */ static removeItem(key: string) { localStorage.removeItem(key); } diff --git a/react-ui/src/utils/promise.ts b/react-ui/src/utils/promise.ts index 1919ecd1..7340e3bf 100644 --- a/react-ui/src/utils/promise.ts +++ b/react-ui/src/utils/promise.ts @@ -1,6 +1,7 @@ /** - * @param { Promise } promise - * @return { Promise } + * 封装 Promise,不会抛异常,resolve 的时候返回 [data, null], reject 的时候返回 [null, error] + * @param promise + * @return resolve 的时候返回 [data, null], reject 的时候返回 [null, error] */ export async function to(promise: Promise): Promise<[T, null] | [null, U]> { try { diff --git a/react-ui/src/utils/sessionStorage.ts b/react-ui/src/utils/sessionStorage.ts index 4a41e214..a230197c 100644 --- a/react-ui/src/utils/sessionStorage.ts +++ b/react-ui/src/utils/sessionStorage.ts @@ -1,15 +1,22 @@ import { parseJsonText } from './index'; export default class SessionStorage { - // 用于新建镜像 + /** 用于新建镜像 */ static readonly mirrorNameKey = 'mirror-name'; - // 模型部署服务版本 + /** 模型部署服务版本 */ static readonly serviceVersionInfoKey = 'service-version-info'; - // 编辑器 url + /** 编辑器 url */ static readonly editorUrlKey = 'editor-url'; - // 客户端信息 + /** 客户端信息 */ static readonly clientInfoKey = 'client-info'; + /** aim url */ + static readonly aimUrlKey = 'aim-url'; + /** + * 获取 SessionStorage 值 + * @param key - SessionStorage key + * @param isObject - 是不是对象 + */ static getItem(key: string, isObject: boolean = false) { const jsonStr = sessionStorage.getItem(key); if (!isObject) { @@ -21,12 +28,22 @@ export default class SessionStorage { return null; } + /** + * 设置 SessionStorage 值 + * @param key - SessionStorage key + * @param state - SessionStorage state + * @param isObject - 是不是对象 + */ static setItem(key: string, state?: any, isObject: boolean = false) { if (state) { sessionStorage.setItem(key, isObject ? JSON.stringify(state) : state); } } + /** + * 移除 SessionStorage 值 + * @param key - SessionStorage key + */ static removeItem(key: string) { sessionStorage.removeItem(key); } diff --git a/react-ui/src/utils/statusTableCell.tsx b/react-ui/src/utils/statusTableCell.tsx new file mode 100644 index 00000000..265aa9c4 --- /dev/null +++ b/react-ui/src/utils/statusTableCell.tsx @@ -0,0 +1,27 @@ +/* + * @Author: 赵伟 + * @Date: 2025-03-20 14:33:01 + * @Description: 通用的 Table 状态单元格 + */ + +export type StatusInfo = { + value: number | string; + label: string; + color?: string; +}; + +/** + * 通用的 Table 状态单元格 + * @param infos - 选项数组 + */ +function statusTableCell(infos: StatusInfo[]) { + return function (status?: string | number | null) { + const info = infos.find((item) => item.value === status); + if (status === null || status === undefined || !info) { + return --; + } + return {info.label}; + }; +} + +export default statusTableCell; diff --git a/react-ui/src/utils/table.tsx b/react-ui/src/utils/table.tsx index 1a1e84c4..ac66967f 100644 --- a/react-ui/src/utils/table.tsx +++ b/react-ui/src/utils/table.tsx @@ -1,7 +1,7 @@ /* * @Author: 赵伟 * @Date: 2024-06-26 10:05:52 - * @Description: Table cell 自定义 render + * @Description: Table Cell 自定义 render */ import { isEmpty } from '@/utils'; @@ -10,26 +10,44 @@ import { Tooltip, TooltipProps, Typography } from 'antd'; import dayjs from 'dayjs'; export enum TableCellValueType { + /** 序号 */ Index = 'Index', + /** 文本 */ Text = 'Text', + /** 日期 */ Date = 'Date', + /** 数组 */ Array = 'Array', + /** 链接 */ Link = 'Link', + /** 自定义 */ Custom = 'Custom', } export type TableCellValueOptions = { - page?: number; // 类型为 Index 时有效 - pageSize?: number; // 类型为 Index 时有效 - property?: string; // 类型为 Array 时有效 - dateFormat?: string; // 类型为 Date 时有效 - onClick?: (record: T, e: React.MouseEvent) => void; // 类型为 Link 时有效 - format?: (value: any | undefined | null, record: T, index: number) => string | undefined | null; // 类型为 Custom 时有效 + /** 页数,类型为 Index 时有效 */ + page?: number; + /** 分页大小,类型为 Index 时有效 */ + pageSize?: number; + /** 取数组对象的哪个属性值,类型为 Array 时有效 */ + property?: string; + /** 日期格式,类型为 Date 时有效*/ + dateFormat?: string; + /** 链接点击回调,类型为 Link 时有效 */ + onClick?: (record: T, e: React.MouseEvent) => void; + /** 自定义函数,类型为 Custom 时有效*/ + format?: (value: any | undefined | null, record: T, index: number) => string | undefined | null; + /** 省略时是否可以复制 */ + copyable?: boolean; }; type TableCellFormatter = (value: any | undefined | null) => string | undefined | null; -// 日期转换函数 +/** + * 日期转换函数 + * @param {string | undefined} dateFormat - 日期格式 + * @returns {TableCellFormatter} Table cell 渲染函数 + */ function formatDateText(dateFormat?: string): TableCellFormatter { return (value: any | undefined | null): ReturnType => { if (value === undefined || value === null || value === '') { @@ -44,7 +62,7 @@ function formatDateText(dateFormat?: string): TableCellFormatter { /** * 数组转换函数,将数组元素转换为字符串,用逗号分隔 - * @param {string} property 如果数组元素是对象,那么取数组元素的某个属性 + * @param {string} property - 如果数组元素是对象,那么取数组元素的某个属性 * @returns {TableCellFormatter} Table cell 渲染函数 */ function formatArray(property?: string): TableCellFormatter { @@ -64,6 +82,13 @@ function formatArray(property?: string): TableCellFormatter { }; } +/** + * Table cell render 函数 + * @param ellipsis - 是否省略 + * @param type - 类型 + * @param options - 选项 + * @returns React 节点 + */ function tableCellRender( ellipsis: boolean | TooltipProps | 'auto' = false, type: TableCellValueType = TableCellValueType.Text, @@ -93,17 +118,17 @@ function tableCellRender( } if (ellipsis === 'auto' && text) { - return renderCell(type, text, 'auto', record, options?.onClick); + return renderCell(type, text, 'auto', record, options); } else if (ellipsis && text) { const tooltipProps = typeof ellipsis === 'object' ? ellipsis : {}; const { overlayStyle, ...rest } = tooltipProps; return ( - {renderCell(type, text, true, record, options?.onClick)} + {renderCell(type, text, true, record, options)} ); } else { - return renderCell(type, text, false, record, options?.onClick); + return renderCell(type, text, false, record, options); } }; } @@ -113,31 +138,38 @@ function renderCell( text: any | undefined | null, ellipsis: boolean | 'auto', record: T, - onClick?: (record: T, e: React.MouseEvent) => void, + options?: TableCellValueOptions, ) { return type === TableCellValueType.Link - ? renderLink(text, ellipsis, record, onClick) - : renderText(text, ellipsis); + ? renderLink(text, ellipsis, record, options) + : renderText(text, ellipsis, options); } function renderLink( text: any | undefined | null, ellipsis: boolean | 'auto', record: T, - onClick?: (record: T, e: React.MouseEvent) => void, + options?: TableCellValueOptions, ) { + const { onClick } = options ?? {}; return ( onClick?.(record, e)}> - {renderText(text, ellipsis)} + {renderText(text, ellipsis, options)} ); } -function renderText(text: any | undefined | null, ellipsis: boolean | 'auto') { +function renderText( + text: any | undefined | null, + ellipsis: boolean | 'auto', + options?: TableCellValueOptions, +) { + const { copyable } = options ?? {}; if (ellipsis === 'auto') { return ( { const { pathname, search } = location; @@ -80,6 +84,9 @@ export const gotoLoginPage = (toHome: boolean = true) => { } }; +/** + * 跳转到 OAuth2 登录页 + */ export const gotoOAuth2 = () => { const clientInfo = SessionStorage.getItem(SessionStorage.clientInfoKey, true) as ClientInfo; if (clientInfo) { @@ -89,7 +96,10 @@ export const gotoOAuth2 = () => { } }; -// 从事件中获取上传文件列表,用于 Upload + Form 中 +/** + * 从事件中获取上传文件列表,用于 Upload + Form 中 + * @param e - 事件,包含文件列表 fileList + */ export const getFileListFromEvent = (e: any) => { const fileList: UploadFile[] = (Array.isArray(e) ? e : e?.fileList) || []; return fileList.map((item) => { @@ -137,7 +147,10 @@ export const validateUploadFiles = (files: UploadFile[], required: boolean = tru return !hasError; }; -// 限制上传文件类型 +/** + * 限制上传文件类型 + * @param type - 只允许上次的的文件类型 + */ export const limitUploadFileType = (type: string) => { return (file: UploadFile): boolean | string => { const acceptTypes = type.split(',').map((item) => item.trim()); @@ -151,14 +164,40 @@ export const limitUploadFileType = (type: string) => { }; }; +/** + * 删除已上传的文件 + * @param file - 已上传的文件 + */ +export const removeUploadedFile = async (file: UploadFile>) => { + const { status, response } = file; + const { code, data } = response ?? {}; + if (status === 'done' && code === 200 && Array.isArray(data) && data.length > 0) { + const uploadRes = data[0]; + const { fileName, url } = uploadRes; + const [res] = await to( + deleteUploadFileReq({ + fileName, + url, + }), + ); + if (res) { + return true; + } else { + return false; + } + } + + return true; +}; + /** * 删除 FormList 表单项,如果表单项没有值,则直接删除,否则弹出确认框 - * @param form From实例 - * @param listName FormList 的 name - * @param name FormList 的其中一项 - * @param remove FormList 的删除方法 - * @param fieldNames FormList 的子项名称数组 - * @param confirmTitle 弹出确认框的标题 + * @param form - From实例 + * @param listName - FormList 的 name + * @param name - FormList 的其中一项 + * @param remove - FormList 的删除方法 + * @param fieldNames - FormList 的子项名称数组 + * @param confirmTitle - 弹出确认框的标题 */ export const removeFormListItem = ( form: FormInstance, @@ -187,3 +226,14 @@ export const removeFormListItem = ( }, }); }; + +/** + * 退出子系统 + * @param url - 退出登录的地址 + */ +export const oauthLogout = (url: string) => { + const iframe = document.createElement('iframe'); + iframe.style.display = 'none'; + iframe.src = url; + document.body.appendChild(iframe); +}; diff --git a/react-ui/typedoc.json b/react-ui/typedoc.json new file mode 100644 index 00000000..f9868f57 --- /dev/null +++ b/react-ui/typedoc.json @@ -0,0 +1,20 @@ +{ + "entryPoints": ["./src/utils", "./src/hooks"], + "entryPointStrategy": "expand", + "out": "docs", + "excludePrivate": true, + "excludeProtected": false, + "excludeExternals": true, + "includeVersion": true, + "categorizeByGroup": true, + "skipErrorChecking": true, + "exclude": [ + "src/utils/formRules.ts", + "src/utils/loading.tsx", + "src/utils/menuRender.tsx", + "src/utils/IconUtil.ts", + "src/utils/permission.ts", + "src/utils/tree.ts" + ], + "name": "工具类文档" +} diff --git a/ruoyi-api/ruoyi-api-system/pom.xml b/ruoyi-api/ruoyi-api-system/pom.xml index fe8f2ee0..623290a8 100644 --- a/ruoyi-api/ruoyi-api-system/pom.xml +++ b/ruoyi-api/ruoyi-api-system/pom.xml @@ -22,7 +22,13 @@ com.ruoyi ruoyi-common-core - + + com.alibaba + easyexcel-core + 3.3.2 + compile + + \ No newline at end of file diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteAuthService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteAuthService.java new file mode 100644 index 00000000..df8e4ebd --- /dev/null +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteAuthService.java @@ -0,0 +1,21 @@ +package com.ruoyi.system.api; + +import com.ruoyi.common.core.constant.ServiceNameConstants; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.api.factory.RemoteAuthFallbackFactory; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; + +@FeignClient(contextId = "remoteAuthService", value = ServiceNameConstants.AUTH_SERVICE, fallbackFactory = RemoteAuthFallbackFactory.class) +public interface RemoteAuthService { + + @PostMapping("/oauth2") + public AjaxResult add(@Validated @RequestBody SysUser user); + + @PutMapping("/oauth2") + public AjaxResult edit(@Validated @RequestBody SysUser user); +} diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteMmpService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteMmpService.java new file mode 100644 index 00000000..45e2ccfd --- /dev/null +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteMmpService.java @@ -0,0 +1,30 @@ +package com.ruoyi.system.api; + +import com.ruoyi.common.core.constant.ServiceNameConstants; +import com.ruoyi.common.core.web.domain.GenericsAjaxResult; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.api.factory.RemoteMmpFallbackFactory; +import io.swagger.annotations.ApiOperation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +@FeignClient(contextId = "remoteMmpService", value = ServiceNameConstants.MANAGEMENT_SERVICE, fallbackFactory = RemoteMmpFallbackFactory.class) +public interface RemoteMmpService { + @GetMapping("/gitLink/login") + public GenericsAjaxResult gitLinkLogin(@RequestParam("username") String username, @RequestParam("password") String password); + + @PostMapping("/gitLink/createGitLinkUser") + public GenericsAjaxResult createGitLinkUser(@RequestBody SysUser sysUser) throws Exception; + + @PostMapping("/gitLink/resetPwd") + public GenericsAjaxResult resetPwd(@RequestBody SysUser sysUser) throws Exception; + + @PutMapping("/gitLink/resetEmail") + public GenericsAjaxResult resetEmail(@RequestBody SysUser sysUser) throws Exception; + + @PutMapping("/gitLink/resetPhoneNum") + public GenericsAjaxResult resetPhoneNum(@RequestBody SysUser sysUser) throws Exception; + + @DeleteMapping("/gitLink/deleteGitLinkUser") + public GenericsAjaxResult deleteGitLinkUser(@RequestBody SysUser sysUser) throws Exception; +} diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java index f074cec3..0384bd7e 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java @@ -1,11 +1,7 @@ package com.ruoyi.system.api; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.*; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.constant.ServiceNameConstants; import com.ruoyi.common.core.domain.R; diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/constant/Constant.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constant/Constant.java similarity index 86% rename from ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/constant/Constant.java rename to ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constant/Constant.java index f6b273b4..8ef31ba8 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/constant/Constant.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constant/Constant.java @@ -1,7 +1,6 @@ -package com.ruoyi.platform.constant; +package com.ruoyi.system.api.constant; public class Constant { - public final static int Image_Type_Pub = 1; // 公共镜像 public final static int Image_Type_Pri = 0; // 私有镜像 @@ -22,8 +21,8 @@ public class Constant { public final static int Git_Category_Id = 39; - public final static String Topic_Dataset = "ci4s-dataset"; - public final static String Topic_model = "ci4s-model"; + public final static String Topic_Dataset = "dataset"; + public final static String Topic_model = "model"; public final static String Item_Public = "public"; @@ -31,6 +30,8 @@ public class Constant { public final static String Source_Hand_Export = "hand_export"; public final static String Source_Add = "add"; + public final static String Building = "building"; + public final static String Running = "Running"; public final static String Failed = "Failed"; public final static String Pending = "Pending"; @@ -56,4 +57,10 @@ public class Constant { public final static String TaskType_Ray = "ray"; public final static String TaskType_ActiveLearn = "active_learn"; public final static String TaskType_Service = "service"; + public final static String DelFlag = "2"; + + public final static String Code = "123123"; + + public final static String Sex_Men = "0"; + } diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java index 4d960370..63faa450 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java @@ -1,11 +1,13 @@ package com.ruoyi.system.api.domain; -import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.annotation.Excel.ColumnType; -import com.ruoyi.common.core.annotation.Excel.Type; -import com.ruoyi.common.core.annotation.Excels; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ContentStyle; +import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum; +import com.alibaba.excel.enums.poi.VerticalAlignmentEnum; import com.ruoyi.common.core.web.domain.BaseEntity; import com.ruoyi.common.core.xss.Xss; +import com.ruoyi.system.api.constant.Constant; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -20,51 +22,56 @@ import java.util.List; * * @author ruoyi */ +@ExcelIgnoreUnannotated +@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, + verticalAlignment = VerticalAlignmentEnum.CENTER) public class SysUser extends BaseEntity { private static final long serialVersionUID = 1L; /** * 用户ID */ - @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") + @ExcelProperty(value = "用户序号", order = 1) private Long userId; /** * 部门ID */ - @Excel(name = "部门编号", type = Type.IMPORT) + @ExcelProperty(value = "部门编号", order = 2) private Long deptId; /** * 用户账号 */ - @Excel(name = "登录名称") + @ExcelProperty(value = "登录名称", order = 3) private String userName; /** * 用户昵称 */ - @Excel(name = "用户名称") + @ExcelProperty(value = "用户名称", order = 4) private String nickName; /** * 用户邮箱 */ - @Excel(name = "用户邮箱") + @ExcelProperty(value = "邮箱", order = 4) private String email; /** * 手机号码 */ - @Excel(name = "手机号码") + @ExcelProperty(value = "手机号码", order = 5) private String phonenumber; /** * 用户性别 */ - @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知") private String sex; + @ExcelProperty(value = "性别", order = 6) + private String sexName; + /** * 用户头像 */ @@ -75,10 +82,11 @@ public class SysUser extends BaseEntity { */ private String password; + private String originPassword; + /** * 帐号状态(0正常 1停用) */ - @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用") private String status; /** @@ -89,22 +97,24 @@ public class SysUser extends BaseEntity { /** * 最后登录IP */ - @Excel(name = "最后登录IP", type = Type.EXPORT) + @ExcelProperty(value = "最后登录IP", order = 7) private String loginIp; /** * 最后登录时间 */ - @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) +// @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) + @ExcelProperty(value = "最后登录时间", order = 8) private Date loginDate; /** * 部门对象 */ - @Excels({ - @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), - @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT) - }) +// @Excels({ +// @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), +// @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT) +// }) +// @ExcelProperty(value = "部门", order = 4) private SysDept dept; /** @@ -127,10 +137,6 @@ public class SysUser extends BaseEntity { */ private Long roleId; - private String gitLinkUsername; - - private String gitLinkPassword; - private Float credit; public SysUser() { @@ -213,6 +219,18 @@ public class SysUser extends BaseEntity { this.sex = sex; } + public String getSexName() { + if (Constant.Sex_Men.equals(this.sex)) { + return "男"; + } else { + return "女"; + } + } + + public void setSexName(String sexName) { + this.sexName = sexName; + } + public String getAvatar() { return avatar; } @@ -229,6 +247,14 @@ public class SysUser extends BaseEntity { this.password = password; } + public String getOriginPassword() { + return originPassword; + } + + public void setOriginPassword(String originPassword) { + this.originPassword = originPassword; + } + public String getStatus() { return status; } @@ -301,22 +327,6 @@ public class SysUser extends BaseEntity { this.roleId = roleId; } - public void setGitLinkUsername(String gitLinkUsername) { - this.gitLinkUsername = gitLinkUsername; - } - - public String getGitLinkUsername() { - return gitLinkUsername; - } - - public void setGitLinkPassword(String gitLinkPassword) { - this.gitLinkPassword = gitLinkPassword; - } - - public String getGitLinkPassword() { - return gitLinkPassword; - } - public void setCredit(Float credit) { this.credit = credit; } @@ -337,6 +347,7 @@ public class SysUser extends BaseEntity { .append("sex", getSex()) .append("avatar", getAvatar()) .append("password", getPassword()) + .append("originPassword", getOriginPassword()) .append("status", getStatus()) .append("delFlag", getDelFlag()) .append("loginIp", getLoginIp()) @@ -347,8 +358,6 @@ public class SysUser extends BaseEntity { .append("updateTime", getUpdateTime()) .append("remark", getRemark()) .append("dept", getDept()) - .append("gitLinkUsername", getGitLinkUsername()) - .append("gitLinkPassword", getGitLinkPassword()) .append("credit", getCredit()) .toString(); } diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteAuthFallbackFactory.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteAuthFallbackFactory.java new file mode 100644 index 00000000..e75e791c --- /dev/null +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteAuthFallbackFactory.java @@ -0,0 +1,30 @@ +package com.ruoyi.system.api.factory; + +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.system.api.RemoteAuthService; +import com.ruoyi.system.api.domain.SysUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.openfeign.FallbackFactory; +import org.springframework.stereotype.Component; + +@Component +public class RemoteAuthFallbackFactory implements FallbackFactory { + private static final Logger log = LoggerFactory.getLogger(RemoteAuthFallbackFactory.class); + + @Override + public RemoteAuthService create(Throwable throwable) { + log.error("Auth服务调用失败:{}", throwable.getMessage()); + return new RemoteAuthService() { + @Override + public AjaxResult add(SysUser user) { + return AjaxResult.error("新增Oauth2用户失败"); + } + + @Override + public AjaxResult edit(SysUser user) { + return AjaxResult.error("更新Oauth2用户失败"); + } + }; + } +} diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteMmpFallbackFactory.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteMmpFallbackFactory.java new file mode 100644 index 00000000..6dda4d7c --- /dev/null +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteMmpFallbackFactory.java @@ -0,0 +1,51 @@ +package com.ruoyi.system.api.factory; + +import com.ruoyi.common.core.web.domain.GenericsAjaxResult; +import com.ruoyi.system.api.RemoteMmpService; +import com.ruoyi.system.api.domain.SysUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.openfeign.FallbackFactory; +import org.springframework.stereotype.Component; + +@Component +public class RemoteMmpFallbackFactory implements FallbackFactory { + + private static final Logger log = LoggerFactory.getLogger(RemoteMmpFallbackFactory.class); + + @Override + public RemoteMmpService create(Throwable throwable) { + log.error("管理平台服务调用失败:{}", throwable.getMessage()); + return new RemoteMmpService() { + @Override + public GenericsAjaxResult gitLinkLogin(String username, String password) { + return GenericsAjaxResult.error("刷新gitLink登录信息失败"); + } + + @Override + public GenericsAjaxResult createGitLinkUser(SysUser sysUser) throws Exception { + throw new Exception("新增gitLink用户失败:" + throwable.getMessage()); + } + + @Override + public GenericsAjaxResult resetPwd(SysUser sysUser) throws Exception { + throw new Exception("修改gitLink用户密码失败:" + throwable.getMessage()); + } + + @Override + public GenericsAjaxResult resetEmail(SysUser sysUser) throws Exception { + throw new Exception("修改gitLink用户邮箱失败:" + throwable.getMessage()); + } + + @Override + public GenericsAjaxResult resetPhoneNum(SysUser sysUser) throws Exception { + throw new Exception("修改gitLink用户手机号失败:" + throwable.getMessage()); + } + + @Override + public GenericsAjaxResult deleteGitLinkUser(SysUser sysUser) throws Exception { + throw new Exception("删除gitLink用户失败:" + throwable.getMessage()); + } + }; + } +} diff --git a/ruoyi-api/ruoyi-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-api/ruoyi-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 0a60da5e..05626c9d 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/ruoyi-api/ruoyi-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,3 +1,5 @@ com.ruoyi.system.api.factory.RemoteUserFallbackFactory com.ruoyi.system.api.factory.RemoteLogFallbackFactory com.ruoyi.system.api.factory.RemoteFileFallbackFactory +com.ruoyi.system.api.factory.RemoteMmpFallbackFactory +com.ruoyi.system.api.factory.RemoteAuthFallbackFactory diff --git a/ruoyi-auth/pom.xml b/ruoyi-auth/pom.xml index 96f78cf0..df3579f1 100644 --- a/ruoyi-auth/pom.xml +++ b/ruoyi-auth/pom.xml @@ -51,9 +51,32 @@ com.ruoyi ruoyi-common-security - + + + + com.mysql + mysql-connector-j + + + + + com.ruoyi + ruoyi-common-datasource + + + + + com.ruoyi + ruoyi-common-datascope + + + + + com.ruoyi + ruoyi-common-log + - + ${project.artifactId} diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/RuoYiAuthApplication.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/RuoYiAuthApplication.java index 1e3a0874..8a8d2b84 100644 --- a/ruoyi-auth/src/main/java/com/ruoyi/auth/RuoYiAuthApplication.java +++ b/ruoyi-auth/src/main/java/com/ruoyi/auth/RuoYiAuthApplication.java @@ -1,5 +1,6 @@ package com.ruoyi.auth; +import com.ruoyi.common.security.annotation.EnableCustomConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @@ -10,6 +11,7 @@ import com.ruoyi.common.security.annotation.EnableRyFeignClients; * * @author ruoyi */ +@EnableCustomConfig @EnableRyFeignClients @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) public class RuoYiAuthApplication diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/controller/Oauth2Controller.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/controller/Oauth2Controller.java new file mode 100644 index 00000000..23c9e924 --- /dev/null +++ b/ruoyi-auth/src/main/java/com/ruoyi/auth/controller/Oauth2Controller.java @@ -0,0 +1,26 @@ +package com.ruoyi.auth.controller; + +import com.ruoyi.auth.service.Oauth2Service; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.system.api.domain.SysUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/oauth2") +public class Oauth2Controller extends BaseController { + @Autowired + private Oauth2Service oauth2Service; + + @PostMapping + public AjaxResult add(@Validated @RequestBody SysUser user) { + return toAjax(oauth2Service.insertOauth2User(user)); + } + + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysUser user) { + return toAjax(oauth2Service.updateOauth2User(user)); + } +} diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/domain/OauthAccount.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/domain/OauthAccount.java new file mode 100644 index 00000000..b99467bc --- /dev/null +++ b/ruoyi-auth/src/main/java/com/ruoyi/auth/domain/OauthAccount.java @@ -0,0 +1,37 @@ +package com.ruoyi.auth.domain; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import lombok.Data; + +import java.util.Date; + +@Data +@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) +public class OauthAccount { + private Long id; + + private String clientId; + + private String username; + + private String password; + + private String mobile; + + private String email; + + private Integer enabled; + + private Integer accountNonExpired; + + private Integer credentialsNonExpired; + + private Integer accountNonLocked; + + private Integer accountNonDeleted; + + private Date createdTime; + + private Date updatedTime; +} diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/mapper/Oauth2Mapper.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/mapper/Oauth2Mapper.java new file mode 100644 index 00000000..bc739599 --- /dev/null +++ b/ruoyi-auth/src/main/java/com/ruoyi/auth/mapper/Oauth2Mapper.java @@ -0,0 +1,10 @@ +package com.ruoyi.auth.mapper; + +import com.ruoyi.auth.domain.OauthAccount; +import org.apache.ibatis.annotations.Param; + +public interface Oauth2Mapper { + int insertOauth2User(@Param("oauthAccount")OauthAccount oauthAccount); + + int updateOauth2User(@Param("oauthAccount")OauthAccount oauthAccount); +} diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/Oauth2Service.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/service/Oauth2Service.java new file mode 100644 index 00000000..02b81404 --- /dev/null +++ b/ruoyi-auth/src/main/java/com/ruoyi/auth/service/Oauth2Service.java @@ -0,0 +1,45 @@ +package com.ruoyi.auth.service; + +import com.ruoyi.auth.domain.OauthAccount; +import com.ruoyi.auth.mapper.Oauth2Mapper; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.system.api.constant.Constant; +import com.ruoyi.system.api.domain.SysUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class Oauth2Service { + @Value("${oauth2.client-id}") + String clientId; + + @Autowired + private Oauth2Mapper oauth2Mapper; + + public int insertOauth2User(SysUser user) { + OauthAccount oauthAccount = new OauthAccount(); + oauthAccount.setClientId(clientId); + oauthAccount.setUsername(user.getUserName()); + oauthAccount.setPassword(user.getPassword()); + oauthAccount.setMobile(user.getPhonenumber()); + oauthAccount.setEmail(user.getEmail()); + oauthAccount.setEnabled(Constant.State_valid); + return oauth2Mapper.insertOauth2User(oauthAccount); + } + + public int updateOauth2User(SysUser user) { + OauthAccount oauthAccount = new OauthAccount(); + oauthAccount.setClientId(clientId); + oauthAccount.setUsername(user.getUserName()); + if (StringUtils.isNotEmpty(user.getPassword())) { + oauthAccount.setPassword(user.getPassword()); + } + oauthAccount.setMobile(user.getPhonenumber()); + oauthAccount.setEmail(user.getEmail()); + if (Constant.DelFlag.equals(user.getDelFlag())) { + oauthAccount.setEnabled(Constant.State_invalid); + } + return oauth2Mapper.updateOauth2User(oauthAccount); + } +} diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java index 2e1a57e8..10a53f86 100644 --- a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java +++ b/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java @@ -1,8 +1,6 @@ package com.ruoyi.auth.service; import com.ruoyi.auth.form.AccessTokenVo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.SecurityConstants; @@ -15,18 +13,20 @@ import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.RemoteMmpService; import com.ruoyi.system.api.RemoteUserService; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.model.LoginUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * 登录校验方法 - * + * * @author ruoyi */ @Component -public class SysLoginService -{ +public class SysLoginService { @Autowired private RemoteUserService remoteUserService; @@ -39,92 +39,82 @@ public class SysLoginService @Autowired private RedisService redisService; + @Autowired + private RemoteMmpService remoteMmpService; + /** * 登录 */ - public LoginUser login(String username, String password) - { + public LoginUser login(String username, String password) { // 用户名或密码为空 错误 - if (StringUtils.isAnyBlank(username, password)) - { + if (StringUtils.isAnyBlank(username, password)) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写"); throw new ServiceException("用户/密码必须填写"); } // 密码如果不在指定范围内 错误 if (password.length() < UserConstants.PASSWORD_MIN_LENGTH - || password.length() > UserConstants.PASSWORD_MAX_LENGTH) - { + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围"); throw new ServiceException("用户密码不在指定范围"); } // 用户名不在指定范围内 错误 if (username.length() < UserConstants.USERNAME_MIN_LENGTH - || username.length() > UserConstants.USERNAME_MAX_LENGTH) - { + || username.length() > UserConstants.USERNAME_MAX_LENGTH) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围"); throw new ServiceException("用户名不在指定范围"); } // IP黑名单校验 String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST)); - if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) - { + if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "很遗憾,访问IP已被列入系统黑名单"); throw new ServiceException("很遗憾,访问IP已被列入系统黑名单"); } // 查询用户信息 R userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); - if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) - { + if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); throw new ServiceException("登录用户:" + username + " 不存在"); } - if (R.FAIL == userResult.getCode()) - { + if (R.FAIL == userResult.getCode()) { throw new ServiceException(userResult.getMsg()); } - + LoginUser userInfo = userResult.getData(); SysUser user = userResult.getData().getSysUser(); - if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) - { + if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除"); throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); } - if (UserStatus.DISABLE.getCode().equals(user.getStatus())) - { + if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员"); throw new ServiceException("对不起,您的账号:" + username + " 已停用"); } passwordService.validate(user, password); + remoteMmpService.gitLinkLogin(username, user.getOriginPassword()); recordLogService.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功"); return userInfo; } - public void logout(String loginName) - { + public void logout(String loginName) { recordLogService.recordLogininfor(loginName, Constants.LOGOUT, "退出成功"); } /** * 注册 */ - public void register(String username, String password) - { + public void register(String username, String password) { // 用户名或密码为空 错误 - if (StringUtils.isAnyBlank(username, password)) - { + if (StringUtils.isAnyBlank(username, password)) { throw new ServiceException("用户/密码必须填写"); } if (username.length() < UserConstants.USERNAME_MIN_LENGTH - || username.length() > UserConstants.USERNAME_MAX_LENGTH) - { + || username.length() > UserConstants.USERNAME_MAX_LENGTH) { throw new ServiceException("账户长度必须在2到20个字符之间"); } if (password.length() < UserConstants.PASSWORD_MIN_LENGTH - || password.length() > UserConstants.PASSWORD_MAX_LENGTH) - { + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) { throw new ServiceException("密码长度必须在5到20个字符之间"); } @@ -135,8 +125,7 @@ public class SysLoginService sysUser.setPassword(SecurityUtils.encryptPassword(password)); R registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER); - if (R.FAIL == registerResult.getCode()) - { + if (R.FAIL == registerResult.getCode()) { throw new ServiceException(registerResult.getMsg()); } recordLogService.recordLogininfor(username, Constants.REGISTER, "注册成功"); @@ -144,52 +133,45 @@ public class SysLoginService public LoginUser loginByKey(String username, String key) { // 用户名或密码为空 错误 - if (StringUtils.isAnyBlank(username, key)) - { + if (StringUtils.isAnyBlank(username, key)) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/key必须填写"); throw new ServiceException("用户/key必须填写"); } // 用户名不在指定范围内 错误 if (username.length() < UserConstants.USERNAME_MIN_LENGTH - || username.length() > UserConstants.USERNAME_MAX_LENGTH) - { + || username.length() > UserConstants.USERNAME_MAX_LENGTH) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围"); throw new ServiceException("用户名不在指定范围"); } // IP黑名单校验 String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST)); - if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) - { + if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "很遗憾,访问IP已被列入系统黑名单"); throw new ServiceException("很遗憾,访问IP已被列入系统黑名单"); } // 查询用户信息 R userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); - if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) - { + if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); throw new ServiceException("登录用户:" + username + " 不存在"); } - if (R.FAIL == userResult.getCode()) - { + if (R.FAIL == userResult.getCode()) { throw new ServiceException(userResult.getMsg()); } LoginUser userInfo = userResult.getData(); SysUser user = userResult.getData().getSysUser(); - if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) - { + if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除"); throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); } - if (UserStatus.DISABLE.getCode().equals(user.getStatus())) - { + if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员"); throw new ServiceException("对不起,您的账号:" + username + " 已停用"); } - if (!StringUtils.equals(key,"h1n2x3j4y5@")){ + if (!StringUtils.equals(key, "h1n2x3j4y5@")) { throw new ServiceException("对不起,您的key不正确"); } return userInfo; @@ -200,51 +182,44 @@ public class SysLoginService String username = accountInfo.getUsername(); // 用户名或密码为空 错误 - if (StringUtils.isAnyBlank(username)) - { + if (StringUtils.isAnyBlank(username)) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写"); throw new ServiceException("用户/密码必须填写"); } // 用户名不在指定范围内 错误 if (username.length() < UserConstants.USERNAME_MIN_LENGTH - || username.length() > UserConstants.USERNAME_MAX_LENGTH) - { + || username.length() > UserConstants.USERNAME_MAX_LENGTH) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围"); throw new ServiceException("用户名不在指定范围"); } // IP黑名单校验 String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST)); - if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) - { + if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "很遗憾,访问IP已被列入系统黑名单"); throw new ServiceException("很遗憾,访问IP已被列入系统黑名单"); } // 查询用户信息 R userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); - if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) - { + if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); throw new ServiceException("登录用户:" + username + " 不存在"); - // register(username, "123456"); + // register(username, "123456"); // userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); } - if (R.FAIL == userResult.getCode()) - { + if (R.FAIL == userResult.getCode()) { throw new ServiceException(userResult.getMsg()); } LoginUser userInfo = userResult.getData(); SysUser user = userResult.getData().getSysUser(); - if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) - { + if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除"); throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); } - if (UserStatus.DISABLE.getCode().equals(user.getStatus())) - { + if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员"); throw new ServiceException("对不起,您的账号:" + username + " 已停用"); } diff --git a/ruoyi-auth/src/main/resources/mapper/auth/Oauth2Mapper.xml b/ruoyi-auth/src/main/resources/mapper/auth/Oauth2Mapper.xml new file mode 100644 index 00000000..16d46aed --- /dev/null +++ b/ruoyi-auth/src/main/resources/mapper/auth/Oauth2Mapper.xml @@ -0,0 +1,31 @@ + + + + + insert into oauth_account(client_id, username, password, mobile, email, enabled) + values (#{oauthAccount.clientId}, #{oauthAccount.username}, #{oauthAccount.password}, #{oauthAccount.mobile}, + #{oauthAccount.email}, #{oauthAccount.enabled}) + + + + update oauth_account + + + username = #{oauthAccount.username}, + + + password = #{oauthAccount.password}, + + + mobile = #{oauthAccount.mobile}, + + + email = #{oauthAccount.email}, + + + enabled = #{oauthAccount.enabled}, + + + where username = #{oauthAccount.username} and enabled = 1 + + \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java index 421a3226..32f01374 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java @@ -21,4 +21,6 @@ public class ServiceNameConstants * 文件服务的serviceid */ public static final String FILE_SERVICE = "ruoyi-file"; + + public static final String MANAGEMENT_SERVICE = "management-platform"; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java index 76f3b3d7..8df3e049 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java @@ -257,7 +257,7 @@ public class ExcelUtil /** * 对excel表单默认第一个索引名转换成list - * + * * @param is 输入流 * @return 转换后集合 */ @@ -282,7 +282,7 @@ public class ExcelUtil /** * 对excel表单默认第一个索引名转换成list - * + * * @param is 输入流 * @param titleNum 标题占用行数 * @return 转换后集合 @@ -294,7 +294,7 @@ public class ExcelUtil /** * 对excel表单指定表格索引名转换成list - * + * * @param sheetName 表格索引名 * @param titleNum 标题占用行数 * @param is 输入流 @@ -503,7 +503,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @return 结果 */ public void exportExcel(HttpServletResponse response) @@ -565,7 +565,7 @@ public class ExcelUtil /** * 填充excel数据 - * + * * @param index 序号 * @param row 单元格行 */ @@ -636,7 +636,7 @@ public class ExcelUtil /** * 创建表格样式 - * + * * @param wb 工作薄对象 * @return 样式列表 */ @@ -689,7 +689,7 @@ public class ExcelUtil /** * 根据Excel注解创建表格头样式 - * + * * @param wb 工作薄对象 * @return 自定义样式列表 */ @@ -722,7 +722,7 @@ public class ExcelUtil /** * 根据Excel注解创建表格列样式 - * + * * @param wb 工作薄对象 * @return 自定义样式列表 */ @@ -784,7 +784,7 @@ public class ExcelUtil /** * 设置单元格信息 - * + * * @param value 单元格值 * @param attr 注解相关 * @param cell 单元格信息 @@ -943,7 +943,7 @@ public class ExcelUtil /** * 设置 POI XSSFSheet 单元格提示或选择框 - * + * * @param sheet 表单 * @param textlist 下拉框显示的内容 * @param promptContent 提示内容 @@ -953,7 +953,7 @@ public class ExcelUtil * @param endCol 结束列 */ public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, - int firstCol, int endCol) + int firstCol, int endCol) { DataValidationHelper helper = sheet.getDataValidationHelper(); DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1"); @@ -980,7 +980,7 @@ public class ExcelUtil /** * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框). - * + * * @param sheet 要设置的sheet. * @param textlist 下拉框显示的内容 * @param promptContent 提示内容 @@ -1069,7 +1069,7 @@ public class ExcelUtil /** * 反向解析值 男=0,女=1,未知=2 - * + * * @param propertyValue 参数值 * @param converterExp 翻译注解 * @param separator 分隔符 @@ -1311,7 +1311,7 @@ public class ExcelUtil /** * 创建工作表 - * + * * @param sheetNo sheet数量 * @param index 序号 */ @@ -1328,7 +1328,7 @@ public class ExcelUtil /** * 获取单元格值 - * + * * @param row 获取的行 * @param column 获取单元格列号 * @return 单元格值 @@ -1388,7 +1388,7 @@ public class ExcelUtil /** * 判断是否是空行 - * + * * @param row 判断的行 * @return */ @@ -1411,7 +1411,7 @@ public class ExcelUtil /** * 格式化不同类型的日期对象 - * + * * @param dateFormat 日期格式 * @param val 被格式化的日期对象 * @return 格式化后的日期字符 @@ -1477,7 +1477,7 @@ public class ExcelUtil /** * 获取对象的子列表方法 - * + * * @param name 名称 * @param pojoClass 类对象 * @return 子列表方法 diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/dataset/NewDatasetFromGitController.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/dataset/NewDatasetFromGitController.java index 2c60c3e6..f572dd45 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/dataset/NewDatasetFromGitController.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/dataset/NewDatasetFromGitController.java @@ -3,6 +3,7 @@ package com.ruoyi.platform.controller.dataset; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.platform.domain.Dataset; import com.ruoyi.platform.service.NewDatasetService; +import com.ruoyi.platform.utils.DVCUtils; import com.ruoyi.platform.vo.LabelDatasetVersionVo; import com.ruoyi.platform.vo.NewDatasetVo; import com.ruoyi.platform.vo.QueryModelMetricsVo; @@ -15,6 +16,8 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.Nullable; import javax.annotation.Resource; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; import java.util.Map; import java.util.Optional; @@ -29,6 +32,8 @@ public class NewDatasetFromGitController { @Resource private NewDatasetService newDatasetService; + @Resource + private DVCUtils dvcUtils; /** * 新增数据集与版本新 @@ -172,7 +177,15 @@ public class NewDatasetFromGitController { @PostMapping("/getVersionsCompare") @ApiOperation(value = "获取数据集版本对比") - public AjaxResult getVersionsCompare(@RequestBody QueryModelMetricsVo querydatasetVo) throws Exception{ + public AjaxResult getVersionsCompare(@RequestBody QueryModelMetricsVo querydatasetVo) throws Exception { return AjaxResult.success(this.newDatasetService.getVersionsCompare(querydatasetVo)); } + + @DeleteMapping("/deleteFile") + @ApiOperation(value = "删除文件") + public AjaxResult deleteFile(@RequestParam("url") String url, @RequestParam("fileName") String fileName) { + Path file = Paths.get(url, System.getProperty("file.separator"), fileName); + dvcUtils.deletePath(file); + return AjaxResult.success("删除成功"); + } } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/git/GitLinkController.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/git/GitLinkController.java new file mode 100644 index 00000000..768db5b1 --- /dev/null +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/git/GitLinkController.java @@ -0,0 +1,61 @@ +package com.ruoyi.platform.controller.git; + +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.GenericsAjaxResult; +import com.ruoyi.platform.service.GitService; +import com.ruoyi.system.api.domain.SysUser; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +@RestController +@RequestMapping("gitLink") +@Api("gitLink") +public class GitLinkController extends BaseController { + + @Resource + private GitService gitService; + + @GetMapping("/login") + @ApiOperation("刷新giotLink用户信息") + public GenericsAjaxResult gitLinkLogin(@RequestParam("username") String username, @RequestParam("password") String password) { + return genericsSuccess(gitService.login(username, password)); + } + + @PostMapping("/createGitLinkUser") + @ApiOperation("新增gitLink用户") + public GenericsAjaxResult createGitLinkUser(@RequestBody SysUser sysUser) throws Exception { + gitService.createUser(sysUser); + return GenericsAjaxResult.success("新增成功"); + } + + @PostMapping("/resetPwd") + @ApiOperation("更改gitLink用户密码") + public GenericsAjaxResult resetPwd(@RequestBody SysUser sysUser) throws Exception { + gitService.resetPwd(sysUser); + return GenericsAjaxResult.success("修改成功"); + } + + @PutMapping("/resetEmail") + @ApiOperation("更改gitLink用户邮箱") + public GenericsAjaxResult resetEmail(@RequestBody SysUser sysUser) throws Exception { + gitService.resetEmail(sysUser); + return GenericsAjaxResult.success("修改成功"); + } + + @PutMapping("/resetPhoneNum") + @ApiOperation("更改gitLink用户手机号") + public GenericsAjaxResult resetPhoneNum(@RequestBody SysUser sysUser) throws Exception { + gitService.resetPhoneNum(sysUser); + return GenericsAjaxResult.success("修改成功"); + } + + @DeleteMapping("/deleteGitLinkUser") + @ApiOperation("删除gitLink用户") + public GenericsAjaxResult deleteGitLinkUser(@RequestBody SysUser sysUser) throws Exception { + gitService.deleteUser(sysUser); + return GenericsAjaxResult.success("删除成功"); + } +} diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/image/ImageController.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/image/ImageController.java index 0c0cc1f3..d4be4c95 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/image/ImageController.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/image/ImageController.java @@ -92,7 +92,7 @@ public class ImageController extends BaseController { @PostMapping("/addImageAndVersion") @ApiOperation("添加镜像和版本") public GenericsAjaxResult addImageAndVersion(@RequestBody ImageVo imageVo) throws Exception { - return genericsSuccess(this.imageService.insertImageAndVersion(imageVo)); + return this.imageService.insertImageAndVersion(imageVo); } @@ -131,8 +131,8 @@ public class ImageController extends BaseController { @ApiOperation("从本地上传构建镜像") public GenericsAjaxResult> createImageFromLocal(@RequestParam("name") String imageName, @RequestParam("tag") String imageTag, - @RequestParam("path") String path) throws Exception { - return genericsSuccess(this.imageService.createImageFromLocal(imageName, imageTag, path)); + @RequestParam("fileName") String fileName) throws Exception { + return genericsSuccess(this.imageService.createImageFromLocal(imageName, imageTag, fileName)); } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/image/ImageVersionController.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/image/ImageVersionController.java index d9e3977f..f8ad69a4 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/image/ImageVersionController.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/image/ImageVersionController.java @@ -90,7 +90,7 @@ public class ImageVersionController extends BaseController { */ @DeleteMapping("{id}") public GenericsAjaxResult deleteById(@PathVariable("id") Integer id) throws Exception { - return genericsSuccess(this.imageVersionService.removeById(id)); + return this.imageVersionService.removeById(id); } } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/model/NewModelFromGitController.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/model/NewModelFromGitController.java index 33fcf5ea..78f8221b 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/model/NewModelFromGitController.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/model/NewModelFromGitController.java @@ -134,7 +134,19 @@ public class NewModelFromGitController { @PostMapping("/getVersionsCompare") @ApiOperation(value = "获取模型版本对比") - public AjaxResult getVersionsCompare(@RequestBody QueryModelMetricsVo queryModelMetricsVo) throws Exception{ + public AjaxResult getVersionsCompare(@RequestBody QueryModelMetricsVo queryModelMetricsVo) throws Exception { return AjaxResult.success(this.modelsService.getVersionsCompare(queryModelMetricsVo)); } + + @PostMapping("/praise/{id}") + @ApiOperation(value = "点赞一个项目") + public AjaxResult praise(@PathVariable("id") Integer id) throws Exception { + return AjaxResult.success(this.modelsService.praise(id)); + } + + @DeleteMapping("/unpraise/{id}") + @ApiOperation(value = "取消点赞一个项目") + public AjaxResult unpraise(@PathVariable("id") Integer id) throws Exception { + return AjaxResult.success(this.modelsService.unpraise(id)); + } } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/workspace/WorkspaceController.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/workspace/WorkspaceController.java index 541ed8b5..fb846b45 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/workspace/WorkspaceController.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/workspace/WorkspaceController.java @@ -29,7 +29,7 @@ public class WorkspaceController extends BaseController { @GetMapping("/assetCount") @ApiOperation("得到AI资产计数") public GenericsAjaxResult> getAssetCount(@RequestParam(value = "isPublic", - defaultValue = "true") Boolean isPublic) { + defaultValue = "true") Boolean isPublic) throws Exception { return genericsSuccess(this.workspaceService.getAssetCount(isPublic)); } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/ImageVersion.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/ImageVersion.java index 64413332..76977d17 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/ImageVersion.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/ImageVersion.java @@ -31,6 +31,9 @@ public class ImageVersion implements Serializable { @ApiModelProperty(value = "镜像版本") private String version; + @ApiModelProperty(value = "镜像版本描述") + private String description; + @ApiModelProperty(value = "镜像推送地址") private String url; diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/AutoMlInsStatusTask.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/AutoMlInsStatusTask.java index fa07acf6..0c71cb7d 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/AutoMlInsStatusTask.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/AutoMlInsStatusTask.java @@ -1,6 +1,6 @@ package com.ruoyi.platform.scheduling; -import com.ruoyi.platform.constant.Constant; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.platform.domain.AutoMl; import com.ruoyi.platform.domain.AutoMlIns; import com.ruoyi.platform.mapper.AutoMlDao; diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java index 926b7e21..f1cf303a 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java @@ -1,6 +1,6 @@ package com.ruoyi.platform.scheduling; -import com.ruoyi.platform.constant.Constant; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.platform.domain.Experiment; import com.ruoyi.platform.domain.ExperimentIns; import com.ruoyi.platform.mapper.ExperimentDao; @@ -18,7 +18,6 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.io.IOException; -import java.text.SimpleDateFormat; import java.time.Instant; import java.util.*; @@ -62,11 +61,12 @@ public class ExperimentInstanceStatusTask { String startedAt = (String) value.get("startedAt"); Instant instant = Instant.parse(startedAt); Date startTime = Date.from(instant); - + String phase = (String) value.get("phase"); String finishedAt = (String) value.get("finishedAt"); - if (StringUtils.isEmpty(finishedAt)) { + + if (StringUtils.isEmpty(finishedAt) && Constant.Running.equals(phase)) { resourceOccupyService.deducing(Constant.TaskType_Workflow, null, Long.valueOf(experimentIns.getId()), key, startTime); - } else { + } else if (StringUtils.isNotEmpty(finishedAt)) { resourceOccupyService.endDeduce(Constant.TaskType_Workflow, null, Long.valueOf(experimentIns.getId()), key, startTime); } } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/RayInsStatusTask.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/RayInsStatusTask.java index 533431d0..f5b0b759 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/RayInsStatusTask.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/RayInsStatusTask.java @@ -1,12 +1,13 @@ package com.ruoyi.platform.scheduling; -import com.ruoyi.platform.constant.Constant; import com.ruoyi.platform.domain.Ray; import com.ruoyi.platform.domain.RayIns; import com.ruoyi.platform.mapper.RayDao; import com.ruoyi.platform.mapper.RayInsDao; +import com.ruoyi.platform.mapper.ResourceOccupyDao; import com.ruoyi.platform.service.RayInsService; import com.ruoyi.platform.service.ResourceOccupyService; +import com.ruoyi.system.api.constant.Constant; import org.apache.commons.lang3.StringUtils; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -25,7 +26,8 @@ public class RayInsStatusTask { private RayInsDao rayInsDao; @Resource private RayDao rayDao; - + @Resource + private ResourceOccupyDao resourceOccupyDao; @Resource private ResourceOccupyService resourceOccupyService; @@ -41,14 +43,19 @@ public class RayInsStatusTask { for (RayIns rayIns : rayInsList) { //当原本状态为null或非终止态时才调用argo接口 try { - rayIns = rayInsService.queryStatusFromArgo(rayIns); - - // 扣除积分 - if (Constant.Running.equals(rayIns.getStatus())) { - resourceOccupyService.deducing(Constant.TaskType_Ray, null, rayIns.getId(), null, null); - } else if (Constant.Failed.equals(rayIns.getStatus()) || Constant.Terminated.equals(rayIns.getStatus()) - || Constant.Succeeded.equals(rayIns.getStatus())) { - resourceOccupyService.endDeduce(Constant.TaskType_Ray, null, rayIns.getId(), null, null); + Long userId = resourceOccupyDao.getResourceOccupyByTask(Constant.TaskType_Ray, rayIns.getRayId(), rayIns.getId(), null).get(0).getUserId(); + if (resourceOccupyDao.getUserCredit(userId) <= 0) { + rayIns.setStatus(Constant.Failed); + rayInsService.terminateRayIns(rayIns.getId()); + } else { + rayIns = rayInsService.queryStatusFromArgo(rayIns); + // 扣除积分 + if (Constant.Running.equals(rayIns.getStatus())) { + resourceOccupyService.deducing(Constant.TaskType_Ray, null, rayIns.getId(), null, null); + } else if (Constant.Failed.equals(rayIns.getStatus()) || Constant.Terminated.equals(rayIns.getStatus()) + || Constant.Succeeded.equals(rayIns.getStatus())) { + resourceOccupyService.endDeduce(Constant.TaskType_Ray, null, rayIns.getId(), null, null); + } } } catch (Exception e) { rayIns.setStatus(Constant.Failed); diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ResourceOccupyTask.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ResourceOccupyTask.java index c13dce32..acf2f191 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ResourceOccupyTask.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ResourceOccupyTask.java @@ -1,14 +1,15 @@ package com.ruoyi.platform.scheduling; -import com.ruoyi.platform.constant.Constant; import com.ruoyi.platform.domain.DevEnvironment; import com.ruoyi.platform.domain.ServiceVersion; import com.ruoyi.platform.mapper.DevEnvironmentDao; +import com.ruoyi.platform.mapper.ResourceOccupyDao; import com.ruoyi.platform.mapper.ServiceDao; import com.ruoyi.platform.service.JupyterService; import com.ruoyi.platform.service.ResourceOccupyService; import com.ruoyi.platform.service.ServiceService; import com.ruoyi.platform.vo.PodStatusVo; +import com.ruoyi.system.api.constant.Constant; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -23,6 +24,9 @@ public class ResourceOccupyTask { @Resource private ResourceOccupyService resourceOccupyService; + @Resource + private ResourceOccupyDao resourceOccupyDao; + @Resource private DevEnvironmentDao devEnvironmentDao; @@ -46,7 +50,10 @@ public class ResourceOccupyTask { devEnv.setUrl(podStatusVo.getUrl()); this.devEnvironmentDao.update(devEnv); } - if (Constant.Running.equals(devEnv.getStatus())) { + Long userId = resourceOccupyDao.getResourceOccupyByTask(Constant.TaskType_Dev, Long.valueOf(devEnv.getId()), null, null).get(0).getUserId(); + if (resourceOccupyDao.getUserCredit(userId) <= 0) { + jupyterService.stopJupyterService(devEnv.getId()); + } else if (Constant.Running.equals(devEnv.getStatus())) { resourceOccupyService.deducing(Constant.TaskType_Dev, Long.valueOf(devEnv.getId()), null, null, null); } } @@ -60,7 +67,10 @@ public class ResourceOccupyTask { Map runStates = serviceService.getRunState(deploymentNames); serviceService.updateRunState(runStates, serviceVersions); for (ServiceVersion serviceVersion : serviceVersions) { - if (Constant.Running.equals(serviceVersion.getRunState())) { + Long userId = resourceOccupyDao.getResourceOccupyByTask(Constant.TaskType_Service, serviceVersion.getServiceId(), serviceVersion.getId(), null).get(0).getUserId(); + if (resourceOccupyDao.getUserCredit(userId) <= 0) { + serviceService.stopServiceVersion(serviceVersion.getId()); + } else if (Constant.Running.equals(serviceVersion.getRunState())) { resourceOccupyService.deducing(Constant.TaskType_Service, null, serviceVersion.getId(), null, null); } } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/GitService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/GitService.java index 85eea493..bf788d3a 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/GitService.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/GitService.java @@ -1,8 +1,8 @@ package com.ruoyi.platform.service; import com.ruoyi.platform.vo.GitProjectVo; +import com.ruoyi.system.api.domain.SysUser; -import java.io.IOException; import java.util.List; import java.util.Map; @@ -13,19 +13,29 @@ public interface GitService { String checkoutToken(); //输入token,项目名,tag,创建新项目,返回项目地址 - Map createProject(String token,GitProjectVo gitProjectVo) throws Exception; + Map createProject(String token, GitProjectVo gitProjectVo) throws Exception; - void createBranch(String token,String owner, String projectName, String branchName, String oldBranchName) throws Exception; + void createBranch(String token, String owner, String projectName, String branchName, String oldBranchName) throws Exception; - void createTopic(String token,Integer id, String topicName) throws Exception; + void createTopic(String token, Integer id, String topicName) throws Exception; - List> getBrancheList(String token,String owner, String projectName) throws Exception; + List> getBrancheList(String token, String owner, String projectName) throws Exception; - void deleteProject(String token,String owner, String projectName) throws Exception; + void deleteProject(String token, String owner, String projectName) throws Exception; - void deleteBranch(String token,String owner, String projectName, String branchName, String localPath) throws Exception; + void deleteBranch(String token, String owner, String projectName, String branchName, String localPath) throws Exception; Map getUserInfo(String token) throws Exception; - Map getProjectDetail(String owner, String identifier, String token) throws IOException; + Map getProjectDetail(String owner, String identifier, String token) throws Exception; + + void createUser(SysUser sysUser) throws Exception; + + void resetPwd(SysUser sysUser) throws Exception; + + void resetEmail(SysUser sysUser) throws Exception; + + void resetPhoneNum(SysUser sysUser) throws Exception; + + void deleteUser(SysUser sysUser) throws Exception; } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ImageService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ImageService.java index 3fd4d0b1..39b5ba53 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ImageService.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ImageService.java @@ -1,5 +1,6 @@ package com.ruoyi.platform.service; +import com.ruoyi.common.core.web.domain.GenericsAjaxResult; import com.ruoyi.platform.domain.Image; import com.ruoyi.platform.vo.ImageVo; import org.springframework.data.domain.Page; @@ -75,7 +76,7 @@ public interface ImageService { String removeById(Integer id) throws Exception; - String insertImageAndVersion(ImageVo imageVo) throws Exception; + GenericsAjaxResult insertImageAndVersion(ImageVo imageVo) throws Exception; /** * 本地上传构建镜像 @@ -85,8 +86,10 @@ public interface ImageService { * @param path * @return */ - Map createImageFromLocal(String imageName, String imageTag, String path) throws Exception; + Map createImageFromLocal(String imageName, String imageTag,String fileName) throws Exception; + Map createImageFromNet(String imageName, String imageTag, String NetPath) throws Exception; + Map uploadImageFiles(MultipartFile file) throws Exception; void saveImage(ImageVo imageVo); diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ImageVersionService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ImageVersionService.java index 737d5f6e..9fd8e3b4 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ImageVersionService.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ImageVersionService.java @@ -1,5 +1,6 @@ package com.ruoyi.platform.service; +import com.ruoyi.common.core.web.domain.GenericsAjaxResult; import com.ruoyi.platform.domain.ImageVersion; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -62,5 +63,5 @@ public interface ImageVersionService { List queryByImageId(Integer id); - String removeById(Integer id) throws Exception; + GenericsAjaxResult removeById(Integer id) throws Exception; } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelsService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelsService.java index 3cc44ba1..6bd90437 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelsService.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelsService.java @@ -116,4 +116,11 @@ public interface ModelsService { void deleteVersion(Integer repoId, String identifier, String owner, String version, String relativePath) throws Exception; Map getVersionsCompare(QueryModelMetricsVo queryModelMetricsVo) throws Exception; + + String praise(Integer id) throws Exception; + + String unpraise(Integer id) throws Exception; + + List convert(List> lst, String modelTopic, String modelTagName, String modelTypeName); + } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/NewDatasetService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/NewDatasetService.java index a1116105..5d280066 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/NewDatasetService.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/NewDatasetService.java @@ -42,4 +42,6 @@ public interface NewDatasetService { Map getVersionsCompare(QueryModelMetricsVo querydatasetVo) throws Exception; String newCreateVersionFromLabelStudio(LabelDatasetVersionVo datasetVo) throws Exception; + + List convert(List> lst, String datasetTopic, String datasetTagName, String datasetTypeName); } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ResourceOccupyService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ResourceOccupyService.java index 46c60d06..8d955cd7 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ResourceOccupyService.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ResourceOccupyService.java @@ -9,9 +9,9 @@ import java.util.Map; public interface ResourceOccupyService { - Boolean haveResource(Integer computingResourceId) throws Exception; + Boolean haveResource(Integer computingResourceId, Integer replicas) throws Exception; - void startDeduce(Integer computingResourceId, String taskType, Long taskId, Long taskInsId, Long workflowId, String taskName, String nodeId); + void startDeduce(Integer computingResourceId, Integer replicas, String taskType, Long taskId, Long taskInsId, Long workflowId, String taskName, String nodeId, Integer state); void endDeduce(String taskType, Long taskId, Long taskInsId, String nodeId, Date nodeStartTime); @@ -20,4 +20,6 @@ public interface ResourceOccupyService { Page queryByPage(PageRequest pageRequest); Map queryCredit(); + + void update(String taskType, Long taskId, Long taskInsId, Integer computingResourceId, Integer replicas); } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ServiceService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ServiceService.java index 11498f5c..cf192a93 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ServiceService.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ServiceService.java @@ -38,7 +38,7 @@ public interface ServiceService { String stopServiceVersion(Long id); - String updateServiceVersion(ServiceVersion serviceVersion) throws Exception; + String updateServiceVersion(ServiceVersion serviceVersion, Boolean reRun) throws Exception; HashMap getServiceVersionLog(Long id, String startTime, String endTime); diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/WorkspaceService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/WorkspaceService.java index 5fdf8998..3bb7112c 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/WorkspaceService.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/WorkspaceService.java @@ -20,5 +20,5 @@ public interface WorkspaceService { Map getOverview(); - Map getAssetCount(Boolean isPublic); + Map getAssetCount(Boolean isPublic) throws Exception; } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AutoMlInsServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AutoMlInsServiceImpl.java index 89358f00..8e32e5e7 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AutoMlInsServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AutoMlInsServiceImpl.java @@ -1,6 +1,6 @@ package com.ruoyi.platform.service.impl; -import com.ruoyi.platform.constant.Constant; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.platform.domain.AutoMl; import com.ruoyi.platform.domain.AutoMlIns; import com.ruoyi.platform.mapper.AutoMlDao; diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AutoMlServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AutoMlServiceImpl.java index c1b567f8..d2cb6a17 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AutoMlServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AutoMlServiceImpl.java @@ -1,7 +1,7 @@ package com.ruoyi.platform.service.impl; import com.ruoyi.common.security.utils.SecurityUtils; -import com.ruoyi.platform.constant.Constant; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.platform.domain.AutoMl; import com.ruoyi.platform.domain.AutoMlIns; import com.ruoyi.platform.mapper.AutoMlDao; @@ -199,9 +199,9 @@ public class AutoMlServiceImpl implements AutoMlService { String outputPath = minioEndpoint + "/" + output2.get("path").replace("{{workflow.name}}", (String) metadata.get("name")) + "/"; autoMlIns.setModelPath(outputPath + "save_model.joblib"); if (Constant.AutoMl_Classification.equals(autoMl.getTaskType())) { - autoMlIns.setImgPath(outputPath + "Auto-sklearn_accuracy_over_time.png" + "," + outputPath + "Train_Confusion_Matrix.png" + "," + outputPath + "Test_Confusion_Matrix.png"); + autoMlIns.setImgPath(outputPath + "Auto-sklearn_metric_over_time.png" + "," + outputPath + "Train_Confusion_Matrix.png" + "," + outputPath + "Test_Confusion_Matrix.png"); } else { - autoMlIns.setImgPath(outputPath + "Auto-sklearn_accuracy_over_time.png" + "," + outputPath + "regression.png"); + autoMlIns.setImgPath(outputPath + "Auto-sklearn_metric_over_time.png" + "," + outputPath + "regression.png"); } autoMlIns.setResultPath(outputPath + "result.txt"); String seed = autoMl.getSeed() != null ? String.valueOf(autoMl.getSeed()) : "1"; diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DevEnvironmentServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DevEnvironmentServiceImpl.java index a35a6881..eba5a138 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DevEnvironmentServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DevEnvironmentServiceImpl.java @@ -122,8 +122,7 @@ public class DevEnvironmentServiceImpl implements DevEnvironmentService { */ @Override public DevEnvironment update(DevEnvironment devEnvironment) throws Exception { - LoginUser loginUser = SecurityUtils.getLoginUser(); - devEnvironment.setUpdateBy(loginUser.getUsername()); + devEnvironment.setUpdateBy(devEnvironment.getCreateBy()); devEnvironment.setUpdateTime(new Date()); this.devEnvironmentDao.update(devEnvironment); return this.queryById(devEnvironment.getId()); diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java index a47abee3..b0cf550c 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java @@ -2,7 +2,7 @@ package com.ruoyi.platform.service.impl; import com.alibaba.fastjson2.JSON; import com.ruoyi.common.security.utils.SecurityUtils; -import com.ruoyi.platform.constant.Constant; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.platform.domain.DatasetTempStorage; import com.ruoyi.platform.domain.Experiment; import com.ruoyi.platform.domain.ExperimentIns; diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentServiceImpl.java index bf87969a..78e5c545 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentServiceImpl.java @@ -5,7 +5,6 @@ import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.platform.annotations.CheckDuplicate; -import com.ruoyi.platform.constant.Constant; import com.ruoyi.platform.domain.*; import com.ruoyi.platform.domain.dependencydomain.ProjectDepency; import com.ruoyi.platform.domain.dependencydomain.TrainTaskDepency; @@ -18,6 +17,7 @@ import com.ruoyi.platform.utils.JsonUtils; import com.ruoyi.platform.utils.YamlUtils; import com.ruoyi.platform.vo.ModelsVo; import com.ruoyi.platform.vo.NewDatasetVo; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.system.api.model.LoginUser; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -231,18 +231,20 @@ public class ExperimentServiceImpl implements ExperimentService { try { String convertRes = HttpUtils.sendPost(argoUrl + argoConvert, dag); if (convertRes == null || StringUtils.isEmpty(convertRes)) { - throw new RuntimeException("转换流水线失败"); + throw new Exception("转换流水线失败"); } Map converMap = JsonUtils.jsonToMap(convertRes); // 判断积分和资源是否足够 Map> resourceInfo = (Map>) converMap.get("resource_info"); + if (resourceInfo == null) { + throw new Exception("未配置运行所需资源"); + } for (Map.Entry> entry : resourceInfo.entrySet()) { Map node = entry.getValue(); - resourceOccupyService.haveResource((Integer) node.get("computing_resource_id")); + resourceOccupyService.haveResource((Integer) node.get("computing_resource_id"), 1); } - // 组装运行接口json Map runReqMap = new HashMap<>(); runReqMap.put("data", converMap.get("data")); @@ -277,7 +279,7 @@ public class ExperimentServiceImpl implements ExperimentService { experimentIns.setExperimentId(experiment.getId()); experimentIns.setArgoInsNs((String) metadata.get("namespace")); experimentIns.setArgoInsName((String) metadata.get("name")); - experimentIns.setStatus("Pending"); + experimentIns.setStatus(Constant.Pending); //传入实验全局参数 experimentIns.setGlobalParam(experiment.getGlobalParam()); @@ -313,11 +315,10 @@ public class ExperimentServiceImpl implements ExperimentService { // 记录开始扣积分 for (Map.Entry> entry : resourceInfo.entrySet()) { Map node = entry.getValue(); - resourceOccupyService.startDeduce((Integer) node.get("computing_resource_id"), Constant.TaskType_Workflow, Long.valueOf(id), Long.valueOf(insert.getId()), experiment.getWorkflowId(), experiment.getName(), entry.getKey()); + resourceOccupyService.startDeduce((Integer) node.get("computing_resource_id"), 1, Constant.TaskType_Workflow, Long.valueOf(id), Long.valueOf(insert.getId()), experiment.getWorkflowId(), experiment.getName(), entry.getKey(), Constant.State_building); } - } catch (Exception e) { - throw new RuntimeException(e); + throw new Exception(e); } List updatedExperimentInsList = experimentInsService.getByExperimentId(id); experiment.setExperimentInsList(updatedExperimentInsList); @@ -524,12 +525,11 @@ public class ExperimentServiceImpl implements ExperimentService { } } } - } private void insertModelDependencyNew(Map dependendcy, Map trainInfo, Map output, String metricRecord, Integer experimentInsId, Long workflowId, Integer experimentId, String experimentName, String globalParam) { LoginUser loginUser = SecurityUtils.getLoginUser(); - String gitLinkUsername = loginUser.getSysUser().getGitLinkUsername(); + String gitLinkUsername = loginUser.getSysUser().getUserName(); Iterator> dependendcyIterator = dependendcy.entrySet().iterator(); Map modelTrain = (Map) trainInfo.get("model_train"); Map modelEvaluate = (Map) trainInfo.get("model_evaluate"); diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/GitServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/GitServiceImpl.java index f7059773..60f62afe 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/GitServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/GitServiceImpl.java @@ -6,6 +6,8 @@ import com.ruoyi.platform.utils.JacksonUtil; import com.ruoyi.platform.utils.JsonUtils; import com.ruoyi.platform.utils.NewHttpUtils; import com.ruoyi.platform.vo.GitProjectVo; +import com.ruoyi.system.api.constant.Constant; +import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.model.LoginUser; import org.apache.commons.lang3.StringUtils; import org.eclipse.jgit.api.Git; @@ -34,6 +36,10 @@ public class GitServiceImpl implements GitService { private Integer redisPort; @Value("${git.endpoint}") String gitendpoint; + @Value("${git.clientId}") + String clientId; + @Value("${git.clientSecret}") + String clientSecret; @Resource private NewHttpUtils httpUtils; private static final Logger log = LoggerFactory.getLogger(GitServiceImpl.class); @@ -44,9 +50,9 @@ public class GitServiceImpl implements GitService { Map params = new HashMap<>(); params.put("grant_type", "password"); params.put("username", username); - params.put("password", password); - params.put("client_id", "jEdGwrIJixCUIJM9vj2MwA6zmoTVhUdXxiSAaaCiXwA"); - params.put("client_secret", "L3wBKTNnRo-wPen7bxR3F1myCvtVDgpWa6MnpfyWeJE"); + params.put("password", decrypt(password)); + params.put("client_id", clientId); + params.put("client_secret", clientSecret); try { // 发送POST请求 String req = httpUtils.sendPost(gitendpoint + "/oauth/token", null, JsonUtils.mapToJson(params)); @@ -65,12 +71,10 @@ public class GitServiceImpl implements GitService { if (StringUtils.isEmpty(userReq)) { throw new RuntimeException("gitlink用户信息出错"); } - LoginUser loginUser = SecurityUtils.getLoginUser(); - String ci4sUsername = loginUser.getUsername(); // 将access_token存入Redis Jedis jedis = new Jedis(redisHost, redisPort); - jedis.set(ci4sUsername + "_gitToken", accessToken); - jedis.set(ci4sUsername + "_gitUserInfo", userReq); + jedis.set(username + "_gitToken", accessToken); + jedis.set(username + "_gitUserInfo", userReq); return accessToken; } catch (Exception e) { throw new RuntimeException("gitlink用户信息出错"); @@ -82,23 +86,21 @@ public class GitServiceImpl implements GitService { LoginUser loginUser = SecurityUtils.getLoginUser(); String ci4sUsername = loginUser.getUsername(); String token = jedis.get(ci4sUsername + "_gitToken"); - String gitLinkUsername = loginUser.getSysUser().getGitLinkUsername(); - String gitLinkPassword = decrypt(loginUser.getSysUser().getGitLinkPassword()); + String gitLinkPassword = loginUser.getSysUser().getOriginPassword(); if (StringUtils.isEmpty(token)) { - login(gitLinkUsername, gitLinkPassword); + login(ci4sUsername, gitLinkPassword); token = jedis.get(ci4sUsername + "_gitToken"); } else { try { Map userInfo = getUserInfo(token); if (userInfo == null || (userInfo.get("status") != null && 401 == (Integer) userInfo.get("status"))) { - login(gitLinkUsername, gitLinkPassword); + login(ci4sUsername, gitLinkPassword); token = jedis.get(ci4sUsername + "_gitToken"); } } catch (Exception e) { throw new RuntimeException(e); } - } return token; } @@ -116,7 +118,7 @@ public class GitServiceImpl implements GitService { // "new_branch_name": "SsS", // "old_branch_name": "master" // } - String createBranchUrl = "https://www.gitlink.org.cn/api/v1/" + owner + "/" + projectName + "/branches.json"; + String createBranchUrl = gitendpoint + "/api/v1/" + owner + "/" + projectName + "/branches.json"; Map resMap = new HashMap<>(); resMap.put("new_branch_name", branchName); resMap.put("old_branch_name", oldBranchName); @@ -147,7 +149,7 @@ public class GitServiceImpl implements GitService { @Override public void deleteProject(String token, String owner, String projectName) throws Exception { - httpUtils.sendDeleteWithToken(gitendpoint + "/api/" + owner + "/" + projectName + ".json", null, token); + httpUtils.sendDeleteWithToken(gitendpoint + "/api/" + owner + "/" + projectName + ".json", null, token, null); } @Override @@ -158,7 +160,7 @@ public class GitServiceImpl implements GitService { } catch (IOException | GitAPIException e) { log.error("Exception occurred while creating local branch based on master", e); } - httpUtils.sendDeleteWithToken(gitendpoint + "/api/v1/" + owner + "/" + projectName + "/branches/" + branchName + ".json", null, token); + httpUtils.sendDeleteWithToken(gitendpoint + "/api/v1/" + owner + "/" + projectName + "/branches/" + branchName + ".json", null, token, null); } @Override @@ -172,7 +174,7 @@ public class GitServiceImpl implements GitService { } @Override - public Map getProjectDetail(String owner, String identifier, String token) throws IOException { + public Map getProjectDetail(String owner, String identifier, String token) throws Exception { String userReq = httpUtils.sendGetWithToken(gitendpoint + "/api/" + owner + "/" + identifier + "/detail.json", null, token); if (StringUtils.isEmpty(userReq)) { return null; @@ -180,4 +182,62 @@ public class GitServiceImpl implements GitService { Map runResMap = JsonUtils.jsonToMap(userReq); return runResMap; } + + @Override + public void createUser(SysUser sysUser) throws Exception { + String token = checkoutToken(); + Map resMap = new HashMap<>(); + resMap.put("phone", sysUser.getPhonenumber()); + resMap.put("email", sysUser.getEmail()); + resMap.put("username", sysUser.getUserName()); + resMap.put("password", sysUser.getPassword()); + resMap.put("password_confirmation", sysUser.getPassword()); + httpUtils.sendPostWithToken(gitendpoint + "/api/accounts/remote_register.json", null, token, JsonUtils.objectToJson(resMap)); + } + + @Override + public void resetPwd(SysUser sysUser) throws Exception { + String token = login(sysUser.getUserName(), sysUser.getOriginPassword()); + Map resMap = new HashMap<>(); + resMap.put("login", sysUser.getUserName()); + resMap.put("password", sysUser.getPassword()); + resMap.put("new_password_repeat", sysUser.getPassword()); + resMap.put("old_password", decrypt(sysUser.getOriginPassword())); + httpUtils.sendPostWithToken(gitendpoint + "/api/accounts/change_password.json", null, token, JsonUtils.objectToJson(resMap)); + } + + @Override + public void resetEmail(SysUser sysUser) throws Exception { + String token = login(sysUser.getUserName(), sysUser.getOriginPassword()); + Map resMap = new HashMap<>(); + resMap.put("email", sysUser.getEmail()); + resMap.put("password", decrypt(sysUser.getOriginPassword())); + resMap.put("code", Constant.Code); + httpUtils.sendPatchWithToken(gitendpoint + "/api/v1/" + sysUser.getUserName() + "/update_email.json", null, token, JsonUtils.objectToJson(resMap)); + } + + @Override + public void resetPhoneNum(SysUser sysUser) throws Exception { + String token = login(sysUser.getUserName(), sysUser.getOriginPassword()); + Map resMap = new HashMap<>(); + resMap.put("phone", sysUser.getPhonenumber()); + resMap.put("password", decrypt(sysUser.getOriginPassword())); + resMap.put("code", Constant.Code); + httpUtils.sendPatchWithToken(gitendpoint + "/api/v1/" + sysUser.getUserName() + "/update_phone.json", null, token, JsonUtils.objectToJson(resMap)); + } + + @Override + public void deleteUser(SysUser sysUser) throws Exception { + String token = login(sysUser.getUserName(), sysUser.getOriginPassword()); + String result = httpUtils.sendPostWithToken(gitendpoint + "/api/v1/" + sysUser.getUserName() + "/check_user_can_delete.json", null, token, null); + Map resultMap = JsonUtils.jsonToMap(result); + if ((boolean) resultMap.get("can_delete")) { + Map resMap = new HashMap<>(); + resMap.put("memo", "用户注销"); + resMap.put("password", decrypt(sysUser.getOriginPassword())); + httpUtils.sendDeleteWithToken(gitendpoint + "/api/v1/" + sysUser.getUserName() + ".json", null, token, JsonUtils.objectToJson(resMap)); + } else { + throw new Exception("用户不可删除:" + resultMap.get("message")); + } + } } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageServiceImpl.java index 591b957a..9b779a1e 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageServiceImpl.java @@ -2,10 +2,13 @@ package com.ruoyi.platform.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.util.DateUtils; +import com.ruoyi.common.core.web.domain.GenericsAjaxResult; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.platform.constant.Constant; import com.ruoyi.platform.domain.*; import com.ruoyi.platform.mapper.*; +import com.ruoyi.platform.domain.*; +import com.ruoyi.platform.mapper.*; import com.ruoyi.platform.service.ImageService; import com.ruoyi.platform.service.ImageVersionService; import com.ruoyi.platform.service.MinioService; @@ -13,6 +16,7 @@ import com.ruoyi.platform.utils.DockerClientUtil; import com.ruoyi.platform.utils.FileUtil; import com.ruoyi.platform.utils.K8sClientUtil; import com.ruoyi.platform.vo.ImageVo; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.system.api.model.LoginUser; import io.kubernetes.client.openapi.models.V1Pod; import org.apache.commons.lang3.StringUtils; @@ -87,8 +91,6 @@ public class ImageServiceImpl implements ImageService { private String mountPath; @Value("${dockerpush.proxyUrl}") private String proxyUrl; - @Value("${minio.pvcName}") - private String pvcName; @Value("${jupyter.namespace}") private String namespace; @@ -198,7 +200,7 @@ public class ImageServiceImpl implements ImageService { String username = loginUser.getUsername(); String createdBy = image.getCreateBy(); - if (!(StringUtils.equals(username, "admin") || !StringUtils.equals(username, createdBy))) { + if (!(StringUtils.equals(username, "admin") || StringUtils.equals(username, createdBy))) { throw new Exception("无权限删除该镜像"); } @@ -210,7 +212,7 @@ public class ImageServiceImpl implements ImageService { } } - image.setState(0); + image.setState(Constant.State_invalid); return this.imageDao.update(image) > 0 ? "删除成功" : "删除失败"; @@ -235,7 +237,7 @@ public class ImageServiceImpl implements ImageService { @Override @Transactional - public String insertImageAndVersion(ImageVo imageVo) throws Exception { + public GenericsAjaxResult insertImageAndVersion(ImageVo imageVo) throws Exception { Image existingImage = getByName(imageVo.getName()); Image imageToUse; if (existingImage == null) { @@ -251,13 +253,21 @@ public class ImageServiceImpl implements ImageService { } else { // 如果已存在相同名称的镜像,使用已存在的镜像 imageToUse = existingImage; + ImageVersion query = new ImageVersion(); + query.setImageId(imageToUse.getId()); + query.setTagName(imageVo.getTagName()); + long count = imageVersionDao.count(query); + if (count != 0) { + return GenericsAjaxResult.error("镜像版本已存在"); + } } ImageVersion imageVersion = new ImageVersion(); imageVersion.setImageId(imageToUse.getId()); imageVersion.setVersion(imageVo.getVersion()); imageVersion.setTagName(imageVo.getTagName()); imageVersion.setFileSize(imageVo.getFileSize()); - imageVersion.setStatus("building"); + imageVersion.setDescription(imageVo.getDescription()); + imageVersion.setStatus(Constant.Building); ImageVersion imageVersionInsert = this.imageVersionService.insert(imageVersion); if (imageVersionInsert == null) { throw new Exception("新增镜像版本失败"); @@ -269,10 +279,10 @@ public class ImageServiceImpl implements ImageService { if (imageVo.getUploadType() == 0) { resultMap = createImageFromNet(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); } else { - resultMap = createImageFromLocal(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); + resultMap = createImageFromLocal(imageVo.getName(), imageVo.getTagName(), imageVo.getFileName()); } } catch (Exception e) { - imageVersion.setStatus("failed"); + imageVersion.setStatus(Constant.Failed); imageVersionService.update(imageVersion); throw new RuntimeException("镜像构建失败: " + e.getMessage(), e); } @@ -293,8 +303,7 @@ public class ImageServiceImpl implements ImageService { return null; }); - - return "新增镜像成功,镜像构建中..."; + return GenericsAjaxResult.success("新增镜像成功,镜像构建中..."); } @Override @@ -304,7 +313,7 @@ public class ImageServiceImpl implements ImageService { V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); if (pod == null) { String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); - pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, pvcName, image); + pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, image); } String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 @@ -341,13 +350,13 @@ public class ImageServiceImpl implements ImageService { } @Override - public Map createImageFromLocal(String imageName, String imageTag, String path) throws Exception { + public Map createImageFromLocal(String imageName, String imageTag, String fileName) throws Exception { Map resultMap = new HashMap<>(); // 得到容器 V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); if (pod == null) { String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); - pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, pvcName, image); + pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, image); } String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 @@ -355,7 +364,7 @@ public class ImageServiceImpl implements ImageService { // 在这个容器的/data/admin 目录下执行命令 docker load -i fileName 得到返回的镜像名字name:tag String username = SecurityUtils.getLoginUser().getUsername(); // - String filePath = "/data/argo-workflow/" + bucketName + "/" + path; + String filePath = mountPath + "/" + username + "/" + fileName; String logs2 = k8sClientUtil.executeCommand(pod, "docker load -i " + filePath); // 在容器里执行 docker tag name:tag nexus3.kube-system.svc:8083/imageName:imageTag @@ -386,7 +395,7 @@ public class ImageServiceImpl implements ImageService { @Override public Map uploadImageFiles(MultipartFile file) throws Exception { LoginUser loginUser = SecurityUtils.getLoginUser(); - String path = "images/" + loginUser.getUsername() + "/" + file.getOriginalFilename(); + String path = "/mini-model-platform-data/images/" + loginUser.getUsername() + "/" + file.getOriginalFilename(); return minioService.uploadFile(bucketName, path, file); } @@ -422,7 +431,7 @@ public class ImageServiceImpl implements ImageService { image.setUpdateBy(username); image.setUpdateTime(new Date()); image.setCreateTime(new Date()); - image.setState(1); + image.setState(Constant.State_valid); imageDao.insert(image); ImageVersion imageVersion = new ImageVersion(); @@ -436,7 +445,7 @@ public class ImageServiceImpl implements ImageService { imageVersion.setHostIp(hostIp); imageVersion.setUpdateTime(new Date()); imageVersion.setCreateTime(new Date()); - imageVersion.setState(1); + imageVersion.setState(Constant.State_valid); imageVersion.setStatus("available"); imageVersionDao.insert(imageVersion); diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageVersionServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageVersionServiceImpl.java index 1fa596b7..bcc7fab8 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageVersionServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageVersionServiceImpl.java @@ -2,10 +2,10 @@ package com.ruoyi.platform.service.impl; import com.alibaba.fastjson2.JSON; import com.ruoyi.common.security.utils.SecurityUtils; -import com.ruoyi.platform.constant.Constant; import com.ruoyi.platform.domain.*; import com.ruoyi.platform.mapper.*; import com.ruoyi.platform.service.ImageVersionService; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.system.api.model.LoginUser; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -50,7 +50,7 @@ public class ImageVersionServiceImpl implements ImageVersionService { * 分页查询 * * @param imageVersion 筛选条件 - * @param pageRequest 分页对象 + * @param pageRequest 分页对象 * @return 查询结果 */ @Override @@ -60,21 +60,22 @@ public class ImageVersionServiceImpl implements ImageVersionService { } @Override - public List queryByImageId(Integer imageId){ + public List queryByImageId(Integer imageId) { return imageVersionDao.queryByImageId(imageId); } @Override - public String removeById(Integer id) throws Exception { + public GenericsAjaxResult removeById(Integer id) throws Exception { ImageVersion imageVersion = this.imageVersionDao.queryById(id); - if (imageVersion == null){ - return "该版本下模型文件信息不存在"; + ImageVersion query = new ImageVersion(); + query.setImageId(imageVersion.getImageId()); + long count = this.imageVersionDao.count(query); + if (count == 1) { + return GenericsAjaxResult.error("当前镜像只有一个版本,不能删除该版本"); } - List assetWorkflow = assetWorkflowDao.getAssetWorkflow(Long.valueOf(imageVersion.getImageId()), Constant.Asset_Type_Image, imageVersion.getTagName()); - if (assetWorkflow != null && !assetWorkflow.isEmpty()) { - String workflows = String.join(",", assetWorkflow.stream().map(AssetWorkflow::getWorkflowName).collect(Collectors.toSet())); - throw new Exception("该镜像版本被流水线:" + workflows + "使用,不能删除,请先删除流水线。"); + if (imageVersion == null) { + return GenericsAjaxResult.error("该版本下模型文件信息不存在"); } HashMap map = new HashMap<>(); @@ -95,12 +96,12 @@ public class ImageVersionServiceImpl implements ImageVersionService { LoginUser loginUser = SecurityUtils.getLoginUser(); String username = loginUser.getUsername(); String createdBy = imageVersion.getCreateBy(); - if (!(StringUtils.equals(username,"admin") || StringUtils.equals(username,createdBy))){ - return "无权限删除该版本下模型信息"; + if (!(StringUtils.equals(username, "admin") || StringUtils.equals(username, createdBy))) { + return GenericsAjaxResult.error("无权限删除该版本下模型信息"); } - imageVersion.setState(0); - return this.imageVersionDao.update(imageVersion)>0?"删除成功":"删除失败"; + imageVersion.setState(Constant.State_invalid); + return this.imageVersionDao.update(imageVersion) > 0 ? GenericsAjaxResult.success("删除成功") : GenericsAjaxResult.error("删除失败"); } @@ -131,7 +132,7 @@ public class ImageVersionServiceImpl implements ImageVersionService { @Override public ImageVersion update(ImageVersion imageVersion) { int currentState = imageVersion.getState(); - if(currentState == 0){ + if (currentState == 0) { throw new RuntimeException("镜像版本已被删除,无法更新。"); } LoginUser loginUser = SecurityUtils.getLoginUser(); diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/JupyterServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/JupyterServiceImpl.java index 747b2f60..7cd30203 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/JupyterServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/JupyterServiceImpl.java @@ -2,7 +2,7 @@ package com.ruoyi.platform.service.impl; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.utils.SecurityUtils; -import com.ruoyi.platform.constant.Constant; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.platform.domain.DevEnvironment; import com.ruoyi.platform.domain.PodStatus; import com.ruoyi.platform.mapper.DevEnvironmentDao; diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsServiceImpl.java index cf919b12..b822ce11 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsServiceImpl.java @@ -6,13 +6,13 @@ import com.alibaba.fastjson2.JSONObject; import com.ruoyi.common.core.utils.DateUtils; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.platform.annotations.CheckDuplicate; -import com.ruoyi.platform.constant.Constant; import com.ruoyi.platform.domain.*; import com.ruoyi.platform.domain.dependencydomain.TrainTaskDepency; import com.ruoyi.platform.mapper.*; import com.ruoyi.platform.service.*; import com.ruoyi.platform.utils.*; import com.ruoyi.platform.vo.*; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.system.api.model.LoginUser; import io.minio.messages.Item; import org.apache.commons.io.FileUtils; @@ -562,9 +562,10 @@ public class ModelsServiceImpl implements ModelsService { String token = gitService.checkoutToken(); LoginUser loginUser = SecurityUtils.getLoginUser(); String ci4sUsername = loginUser.getUsername(); - String gitLinkUsername = loginUser.getSysUser().getGitLinkUsername(); - String gitLinkPassword = decrypt(loginUser.getSysUser().getGitLinkPassword()); - Map userInfo = getUserInfo(ci4sUsername, gitLinkUsername, gitLinkPassword); + String gitLinkUsername = loginUser.getSysUser().getUserName(); + String gitLinkPassword = loginUser.getSysUser().getOriginPassword(); + Map userInfo = getUserInfo(ci4sUsername, gitLinkPassword); + String decryptGitLinkPassword = decrypt(gitLinkPassword); Integer userId = (Integer) userInfo.get("user_id"); ci4sUsername = Boolean.TRUE.equals(modelsVo.getIsPublic()) ? Constant.Item_Public : ci4sUsername; @@ -595,7 +596,7 @@ public class ModelsServiceImpl implements ModelsService { String branchName = modelsVo.getVersion(); String owner = (String) userInfo.get("login"); - String projectUrl = gitendpoint + "/" + owner + "/" + repositoryName + ".git"; + String projectUrl = gitCloneEndpoint + "/" + owner + "/" + repositoryName + ".git"; String sourcePath = modelsVo.getModelVersionVos().get(0).getUrl(); String rootPath = localPath + ci4sUsername + "/model/" + gitlinIid + "/" + repositoryName + "/" + branchName; String modelPath = rootPath + "/model"; @@ -604,7 +605,7 @@ public class ModelsServiceImpl implements ModelsService { // 创建分支 gitService.createBranch(token, (String) userInfo.get("login"), repositoryName, branchName, "master"); - // 定义标签 标签1:ci4s-model 标签2:ModelTag 标签3:ModelType + // 定义标签 标签1:model 标签2:ModelTag 标签3:ModelType gitService.createTopic(token, gitlinIid, Constant.Topic_model); if (StringUtils.isNotEmpty(modelsVo.getModelTag())) { gitService.createTopic(token, gitlinIid, "modeltag-" + modelsVo.getModelTag()); @@ -613,7 +614,7 @@ public class ModelsServiceImpl implements ModelsService { gitService.createTopic(token, gitlinIid, "modeltype-" + modelsVo.getModelType()); } - dvcUtils.gitClone(rootPath, projectUrl, branchName, gitLinkUsername, gitLinkPassword); + dvcUtils.gitClone(rootPath, projectUrl, branchName, gitLinkUsername, decryptGitLinkPassword); //干掉目标文件夹 dvcUtils.deleteDirectory(modelPath); @@ -634,7 +635,6 @@ public class ModelsServiceImpl implements ModelsService { ""); modelMetaVo.setIdentifier(repositoryName); modelMetaVo.setOwner(owner); - modelMetaVo.setVersionDesc(modelMetaVo.getDescription()); modelMetaVo.setRelativePaths(relatePath); File folder = new File(modelPath); long folderSize = FileUtil.getFolderSize(folder); @@ -669,7 +669,7 @@ public class ModelsServiceImpl implements ModelsService { dvcUtils.dvcAdd(rootPath, "model"); // git commit dvcUtils.gitCommit(rootPath, "commit from ci4s with " + loginUser.getUsername()); - dvcUtils.gitPush(rootPath, gitLinkUsername, gitLinkPassword); + dvcUtils.gitPush(rootPath, gitLinkUsername, decryptGitLinkPassword); dvcUtils.dvcPush(rootPath); } catch (Exception e) { logger.error(e.getMessage(), e); @@ -689,9 +689,10 @@ public class ModelsServiceImpl implements ModelsService { public String newCreateVersion(ModelsVo modelsVo) throws Exception { LoginUser loginUser = SecurityUtils.getLoginUser(); String ci4sUsername = loginUser.getUsername(); - String gitLinkUsername = loginUser.getSysUser().getGitLinkUsername(); - String gitLinkPassword = decrypt(loginUser.getSysUser().getGitLinkPassword()); - Map userInfo = getUserInfo(ci4sUsername, gitLinkUsername, gitLinkPassword); + String gitLinkUsername = loginUser.getSysUser().getUserName(); + String gitLinkPassword = loginUser.getSysUser().getOriginPassword(); + Map userInfo = getUserInfo(ci4sUsername, gitLinkPassword); + gitLinkPassword = decrypt(gitLinkPassword); ci4sUsername = Boolean.TRUE.equals(modelsVo.getIsPublic()) ? Constant.Item_Public : loginUser.getUsername(); String repositoryName = modelsVo.getIdentifier() == null ? ci4sUsername + "_model_" + DateUtils.dateTimeNow() : modelsVo.getIdentifier(); @@ -705,7 +706,7 @@ public class ModelsServiceImpl implements ModelsService { String branchName = modelsVo.getVersion(); String owner = (String) userInfo.get("login"); - String projectUrl = gitendpoint + "/" + owner + "/" + repositoryName + ".git"; + String projectUrl = gitCloneEndpoint + "/" + owner + "/" + repositoryName + ".git"; String rootPath = localPath + ci4sUsername + "/model/" + modelsVo.getId() + "/" + repositoryName + "/" + branchName; String modelPath = rootPath + "/model"; String metaPath = rootPath + "/metadata"; @@ -924,10 +925,9 @@ public class ModelsServiceImpl implements ModelsService { public Page newPersonalQueryByPage(ModelsVo modelsVo, PageRequest pageRequest) throws Exception { LoginUser loginUser = SecurityUtils.getLoginUser(); String ci4sUsername = loginUser.getUsername(); - String gitLinkUsername = loginUser.getSysUser().getGitLinkUsername(); - String gitLinkPassword = decrypt(loginUser.getSysUser().getGitLinkPassword()); + String gitLinkPassword = loginUser.getSysUser().getOriginPassword(); - Map userInfo = getUserInfo(ci4sUsername, gitLinkUsername, gitLinkPassword); + Map userInfo = getUserInfo(ci4sUsername, gitLinkPassword); String token = (String) userInfo.get("token"); //拼接查询url @@ -954,16 +954,15 @@ public class ModelsServiceImpl implements ModelsService { public Page newPubilcQueryByPage(ModelsVo modelsVo, PageRequest pageRequest) throws Exception { LoginUser loginUser = SecurityUtils.getLoginUser(); String ci4sUsername = loginUser.getUsername(); - String gitLinkUsername = loginUser.getSysUser().getGitLinkUsername(); - String gitLinkPassword = decrypt(loginUser.getSysUser().getGitLinkPassword()); + String gitLinkPassword = loginUser.getSysUser().getOriginPassword(); - Map userInfo = getUserInfo(ci4sUsername, gitLinkUsername, gitLinkPassword); + Map userInfo = getUserInfo(ci4sUsername, gitLinkPassword); String token = (String) userInfo.get("token"); - //拼接查询url String modelTagName = modelsVo.getModelTag(); String modelTypeName = modelsVo.getModelType(); + //拼接查询url String url = gitendpoint + "/api/projects.json?sort_direction=updated_on&sort_by=desc&category_id=" + Constant.Git_Category_Id; String name = modelsVo.getName(); @@ -1126,6 +1125,12 @@ public class ModelsServiceImpl implements ModelsService { throw new Exception("版本数据为空"); } + String token = gitService.checkoutToken(); + String url = gitendpoint + "/api/" + owner + "/" + identifier + "/detail.json"; + String req = httpUtils.sendGetWithToken(url, null, token); + Map reqMap = JacksonUtil.parseJSONStr2Map(req); + modelsVo.setPraisesCount((Integer) reqMap.get("praises_count")); + modelsVo.setPraised((Boolean) reqMap.get("praised")); return modelsVo; } @@ -1162,12 +1167,6 @@ public class ModelsServiceImpl implements ModelsService { throw new Exception("该模型被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); } - List activeLearnList = activeLearnDao.queryByModelId(JSON.toJSONString(queryMap)); - if (activeLearnList != null && !activeLearnList.isEmpty()) { - String rays = String.join(",", activeLearnList.stream().map(ActiveLearn::getName).collect(Collectors.toSet())); - throw new Exception("该模型被主动学习:" + rays + "使用,不能删除,请先删除主动学习。"); - } - String token = gitService.checkoutToken(); gitService.deleteProject(token, owner, identifier); //删除模型依赖 @@ -1191,6 +1190,15 @@ public class ModelsServiceImpl implements ModelsService { throw new Exception("该模型版本被流水线:" + workflows + "使用,不能删除,请先删除流水线。"); } + HashMap queryMap = new HashMap<>(); + queryMap.put("id", String.valueOf(repoId)); + queryMap.put("version", version); + List rayList = rayDao.queryByModelId(JSON.toJSONString(queryMap)); + if (rayList != null && !rayList.isEmpty()) { + String rays = String.join(",", rayList.stream().map(Ray::getName).collect(Collectors.toSet())); + throw new Exception("该数据集版本被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); + } + String token = gitService.checkoutToken(); String rootPath = Paths.get(localPath + "/" + relativePath).getParent().toString(); gitService.deleteBranch(token, owner, identifier, version, rootPath); @@ -1225,6 +1233,23 @@ public class ModelsServiceImpl implements ModelsService { return result; } + @Override + public String praise(Integer id) throws Exception { + String token = gitService.checkoutToken(); + String url = gitendpoint + "/api/projects/" + id + "/praise_tread/like.json"; + httpUtils.sendPostWithToken(url, null, token, null); + return "点赞成功"; + } + + @Override + public String unpraise(Integer id) throws Exception { + String token = gitService.checkoutToken(); + String url = gitendpoint + "/api/projects/" + id + "/praise_tread/unlike.json"; + httpUtils.sendDeleteWithToken(url, null, token, null); + return "取消点赞成功"; + } + + @Override public List convert(List> lst, String modelTopic, String modelTagName, String modelTypeName) { if (lst != null && lst.size() > 0) { List result = new ArrayList<>(); @@ -1322,11 +1347,11 @@ public class ModelsServiceImpl implements ModelsService { modelDependency1TreeVo.setChildModelList(childModelList); } - Map getUserInfo(String ci4sUsername, String gitLinkUsername, String gitLinkPassword) throws Exception { + Map getUserInfo(String ci4sUsername, String gitLinkPassword) throws Exception { Jedis jedis = new Jedis(redisHost, redisPort); String userReq = jedis.get(ci4sUsername + "_gitUserInfo"); if (userReq == null) { - gitService.login(gitLinkUsername, gitLinkPassword); + gitService.login(ci4sUsername, gitLinkPassword); userReq = jedis.get(ci4sUsername + "_gitUserInfo"); } Map userInfo = JsonUtils.jsonToMap(userReq); diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/NewDatasetServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/NewDatasetServiceImpl.java index 5d1aaf76..5932e912 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/NewDatasetServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/NewDatasetServiceImpl.java @@ -3,9 +3,7 @@ package com.ruoyi.platform.service.impl; import com.alibaba.fastjson2.JSON; import com.ruoyi.common.core.utils.DateUtils; import com.ruoyi.common.security.utils.SecurityUtils; -import com.ruoyi.platform.constant.Constant; import com.ruoyi.platform.domain.*; -import com.ruoyi.platform.mapper.ActiveLearnDao; import com.ruoyi.platform.mapper.AssetWorkflowDao; import com.ruoyi.platform.mapper.AutoMlDao; import com.ruoyi.platform.mapper.RayDao; @@ -14,6 +12,7 @@ import com.ruoyi.platform.service.GitService; import com.ruoyi.platform.service.NewDatasetService; import com.ruoyi.platform.utils.*; import com.ruoyi.platform.vo.*; +import com.ruoyi.system.api.constant.Constant; import com.ruoyi.system.api.model.LoginUser; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; @@ -72,6 +71,8 @@ public class NewDatasetServiceImpl implements NewDatasetService { String endpoint; @Value("${git.endpoint}") String gitendpoint; + @Value("${git.cloneEndpoint}") + String gitCloneEndpoint; @Value("${minio.dataReleaseBucketName}") private String bucketName; @Value("${git.localPath}") @@ -95,8 +96,8 @@ public class NewDatasetServiceImpl implements NewDatasetService { Jedis jedis = new Jedis(redisHost, redisPort); LoginUser loginUser = SecurityUtils.getLoginUser(); String ci4sUsername = loginUser.getUsername(); - String gitLinkUsername = loginUser.getSysUser().getGitLinkUsername(); - String gitLinkPassword = decrypt(loginUser.getSysUser().getGitLinkPassword()); + String gitLinkUsername = loginUser.getSysUser().getUserName(); + String gitLinkPassword = decrypt(loginUser.getSysUser().getOriginPassword()); String userReq = jedis.get(ci4sUsername + "_gitUserInfo"); // 得到用户操作的路径 Map userInfo = JsonUtils.jsonToMap(userReq); @@ -122,7 +123,7 @@ public class NewDatasetServiceImpl implements NewDatasetService { String owner = (String) userInfo.get("login"); gitService.createBranch(token, (String) userInfo.get("login"), repositoryName, branchName, "master"); - // 定义标签 标签1:ci4s-dataset 标签2:DataTag 标签3:DataType + // 定义标签 标签1:dataset 标签2:DataTag 标签3:DataType gitService.createTopic(token, gitlinIid, Constant.Topic_Dataset); if (StringUtils.isNotEmpty(datasetVo.getDataTag())) { gitService.createTopic(token, gitlinIid, "datatag-" + datasetVo.getDataTag()); @@ -132,7 +133,7 @@ public class NewDatasetServiceImpl implements NewDatasetService { } // 得到项目地址 - String projectUrl = gitendpoint + "/" + owner + "/" + repositoryName + ".git"; + String projectUrl = gitCloneEndpoint + "/" + owner + "/" + repositoryName + ".git"; // 得到用户操作的路径 String sourcePath = datasetVo.getDatasetVersionVos().get(0).getUrl(); @@ -149,7 +150,6 @@ public class NewDatasetServiceImpl implements NewDatasetService { // 拼接生产的元数据后写入yaml文件 datasetVo.setCreateBy(String.valueOf(StringUtils.isNotEmpty((String) userInfo.get("nickname")) ? userInfo.get("nickname") : userInfo.get("login"))); datasetVo.setUpdateTime(DateUtils.getTime()); - datasetVo.setVersionDesc(datasetVo.getDescription()); datasetVo.setUsage("
" +
                 "# 克隆数据集配置文件与存储参数到本地\n" +
                 "git clone -b " + branchName + " " + projectUrl + "\n" +
@@ -203,8 +203,8 @@ public class NewDatasetServiceImpl implements NewDatasetService {
         Jedis jedis = new Jedis(redisHost, redisPort);
         LoginUser loginUser = SecurityUtils.getLoginUser();
         String ci4sUsername = loginUser.getUsername();
-        String gitLinkUsername = loginUser.getSysUser().getGitLinkUsername();
-        String gitLinkPassword = decrypt(loginUser.getSysUser().getGitLinkPassword());
+        String gitLinkUsername = loginUser.getSysUser().getUserName();
+        String gitLinkPassword = decrypt(loginUser.getSysUser().getOriginPassword());
         String userReq = jedis.get(ci4sUsername + "_gitUserInfo");
         ci4sUsername = Boolean.TRUE.equals(datasetVo.getIsPublic()) ? Constant.Item_Public : loginUser.getUsername();
         Map userInfo = JsonUtils.jsonToMap(userReq);
@@ -217,7 +217,7 @@ public class NewDatasetServiceImpl implements NewDatasetService {
         String relatePath = ci4sUsername + "/datasets/" + datasetVo.getId() + "/" + repositoryName + "/" + branchName;
         String localPath = localPathlocal + relatePath;
         String datasetPath = localPath + "/dataset";
-        String projectUrl = gitendpoint + "/" + owner + "/" + repositoryName + ".git";
+        String projectUrl = gitCloneEndpoint + "/" + owner + "/" + repositoryName + ".git";
 
         //干掉目标文件夹
         dvcUtils.deleteDirectory(localPath);
@@ -341,11 +341,6 @@ public class NewDatasetServiceImpl implements NewDatasetService {
     @Override
     public Page newPubilcQueryByPage(Dataset dataset, PageRequest pageRequest) throws Exception {
         String token = gitService.checkoutToken();
-        Jedis jedis = new Jedis(redisHost, redisPort);
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        String ci4sUsername = loginUser.getUsername();
-        String userReq = jedis.get(ci4sUsername + "_gitUserInfo");
-        Map userInfo = JsonUtils.jsonToMap(userReq);
         // 拼接查询url
         String url = gitendpoint + "/api/projects.json?sort_direction=updated_on&sort_by=desc&category_id=" + Constant.Git_Category_Id;
 
@@ -384,7 +379,7 @@ public class NewDatasetServiceImpl implements NewDatasetService {
         Map stringObjectMap = YamlUtils.loadYamlFile(localPathlocal + ci4sUsername + "/datasets/" + id + "/" + repo + "/" + version + "/dataset.yaml");
         String jsonString = JacksonUtil.toJSONString(stringObjectMap);
         NewDatasetVo newDatasetVo = JsonUtils.jsonToObject(jsonString, NewDatasetVo.class);
-        List versionVos = new ArrayList();
+        List versionVos = new ArrayList<>();
         if (fileDetailsAfterGitPull != null && fileDetailsAfterGitPull.size() > 0) {
             for (Map fileDetail : fileDetailsAfterGitPull) {
                 VersionVo versionVo = new VersionVo();
@@ -396,6 +391,13 @@ public class NewDatasetServiceImpl implements NewDatasetService {
             }
         }
         newDatasetVo.setDatasetVersionVos(versionVos);
+
+        String token = gitService.checkoutToken();
+        String url = gitendpoint + "/api/" + owner + "/" + repo + "/detail.json";
+        String req = httpUtils.sendGetWithToken(url, null, token);
+        Map reqMap = JacksonUtil.parseJSONStr2Map(req);
+        newDatasetVo.setPraisesCount((Integer) reqMap.get("praises_count"));
+        newDatasetVo.setPraised((Boolean) reqMap.get("praised"));
         return newDatasetVo;
     }
 
@@ -622,7 +624,7 @@ public class NewDatasetServiceImpl implements NewDatasetService {
 
     }
 
-
+    @Override
     public List convert(List> lst, String datasetTopic, String datasetTagName, String datasetTypeName) {
         if (lst != null && lst.size() > 0) {
             List result = new ArrayList<>();
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayInsServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayInsServiceImpl.java
index 42701bc0..9f3ec88d 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayInsServiceImpl.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayInsServiceImpl.java
@@ -1,6 +1,6 @@
 package com.ruoyi.platform.service.impl;
 
-import com.ruoyi.platform.constant.Constant;
+import com.ruoyi.system.api.constant.Constant;
 import com.ruoyi.platform.domain.Ray;
 import com.ruoyi.platform.domain.RayIns;
 import com.ruoyi.platform.mapper.RayDao;
@@ -157,8 +157,8 @@ public class RayInsServiceImpl implements RayInsService {
                     if (innerMap.containsKey("phase")) {
                         String phaseValue = (String) innerMap.get("phase");
                         // 如果值不等于 Succeeded,则赋值为 Failed
-                        if (!StringUtils.equals("Succeeded", phaseValue)) {
-                            innerMap.put("phase", "Failed");
+                        if (!StringUtils.equals(Constant.Succeeded, phaseValue)) {
+                            innerMap.put("phase", Constant.Failed);
                         }
                     }
                 }
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayServiceImpl.java
index 0cbf6ffb..8f4643ed 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayServiceImpl.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayServiceImpl.java
@@ -3,7 +3,7 @@ package com.ruoyi.platform.service.impl;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
 import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.platform.constant.Constant;
+import com.ruoyi.system.api.constant.Constant;
 import com.ruoyi.platform.domain.Ray;
 import com.ruoyi.platform.domain.RayIns;
 import com.ruoyi.platform.mapper.RayDao;
@@ -153,10 +153,10 @@ public class RayServiceImpl implements RayService {
         }
 
         // 记录开始扣积分
-        if (resourceOccupyService.haveResource(ray.getComputingResourceId())) {
+        if (resourceOccupyService.haveResource(ray.getComputingResourceId(), 1)) {
             RayParamVo rayParamVo = new RayParamVo();
             BeanUtils.copyProperties(ray, rayParamVo);
-            rayParamVo.setResource(ray.getComputingResourceId());
+            rayParamVo.setComputingResourceId(ray.getComputingResourceId());
             rayParamVo.setCodeConfig(JsonUtils.jsonToMap(ray.getCodeConfig()));
             rayParamVo.setDataset(JsonUtils.jsonToMap(ray.getDataset()));
             rayParamVo.setModel(JsonUtils.jsonToMap(ray.getModel()));
@@ -206,7 +206,7 @@ public class RayServiceImpl implements RayService {
                 rayInsDao.insert(rayIns);
                 rayInsService.updateRayStatus(id);
                 // 记录开始扣除积分
-                resourceOccupyService.startDeduce(ray.getComputingResourceId(), Constant.TaskType_Ray, id, rayIns.getId(), null, ray.getName(), null);
+                resourceOccupyService.startDeduce(ray.getComputingResourceId(), 1, Constant.TaskType_Ray, id, rayIns.getId(), null, ray.getName(), null, null);
             } catch (Exception e) {
                 throw new RuntimeException(e);
             }
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ResourceOccupyServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ResourceOccupyServiceImpl.java
index bdcf7b58..48373b2a 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ResourceOccupyServiceImpl.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ResourceOccupyServiceImpl.java
@@ -1,7 +1,7 @@
 package com.ruoyi.platform.service.impl;
 
 import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.platform.constant.Constant;
+import com.ruoyi.system.api.constant.Constant;
 import com.ruoyi.platform.domain.ComputingResource;
 import com.ruoyi.platform.domain.ResourceOccupy;
 import com.ruoyi.platform.mapper.ComputingResourceDao;
@@ -29,21 +29,20 @@ public class ResourceOccupyServiceImpl implements ResourceOccupyService {
     private ComputingResourceDao computingResourceDao;
 
     @Override
-    public Boolean haveResource(Integer computingResourceId) throws Exception {
+    public Boolean haveResource(Integer computingResourceId, Integer replicas) throws Exception {
         ComputingResource computingResource = computingResourceDao.queryById(computingResourceId);
 
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (loginUser.getSysUser().getCredit() < computingResource.getCreditPerHour()) {
-            throw new Exception("积分不足");
+        if (resourceOccupyDao.getUserCredit(SecurityUtils.getLoginUser().getUserid()) <= 0) {
+            throw new Exception("当前积分不足");
         }
         if (Constant.Computing_Resource_GPU.equals(computingResource.getComputingResource())) {
-            if (resourceOccupyDao.haveResource(computingResource.getResourceId(), computingResource.getGpuNums())) {
+            if (resourceOccupyDao.haveResource(computingResource.getResourceId(), computingResource.getGpuNums() * replicas)) {
                 return true;
             } else {
                 throw new Exception("资源不足,GPU资源已被占用");
             }
         } else {
-            if (resourceOccupyDao.haveResource(computingResource.getResourceId(), computingResource.getCpuCores())) {
+            if (resourceOccupyDao.haveResource(computingResource.getResourceId(), computingResource.getCpuCores() * replicas)) {
                 return true;
             } else {
                 throw new Exception("资源不足,CPU资源已被占用完");
@@ -53,26 +52,31 @@ public class ResourceOccupyServiceImpl implements ResourceOccupyService {
 
     @Override
     @Transactional
-    public void startDeduce(Integer computingResourceId, String taskType, Long taskId, Long taskInsId, Long workflowId, String taskName, String nodeId) {
+    public void startDeduce(Integer computingResourceId, Integer replicas, String taskType, Long taskId, Long taskInsId, Long workflowId, String taskName, String nodeId, Integer state) {
         ResourceOccupy resourceOccupy = new ResourceOccupy();
         ComputingResource computingResource = computingResourceDao.queryById(computingResourceId);
         resourceOccupy.setComputingResourceId(computingResourceId);
         LoginUser loginUser = SecurityUtils.getLoginUser();
         resourceOccupy.setUserId(loginUser.getUserid());
-        resourceOccupy.setCreditPerHour(computingResource.getCreditPerHour());
-        resourceOccupy.setDescription(computingResource.getDescription());
+        resourceOccupy.setCreditPerHour(computingResource.getCreditPerHour() * replicas);
+        if (replicas > 1) {
+            resourceOccupy.setDescription(replicas + " * [" + computingResource.getDescription() + "]");
+        } else {
+            resourceOccupy.setDescription(computingResource.getDescription());
+        }
         resourceOccupy.setTaskType(taskType);
         resourceOccupy.setTaskId(taskId);
         resourceOccupy.setTaskInsId(taskInsId);
         resourceOccupy.setWorkflowId(workflowId);
         resourceOccupy.setTaskName(taskName);
         resourceOccupy.setNodeId(nodeId);
+        resourceOccupy.setState(state);
         resourceOccupyDao.save(resourceOccupy);
 
         if (Constant.Computing_Resource_GPU.equals(computingResource.getComputingResource())) {
-            resourceOccupyDao.updateUsed(computingResource.getResourceId(), computingResource.getGpuNums());
+            resourceOccupyDao.updateUsed(computingResource.getResourceId(), computingResource.getGpuNums() * replicas);
         } else {
-            resourceOccupyDao.updateUsed(computingResource.getResourceId(), computingResource.getCpuCores());
+            resourceOccupyDao.updateUsed(computingResource.getResourceId(), computingResource.getCpuCores() * replicas);
         }
     }
 
@@ -86,10 +90,11 @@ public class ResourceOccupyServiceImpl implements ResourceOccupyService {
             resourceOccupyDao.edit(resourceOccupy);
 
             ComputingResource computingResource = computingResourceDao.queryById(resourceOccupy.getComputingResourceId());
+            int occupy_num = (int) (resourceOccupy.getCreditPerHour() / computingResource.getCreditPerHour());
             if (Constant.Computing_Resource_GPU.equals(computingResource.getComputingResource())) {
-                resourceOccupyDao.updateUnUsed(computingResource.getResourceId(), computingResource.getGpuNums());
+                resourceOccupyDao.updateUnUsed(computingResource.getResourceId(), computingResource.getGpuNums() * occupy_num);
             } else {
-                resourceOccupyDao.updateUnUsed(computingResource.getResourceId(), computingResource.getCpuCores());
+                resourceOccupyDao.updateUnUsed(computingResource.getResourceId(), computingResource.getCpuCores() * occupy_num);
             }
         }
     }
@@ -112,6 +117,7 @@ public class ResourceOccupyServiceImpl implements ResourceOccupyService {
 
             resourceOccupy.setDeduceCredit(resourceOccupy.getDeduceCredit() + deduceCredit);
             resourceOccupy.setDeduceLastTime(now);
+            resourceOccupy.setState(Constant.State_valid);
             resourceOccupyDao.edit(resourceOccupy);
         }
     }
@@ -131,4 +137,35 @@ public class ResourceOccupyServiceImpl implements ResourceOccupyService {
         result.put("deduceCredit", deduceCredit);
         return result;
     }
+
+    @Override
+    @Transactional
+    public void update(String taskType, Long taskId, Long taskInsId, Integer computingResourceId, Integer replicas) {
+        ResourceOccupy resourceOccupy = resourceOccupyDao.getResourceOccupyByTask(taskType, taskId, taskInsId, null).get(0);
+        ComputingResource oldComputingResource = computingResourceDao.queryById(resourceOccupy.getComputingResourceId());
+        ComputingResource computingResource = computingResourceDao.queryById(computingResourceId);
+
+        int occupy_num = (int) (resourceOccupy.getCreditPerHour() / oldComputingResource.getCreditPerHour());
+
+        if (Constant.Computing_Resource_GPU.equals(oldComputingResource.getComputingResource())) {
+            resourceOccupyDao.updateUnUsed(oldComputingResource.getResourceId(), oldComputingResource.getGpuNums() * occupy_num);
+        } else {
+            resourceOccupyDao.updateUnUsed(oldComputingResource.getResourceId(), computingResource.getCpuCores() * occupy_num);
+        }
+
+        if (Constant.Computing_Resource_GPU.equals(computingResource.getComputingResource())) {
+            resourceOccupyDao.updateUsed(computingResource.getResourceId(), computingResource.getGpuNums() * replicas);
+        } else {
+            resourceOccupyDao.updateUsed(computingResource.getResourceId(), computingResource.getCpuCores() * replicas);
+        }
+
+        if (replicas > 1) {
+            resourceOccupy.setDescription(replicas + " * [" + computingResource.getDescription() + "]");
+        } else {
+            resourceOccupy.setDescription(computingResource.getDescription());
+        }
+        resourceOccupy.setCreditPerHour(computingResource.getCreditPerHour() * replicas);
+        resourceOccupy.setComputingResourceId(computingResourceId);
+        resourceOccupyDao.edit(resourceOccupy);
+    }
 }
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ServiceServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ServiceServiceImpl.java
index 41e1df5d..41b2704c 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ServiceServiceImpl.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ServiceServiceImpl.java
@@ -3,7 +3,6 @@ package com.ruoyi.platform.service.impl;
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
 import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.platform.constant.Constant;
 import com.ruoyi.platform.domain.AssetWorkflow;
 import com.ruoyi.platform.domain.ComputingResource;
 import com.ruoyi.platform.domain.ServiceVersion;
@@ -18,6 +17,7 @@ import com.ruoyi.platform.utils.JacksonUtil;
 import com.ruoyi.platform.vo.serviceVos.ServiceCodeConfigVo;
 import com.ruoyi.platform.vo.serviceVos.ServiceModelVo;
 import com.ruoyi.platform.vo.serviceVos.ServiceVersionVo;
+import com.ruoyi.system.api.constant.Constant;
 import com.ruoyi.system.api.model.LoginUser;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
@@ -28,6 +28,8 @@ import org.springframework.data.domain.PageRequest;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -151,7 +153,8 @@ public class ServiceServiceImpl implements ServiceService {
         ServiceVersion oldServiceVersion = serviceDao.getServiceVersionById(serviceVersionVo.getId());
         if (!oldServiceVersion.getReplicas().equals(serviceVersionVo.getReplicas()) || !oldServiceVersion.getComputingResourceId().equals(serviceVersionVo.getComputingResourceId())
                 || serviceVersionVo.getRerun()) {
-            updateServiceVersion(serviceVersion);
+            updateServiceVersion(serviceVersion, serviceVersionVo.getRerun());
+            serviceVersion.setRunState(Constant.Pending);
         }
         LoginUser loginUser = SecurityUtils.getLoginUser();
         serviceVersion.setUpdateBy(loginUser.getUsername());
@@ -171,6 +174,23 @@ public class ServiceServiceImpl implements ServiceService {
         ServiceVersionVo serviceVersionVo = getServiceVersionVo(serviceVersion);
         com.ruoyi.platform.domain.Service service = serviceDao.getServiceById(serviceVersion.getServiceId());
         serviceVersionVo.setServiceName(service.getServiceName());
+        // 拼接文档地址和gradio地址
+        if (StringUtils.isNotEmpty(serviceVersionVo.getUrl())) {
+            try {
+                URL url = new URL(serviceVersionVo.getUrl());
+                // 获取协议、主机、端口
+                String protocol = url.getProtocol();
+                String host = url.getHost();
+                int port = url.getPort();
+                String baseUrl = (port == -1 || port == url.getDefaultPort())
+                        ? protocol + "://" + host
+                        : protocol + "://" + host + ":" + port;
+                serviceVersionVo.setDocPath(baseUrl + "/redoc");
+                serviceVersionVo.setPagePath(baseUrl + "/gradio");
+            } catch (MalformedURLException e) {
+                throw new RuntimeException(e);
+            }
+        }
         return serviceVersionVo;
     }
 
@@ -238,6 +258,8 @@ public class ServiceServiceImpl implements ServiceService {
         if (StringUtils.isNotEmpty(req)) {
             Map reqMap = JacksonUtil.parseJSONStr2Map(req);
 //            if ((Integer) reqMap.get("code") == 200) {
+            // 结束扣积分
+            resourceOccupyService.endDeduce(Constant.TaskType_Service, null, id, null, null);
             return serviceDao.updateServiceVersion(serviceVersion) > 0 ? "删除成功" : "删除失败";
 //            }
         }
@@ -251,7 +273,7 @@ public class ServiceServiceImpl implements ServiceService {
         HashMap paramMap = new HashMap<>();
         paramMap.put("service_name", service.getServiceName());
         paramMap.put("description", serviceVersion.getDescription());
-        paramMap.put("resource", serviceVersion.getComputingResourceId());
+        paramMap.put("computing_resource_id", serviceVersion.getComputingResourceId());
         paramMap.put("mount_path", serviceVersion.getMountPath());
         paramMap.put("replicas", serviceVersion.getReplicas());
         paramMap.put("env", JSONObject.parseObject(serviceVersion.getEnvVariables()));
@@ -262,7 +284,7 @@ public class ServiceServiceImpl implements ServiceService {
         paramMap.put("deploy_type", serviceVersion.getDeployType());
 
         // 判断是否有资源
-        if (resourceOccupyService.haveResource(serviceVersion.getComputingResourceId())) {
+        if (resourceOccupyService.haveResource(serviceVersion.getComputingResourceId(), serviceVersion.getReplicas())) {
             String req = HttpUtils.sendPost(argoUrl + modelService + "/create", JSON.toJSONString(paramMap));
             if (StringUtils.isNotEmpty(req)) {
                 Map reqMap = JacksonUtil.parseJSONStr2Map(req);
@@ -275,7 +297,7 @@ public class ServiceServiceImpl implements ServiceService {
                     serviceDao.updateServiceVersion(serviceVersion);
 
                     // 记录开始扣积分
-                    resourceOccupyService.startDeduce(serviceVersion.getComputingResourceId(), Constant.TaskType_Service, serviceVersion.getServiceId(), serviceVersion.getId(), null, service.getServiceName(), null);
+                    resourceOccupyService.startDeduce(serviceVersion.getComputingResourceId(), serviceVersion.getReplicas(), Constant.TaskType_Service, serviceVersion.getServiceId(), serviceVersion.getId(), null, service.getServiceName(), null, Constant.State_building);
                     return "启动成功";
                 } else {
                     throw new RuntimeException("启动失败");
@@ -305,20 +327,25 @@ public class ServiceServiceImpl implements ServiceService {
     }
 
     @Override
-    public String updateServiceVersion(ServiceVersion serviceVersion) throws Exception {
+    public String updateServiceVersion(ServiceVersion serviceVersion, Boolean reRun) throws Exception {
         // 判断是否有资源
-        if (resourceOccupyService.haveResource(serviceVersion.getComputingResourceId())) {
+        if (resourceOccupyService.haveResource(serviceVersion.getComputingResourceId(), serviceVersion.getReplicas())) {
             HashMap paramMap = new HashMap<>();
             paramMap.put("deployment_name", serviceVersion.getDeploymentName());
             HashMap updateMap = new HashMap<>();
             updateMap.put("replicas", serviceVersion.getReplicas());
-            updateMap.put("resource", serviceVersion.getResource());
+            updateMap.put("computing_resource_id", serviceVersion.getComputingResourceId());
             paramMap.put("update_model", new JSONObject(updateMap));
             String req = HttpUtils.sendPost(argoUrl + modelService + "/update", JSON.toJSONString(paramMap));
             if (StringUtils.isNotEmpty(req)) {
                 com.ruoyi.platform.domain.Service service = serviceDao.getServiceById(serviceVersion.getServiceId());
+                ServiceVersion serviceVersionById = serviceDao.getServiceVersionById(serviceVersion.getId());
                 // 记录开始扣积分
-                resourceOccupyService.startDeduce(serviceVersion.getComputingResourceId(), Constant.TaskType_Service, serviceVersion.getServiceId(), serviceVersion.getId(), null, service.getServiceName(), null);
+                if (reRun) {
+                    resourceOccupyService.startDeduce(serviceVersion.getComputingResourceId(), serviceVersion.getReplicas(), Constant.TaskType_Service, serviceVersion.getServiceId(), serviceVersion.getId(), null, service.getServiceName(), null, Constant.State_building);
+                } else if (Constant.Running.equals(serviceVersionById.getRunState()) || Constant.Pending.equals(serviceVersionById.getRunState())) {
+                    resourceOccupyService.update(Constant.TaskType_Service, serviceVersion.getServiceId(), serviceVersion.getId(), serviceVersion.getComputingResourceId(), serviceVersion.getReplicas());
+                }
                 return "修改成功";
             } else {
                 throw new RuntimeException("更新失败");
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkflowServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkflowServiceImpl.java
index 06e9646b..2535c1e0 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkflowServiceImpl.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkflowServiceImpl.java
@@ -2,7 +2,6 @@ package com.ruoyi.platform.service.impl;
 
 import com.ruoyi.common.security.utils.SecurityUtils;
 import com.ruoyi.platform.annotations.CheckDuplicate;
-import com.ruoyi.platform.constant.Constant;
 import com.ruoyi.platform.domain.AssetWorkflow;
 import com.ruoyi.platform.domain.Experiment;
 import com.ruoyi.platform.domain.ImageVersion;
@@ -15,6 +14,7 @@ import com.ruoyi.platform.service.WorkflowService;
 import com.ruoyi.platform.utils.HttpUtils;
 import com.ruoyi.platform.utils.JsonUtils;
 import com.ruoyi.platform.utils.MinioUtil;
+import com.ruoyi.system.api.constant.Constant;
 import com.ruoyi.system.api.model.LoginUser;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Value;
@@ -126,6 +126,13 @@ public class WorkflowServiceImpl implements WorkflowService {
         this.workflowDao.update(workflow);
         assetWorkflowDao.deleteByWorkFlowId(workflow.getId());
         saveAssetWorkFlow(workflow);
+        if (StringUtils.isNotEmpty(workflow.getGlobalParam())) {
+            List experimentList = experimentService.queryByWorkflowId(workflow.getId());
+            for (Experiment experiment : experimentList) {
+                experiment.setGlobalParam(workflow.getGlobalParam());
+                experimentService.update(experiment);
+            }
+        }
         return this.queryById(workflow.getId());
     }
 
@@ -173,6 +180,10 @@ public class WorkflowServiceImpl implements WorkflowService {
         Workflow workflow = this.queryById(id);
         if (workflow != null) {
             try {
+                if (workflow.getName().length() >= 64) {
+                    throw new RuntimeException("流水线名称大于最大长度");
+                }
+
                 Workflow duplicateWorkflow = new Workflow();
                 duplicateWorkflow.setName(workflow.getName() + "-copy-" + UUID.randomUUID().toString().substring(0, 6));
                 String oldDag = workflow.getDag();
@@ -198,7 +209,6 @@ public class WorkflowServiceImpl implements WorkflowService {
                 return this.insert(duplicateWorkflow);
             } catch (Exception e) {
                 throw new RuntimeException("复制流水线失败: " + e.getMessage(), e);
-
             }
         }
         return null;
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkspaceServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkspaceServiceImpl.java
index d0f82ccf..1bd00d36 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkspaceServiceImpl.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkspaceServiceImpl.java
@@ -1,14 +1,19 @@
 package com.ruoyi.platform.service.impl;
 
+import com.ruoyi.common.security.utils.SecurityUtils;
 import com.ruoyi.platform.domain.*;
 import com.ruoyi.platform.mapper.*;
-import com.ruoyi.platform.service.ExperimentInsService;
-import com.ruoyi.platform.service.ModelsService;
-import com.ruoyi.platform.service.WorkflowService;
-import com.ruoyi.platform.service.WorkspaceService;
-import lombok.val;
-import org.checkerframework.checker.units.qual.C;
+import com.ruoyi.platform.service.*;
+import com.ruoyi.platform.utils.JacksonUtil;
+import com.ruoyi.platform.utils.JsonUtils;
+import com.ruoyi.platform.utils.NewHttpUtils;
+import com.ruoyi.platform.vo.ModelsVo;
+import com.ruoyi.platform.vo.NewDatasetVo;
+import com.ruoyi.system.api.constant.Constant;
+import com.ruoyi.system.api.model.LoginUser;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
+import redis.clients.jedis.Jedis;
 
 import javax.annotation.Resource;
 import java.util.HashMap;
@@ -18,36 +23,33 @@ import java.util.Map;
 @Service("WorkspaceService")
 public class WorkspaceServiceImpl implements WorkspaceService {
 
-
-    @Resource
-    private WorkflowService workflowService;
     @Resource
     private WorkflowDao workflowDao;
     @Resource
     private ExperimentDao experimentDao;
-
     @Resource
     private ExperimentInsDao experimentInsDao;
-
     @Resource
     private ExperimentInsService experimentInsService;
-
     @Resource
-    private ModelsService modelsService;
+    private ImageDao imageDao;
     @Resource
-    private ModelsDao modelsDao;
-
+    private ComponentDao componentDao;
     @Resource
-    private DatasetDao datasetDao;
-
+    private GitService gitService;
     @Resource
-    private ImageDao imageDao;
-
+    private NewDatasetService newDatasetService;
     @Resource
-    private ComponentDao componentDao;
-
-
+    private ModelsService modelsService;
+    @Resource
+    private NewHttpUtils httpUtils;
 
+    @Value("${git.endpoint}")
+    String gitendpoint;
+    @Value("${spring.redis.host}")
+    private String redisHost;
+    @Value("${spring.redis.port}")
+    private Integer redisPort;
 
     @Override
     public Map getOverview() {
@@ -59,16 +61,16 @@ public class WorkspaceServiceImpl implements WorkspaceService {
 
         // 获取运行中实验实例数量
         List experimentInsList = experimentInsService.queryByExperimentIsNotTerminated();
-        if (experimentInsList!=null && !experimentInsList.isEmpty()) {
+        if (experimentInsList != null && !experimentInsList.isEmpty()) {
             Integer experimentInsCount = experimentInsList.size();
             resMap.put("runningExperimentInsCount", experimentInsCount);
-        }else{
+        } else {
             resMap.put("runningExperimentInsCount", 0);
         }
         //得到最近的三条实例记录,放进返回map
         List latestExperimentInsList = experimentInsDao.getLatestInsList();
         if (latestExperimentInsList != null && !latestExperimentInsList.isEmpty()) {
-            for (ExperimentIns experimentIns : latestExperimentInsList){
+            for (ExperimentIns experimentIns : latestExperimentInsList) {
                 Integer experimentId = experimentIns.getExperimentId();
                 Experiment experiment = this.experimentDao.queryById(experimentId);
                 //拿到对应的流水线id
@@ -83,22 +85,43 @@ public class WorkspaceServiceImpl implements WorkspaceService {
     }
 
     @Override
-    public Map getAssetCount(Boolean isPublic) {
-        Map assetCountMap = new HashMap();
-        int availableRange = isPublic ? 1 : 0;
-        //统计数据集数量
-        Dataset dataset = new Dataset();
-        dataset.setAvailableRange(availableRange);
-        Integer datasetCount = (int) this.datasetDao.count(dataset);
-        assetCountMap.put("dataset", datasetCount);
-        //统计模型数量
-        Models models = new Models();
-        models.setAvailableRange(availableRange);
-        Integer modelCount = (int) this.modelsDao.count(models);
-        assetCountMap.put("model", modelCount);
-        //统计镜像数量
+    public Map getAssetCount(Boolean isPublic) throws Exception {
+        Map assetCountMap = new HashMap<>();
+        String token = gitService.checkoutToken();
+        int availableRange = isPublic ? Constant.Image_Type_Pub : Constant.Image_Type_Pri;
+        String datasetUrl;
+        String modelUrl;
+        if (isPublic) {
+            // 数据集
+            datasetUrl = gitendpoint + "/api/projects.json?sort_direction=updated_on&sort_by=desc&category_id=" + Constant.Git_Category_Id;
+            // 模型
+            modelUrl = gitendpoint + "/api/projects.json?sort_direction=updated_on&sort_by=desc&category_id=" + Constant.Git_Category_Id;
+        } else {
+            Jedis jedis = new Jedis(redisHost, redisPort);
+            LoginUser loginUser = SecurityUtils.getLoginUser();
+            String ci4sUsername = loginUser.getUsername();
+            String userReq = jedis.get(ci4sUsername + "_gitUserInfo");
+            Map userInfo = JsonUtils.jsonToMap(userReq);
+
+            datasetUrl = gitendpoint + "/api/users/" + userInfo.get("login") + "/projects.json?category=manage";
+            modelUrl = gitendpoint + "/api/users/" + userInfo.get("login") + "/projects.json?category=manage";
+        }
+
+        String req = httpUtils.sendGetWithToken(datasetUrl, null, token);
+        Map stringObjectMap = JacksonUtil.parseJSONStr2Map(req);
+        List> projects = (List>) stringObjectMap.get("projects");
+        List collect1 = newDatasetService.convert(projects, Constant.Topic_Dataset, null, null);
+        assetCountMap.put("dataset", collect1.size());
+
+        req = httpUtils.sendGetWithToken(modelUrl, null, token);
+        stringObjectMap = JacksonUtil.parseJSONStr2Map(req);
+        projects = (List>) stringObjectMap.get("projects");
+        List collect2 = modelsService.convert(projects, Constant.Topic_model, null, null);
+        assetCountMap.put("model", collect2.size());
+
+        // 镜像
         Image image = new Image();
-        image.setImageType(availableRange);
+        image.setImageType(Constant.Image_Type_Pub);
         Integer imageCount = (int) this.imageDao.count(image);
         assetCountMap.put("image", imageCount);
         //统计组件数量
@@ -113,6 +136,4 @@ public class WorkspaceServiceImpl implements WorkspaceService {
 
         return assetCountMap;
     }
-
-
 }
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/DVCUtils.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/DVCUtils.java
index 7ecbdc51..5be79efa 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/DVCUtils.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/DVCUtils.java
@@ -91,7 +91,7 @@ public class DVCUtils {
         }
     }
 
-    private void deletePath(Path path) {
+    public void deletePath(Path path) {
         try {
             Files.deleteIfExists(path);
         } catch (IOException e) {
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java
index c4608fd6..13fab8fd 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java
@@ -1,6 +1,6 @@
 package com.ruoyi.platform.utils;
 
-import com.ruoyi.platform.constant.Constant;
+import com.ruoyi.system.api.constant.Constant;
 import com.ruoyi.platform.domain.ComputingResource;
 import com.ruoyi.platform.domain.DevEnvironment;
 import com.ruoyi.platform.mapper.ComputingResourceDao;
@@ -41,6 +41,9 @@ public class K8sClientUtil {
     @Value("${dockerpush.proxyUrl}")
     private String proxyUrl;
 
+    @Value("${git.localPath}")
+    String localPathlocal;
+
     private String http;
     private String token;
     /**
@@ -512,17 +515,17 @@ public class K8sClientUtil {
 
         try {
             // 记录开始扣积分
-            if (resourceOccupyService.haveResource(devEnvironment.getComputingResourceId())) {
+            if (resourceOccupyService.haveResource(devEnvironment.getComputingResourceId(), 1)) {
                 pod = api.createNamespacedPod(namespace, pod, null, null, null);
                 String nodeName = getNodeName(podName, namespace);
 
                 // 记录开始扣除积分
-                resourceOccupyService.startDeduce(devEnvironment.getComputingResourceId(), Constant.TaskType_Dev, Long.valueOf(devEnvironment.getId()), null, null, devEnvironment.getName(), null);
+                resourceOccupyService.startDeduce(devEnvironment.getComputingResourceId(), 1, Constant.TaskType_Dev, Long.valueOf(devEnvironment.getId()), null, null, devEnvironment.getName(), null, null);
             }
         } catch (ApiException e) {
             throw new RuntimeException("创建pod异常:" + e.getResponseBody());
         } catch (Exception e) {
-            throw new RuntimeException("创建pod系统异常:", e);
+            throw new RuntimeException("创建pod系统异常:" + e.getMessage());
         }
 
         V1Service service = createService(namespace, podName + "-svc", port, selector);
@@ -638,7 +641,7 @@ public class K8sClientUtil {
     }
 
 
-    public V1Pod createPodWithEnv(String podName, String namespace, String proxyUrl, String mountPath, String pvcName, String image) {
+    public V1Pod createPodWithEnv(String podName, String namespace, String proxyUrl, String mountPath, String image) {
         CoreV1Api api = new CoreV1Api(apiClient);
 
         V1SecurityContext v1SecurityContext = new V1SecurityContext();
@@ -649,7 +652,7 @@ public class K8sClientUtil {
         volumeMounts.add(new V1VolumeMount().name("workspace").mountPath(mountPath));
 
         List volumes = new ArrayList<>();
-        volumes.add(new V1Volume().name("workspace").hostPath(new V1HostPathVolumeSource().path(hostPath + "/" + podName + "/" + mountPath).type("DirectoryOrCreate")));
+        volumes.add(new V1Volume().name("workspace").hostPath(new V1HostPathVolumeSource().path(hostPath + "/images").type("DirectoryOrCreate")));
 
         V1Pod pod = new V1PodBuilder()
                 .withNewMetadata()
@@ -704,7 +707,7 @@ public class K8sClientUtil {
         }
         limitMap.put("cpu", new Quantity(String.valueOf(computingResource.getCpuCores())));
         limitMap.put("memory", new Quantity(memory));
-        limitMap.put("ephemeral-storage", new Quantity("100Gi"));
+        limitMap.put("ephemeral-storage", new Quantity("20Gi"));
 
         V1ResourceRequirements v1ResourceRequirements = new V1ResourceRequirements();
         v1ResourceRequirements.setRequests(limitMap);
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/NewHttpUtils.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/NewHttpUtils.java
index da117614..dc88ad0e 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/NewHttpUtils.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/NewHttpUtils.java
@@ -1,4 +1,5 @@
 package com.ruoyi.platform.utils;
+
 import org.apache.http.HttpHost;
 import org.apache.http.client.methods.*;
 import org.apache.http.client.utils.URIBuilder;
@@ -20,6 +21,7 @@ import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
+import java.util.Map;
 
 @Component
 public class NewHttpUtils {
@@ -61,27 +63,31 @@ public class NewHttpUtils {
         }
     }
 
-    public static String sendGet(String url, String param) {
+    public static String sendGet(String url, String param) throws Exception {
         return sendRequest(new HttpGet(), url, param, null, null);
     }
 
-    public static String sendPost(String url, String param, String body) {
+    public static String sendPost(String url, String param, String body) throws Exception {
         return sendRequest(new HttpPost(), url, param, null, body);
     }
 
-    public static String sendGetWithToken(String url, String param, String token) {
+    public static String sendGetWithToken(String url, String param, String token) throws Exception {
         return sendRequest(new HttpGet(), url, param, token, null);
     }
 
-    public static String sendPostWithToken(String url, String param, String token, String body) {
+    public static String sendPostWithToken(String url, String param, String token, String body) throws Exception {
         return sendRequest(new HttpPost(), url, param, token, body);
     }
 
-    public static String sendDeleteWithToken(String url, String param, String token) {
-        return sendRequest(new HttpDelete(), url, param, token, null);
+    public static String sendDeleteWithToken(String url, String param, String token, String body) throws Exception {
+        return sendRequest(new HttpDelete(), url, param, token, body);
+    }
+
+    public static String sendPatchWithToken(String url, String param, String token, String body) throws Exception {
+        return sendRequest(new HttpPatch(), url, param, token, body);
     }
 
-    private static String sendRequest(HttpRequestBase request, String url, String param, String token, String body) {
+    private static String sendRequest(HttpRequestBase request, String url, String param, String token, String body) throws Exception {
         if (httpClient == null) {
             throw new IllegalStateException("HttpClient is not initialized");
         }
@@ -121,11 +127,20 @@ public class NewHttpUtils {
                     throw new IOException("HTTP request failed with response code: " + statusCode);
                 }
                 log.info("Response: " + result);
+                if (result.startsWith("{")) {
+                    Map resultMap = JsonUtils.jsonToMap(result);
+                    Integer status = (Integer) resultMap.get("status");
+                    if (status != null && status != 0 && status != 1) {
+                        throw new Exception((String) resultMap.get("message"));
+                    }
+                }
             }
         } catch (URISyntaxException e) {
             log.error("URISyntaxException, url=" + url + ", param=" + param, e);
+            throw e;
         } catch (IOException e) {
             log.error("IOException, url=" + url + ", param=" + param, e);
+            throw e;
         }
         return result;
     }
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ImageVo.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ImageVo.java
index 8345f214..b6eea537 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ImageVo.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ImageVo.java
@@ -3,10 +3,12 @@ package com.ruoyi.platform.vo;
 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
 import com.fasterxml.jackson.databind.annotation.JsonNaming;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 
 import java.io.Serializable;
 
 @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
+@Data
 public class ImageVo implements Serializable {
 
 
@@ -51,6 +53,10 @@ public class ImageVo implements Serializable {
      */
     @ApiModelProperty(name = "file_size")
     private String fileSize;
+
+    @ApiModelProperty(name = "file_name")
+    private String fileName;
+
     /**
      * 镜像构建状态
      */
@@ -66,101 +72,4 @@ public class ImageVo implements Serializable {
 
     @ApiModelProperty(name = "dev_environment_id", value = "环境id")
     private Integer devEnvironmentId;
-
-//    public Integer getId() {
-//        return id;
-//    }
-//
-//    public void setId(Integer id) {
-//        this.id = id;
-//    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    public Integer getImageType() {
-        return imageType;
-    }
-
-    public void setImageType(Integer imageType) {
-        this.imageType = imageType;
-    }
-
-    public String getVersion() {
-        return version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-//    public String getUrl() {
-//        return url;
-//    }
-//
-//    public void setUrl(String url) {
-//        this.url = url;
-//    }
-
-    public String getTagName() {
-        return tagName;
-    }
-
-    public void setTagName(String tagName) {
-        this.tagName = tagName;
-    }
-
-    public String getFileSize() {
-        return fileSize;
-    }
-
-    public void setFileSize(String fileSize) {
-        this.fileSize = fileSize;
-    }
-
-    public String getStatus() {
-        return status;
-    }
-
-    public void setStatus(String status) {
-        this.status = status;
-    }
-
-    public Integer getUploadType() {
-        return uploadType;
-    }
-
-    public void setUploadType(Integer uploadType) {
-        this.uploadType = uploadType;
-    }
-
-    public String getPath() {
-        return path;
-    }
-
-    public void setPath(String path) {
-        this.path = path;
-    }
-
-    public Integer getDevEnvironmentId() {
-        return devEnvironmentId;
-    }
-
-    public void setDevEnvironmentId(Integer devEnvironmentId) {
-        this.devEnvironmentId = devEnvironmentId;
-    }
-
 }
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelsVo.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelsVo.java
index 9859bf77..50d26219 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelsVo.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelsVo.java
@@ -15,6 +15,12 @@ public class ModelsVo extends ModelMetaVo implements Serializable {
     @ApiModelProperty(name = "status", value = "状态")
     private Integer status;
 
+    @ApiModelProperty(name = "praises_count",value = "点赞数量")
+    private Integer praisesCount;
+
+    @ApiModelProperty(name = "praises_count",value = "是否点赞")
+    private Boolean praised;
+
     @ApiModelProperty(name = "model_version_vos")
     private List modelVersionVos;
 
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/NewDatasetVo.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/NewDatasetVo.java
index 1f84900f..082df2a4 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/NewDatasetVo.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/NewDatasetVo.java
@@ -50,6 +50,13 @@ public class NewDatasetVo implements Serializable {
     private Integer id;
     @ApiModelProperty(name = "visits",value = "访问次数")
     private Integer visits;
+
+    @ApiModelProperty(name = "praises_count",value = "点赞数量")
+    private Integer praisesCount;
+
+    @ApiModelProperty(name = "praised",value = "是否点赞")
+    private Boolean praised;
+
     @ApiModelProperty(name = "create_by",value = "创建者")
     private String createBy;
     @ApiModelProperty(name = "version_desc",value = "版本描述")
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/RayParamVo.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/RayParamVo.java
index 67e768b4..72963fba 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/RayParamVo.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/RayParamVo.java
@@ -44,5 +44,5 @@ public class RayParamVo {
 
     private Integer minSamplesRequired;
 
-    private Integer resource;
+    private Integer computingResourceId;
 }
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/serviceVos/ServiceVersionVo.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/serviceVos/ServiceVersionVo.java
index d1cb79cd..b42797ad 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/serviceVos/ServiceVersionVo.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/serviceVos/ServiceVersionVo.java
@@ -61,4 +61,8 @@ public class ServiceVersionVo {
     private Boolean rerun;
 
     private String deployType;
+
+    private String docPath;
+
+    private String pagePath;
 }
diff --git a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/CodeConfigDaoMapper.xml b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/CodeConfigDaoMapper.xml
index 8dce9ccf..9ae12b5b 100644
--- a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/CodeConfigDaoMapper.xml
+++ b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/CodeConfigDaoMapper.xml
@@ -57,6 +57,7 @@
     
 
diff --git a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ImageDaoMapper.xml b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ImageDaoMapper.xml
index ead149e7..e23fa964 100644
--- a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ImageDaoMapper.xml
+++ b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ImageDaoMapper.xml
@@ -67,6 +67,7 @@
                 and img.state = #{image.state}
             
         
+        order by img.create_time desc
         limit #{pageable.offset}, #{pageable.pageSize}
     
 
diff --git a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ImageVersionDaoMapper.xml b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ImageVersionDaoMapper.xml
index 46b16587..df174d68 100644
--- a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ImageVersionDaoMapper.xml
+++ b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ImageVersionDaoMapper.xml
@@ -75,6 +75,7 @@
                 and state = #{imageVersion.state}
             
         
+        order by create_time desc
         limit #{pageable.offset}, #{pageable.pageSize}
     
 
@@ -117,9 +118,6 @@
             
                 and update_time = #{imageVersion.updateTime}
             
-            
-                and state = #{imageVersion.state}
-            
         
     
 
@@ -129,8 +127,12 @@
 
     
     
-        insert into image_version(image_id, version, url, tag_name, file_size, status, create_by, create_time, update_by, update_time, state)
-        values (#{imageVersion.imageId}, #{imageVersion.version}, #{imageVersion.url}, #{imageVersion.tagName}, #{imageVersion.fileSize}, #{imageVersion.status}, #{imageVersion.createBy}, #{imageVersion.createTime}, #{imageVersion.updateBy}, #{imageVersion.updateTime}, #{imageVersion.state})
+        insert into image_version(image_id, version, description, url, tag_name, file_size, status, create_by,
+                                  create_time, update_by, update_time, state, host_ip)
+        values (#{imageVersion.imageId}, #{imageVersion.version}, #{imageVersion.description}, #{imageVersion.url},
+                #{imageVersion.tagName}, #{imageVersion.fileSize}, #{imageVersion.status}, #{imageVersion.createBy},
+                #{imageVersion.createTime}, #{imageVersion.updateBy}, #{imageVersion.updateTime}, #{imageVersion.state},
+                #{imageVersion.hostIp})
     
 
 
diff --git a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ResourceOccupy.xml b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ResourceOccupy.xml
index 7f7544b0..22e662a4 100644
--- a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ResourceOccupy.xml
+++ b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ResourceOccupy.xml
@@ -3,12 +3,18 @@
 
     
         insert into resource_occupy (user_id, computing_resource_id, credit_per_hour, description, task_type, task_id,
-                                     task_ins_id, workflow_id, task_name,
-                                     node_id)
+        task_ins_id, workflow_id, task_name,
+        
+            state,
+        
+        node_id)
         values (#{resourceOccupy.userId}, #{resourceOccupy.computingResourceId}, #{resourceOccupy.creditPerHour},
-                #{resourceOccupy.description}, #{resourceOccupy.taskType}, #{resourceOccupy.taskId},
-                #{resourceOccupy.taskInsId}, #{resourceOccupy.workflowId}, #{resourceOccupy.taskName},
-                #{resourceOccupy.nodeId})
+        #{resourceOccupy.description}, #{resourceOccupy.taskType}, #{resourceOccupy.taskId},
+        #{resourceOccupy.taskInsId}, #{resourceOccupy.workflowId}, #{resourceOccupy.taskName},
+        
+            #{resourceOccupy.state},
+        
+        #{resourceOccupy.nodeId})
     
 
     
@@ -23,6 +29,15 @@
             
                 deduce_credit = #{resourceOccupy.deduceCredit},
             
+            
+                computing_resource_id = #{resourceOccupy.computingResourceId},
+            
+            
+                credit_per_hour = #{resourceOccupy.creditPerHour},
+            
+            
+                description = #{resourceOccupy.description},
+            
         
         where id = #{resourceOccupy.id}
     
@@ -64,7 +79,7 @@
         
             and node_id = #{nodeId}
         
-        and state = 1
+        and state in (1, 2)
     
 
     
         select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status,
-        u.git_link_username, TRUNCATE(u.credit, 1) as credit,
+        u.origin_password , ROUND(u.credit, 1) as credit,
         u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader
         from sys_user u
         left join sys_dept d on u.dept_id = d.dept_id
@@ -125,7 +123,7 @@
     
 
     
 
     
 
-    
+        select origin_password from sys_user where user_id = #{userId}
     
 
     
@@ -209,11 +204,10 @@
         phonenumber,
         sex,
         password,
+        origin_password,
         status,
         create_by,
         remark,
-        git_link_username,
-        git_link_password,
         credit,
         create_time
         )values(
@@ -226,11 +220,10 @@
         #{phonenumber},
         #{sex},
         #{password},
+        #{originPassword},
         #{status},
         #{createBy},
         #{remark},
-        #{gitLinkUsername},
-        #{gitLinkPassword},
         #{credit},
         sysdate()
         )
@@ -247,13 +240,12 @@
             sex = #{sex},
             avatar = #{avatar},
             password = #{password},
+            origin_password = #{originPassword},
             status = #{status},
             login_ip = #{loginIp},
             login_date = #{loginDate},
             update_by = #{updateBy},
             remark = #{remark},
-            git_link_username = #{gitLinkUsername},
-            git_link_password = #{gitLinkPassword},
             credit = #{credit},
             update_time = sysdate()