Browse Source

Merge branch 'dev' of https://gitlink.org.cn/ci4s/ci4sManagement-cloud into dev

dev-active_learn
somunslotus 10 months ago
parent
commit
f4ad288e1d
49 changed files with 751 additions and 233 deletions
  1. +2
    -0
      .gitignore
  2. +1
    -1
      react-ui/.storybook/main.ts
  3. +1
    -133
      react-ui/README.md
  4. +12
    -1
      react-ui/config/routes.ts
  5. +5
    -3
      react-ui/package.json
  6. BIN
      react-ui/public/fonts/DingTalk-JinBuTi.ttf
  7. BIN
      react-ui/public/fonts/DingTalk-JinBuTi.woff
  8. BIN
      react-ui/public/fonts/DingTalk-JinBuTi.woff2
  9. BIN
      react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.otf
  10. BIN
      react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.ttf
  11. BIN
      react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff
  12. BIN
      react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff2
  13. +22
    -4
      react-ui/public/fonts/font.css
  14. BIN
      react-ui/src/assets/img/user-points-bg.png
  15. BIN
      react-ui/src/assets/img/workspace-experiment.png
  16. BIN
      react-ui/src/assets/img/workspace-pipeline.png
  17. +1
    -1
      react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx
  18. +1
    -1
      react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx
  19. +2
    -2
      react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx
  20. +1
    -1
      react-ui/src/pages/ModelDeployment/components/VersionBasicInfo/index.tsx
  21. +1
    -1
      react-ui/src/pages/ModelDeployment/types.ts
  22. +31
    -0
      react-ui/src/pages/Points/components/Statistics/index.less
  23. +38
    -0
      react-ui/src/pages/Points/components/Statistics/index.tsx
  24. +19
    -0
      react-ui/src/pages/Points/index.less
  25. +256
    -0
      react-ui/src/pages/Points/index.tsx
  26. +15
    -6
      react-ui/src/pages/System/User/edit.tsx
  27. +5
    -0
      react-ui/src/pages/System/User/index.tsx
  28. +1
    -0
      react-ui/src/pages/Workspace/components/ExperimentChart/index.less
  29. +5
    -5
      react-ui/src/pages/Workspace/components/ExperimentTable/index.less
  30. +4
    -16
      react-ui/src/pages/Workspace/components/TotalStatistics/index.less
  31. +3
    -3
      react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx
  32. +36
    -0
      react-ui/src/pages/Workspace/components/UserPoints/index.less
  33. +40
    -0
      react-ui/src/pages/Workspace/components/UserPoints/index.tsx
  34. +11
    -2
      react-ui/src/pages/Workspace/index.less
  35. +34
    -20
      react-ui/src/pages/Workspace/index.tsx
  36. +22
    -0
      react-ui/src/services/points/index.ts
  37. +5
    -0
      react-ui/src/stories/docs/Utils.mdx
  38. +8
    -0
      react-ui/src/styles/theme.less
  39. +1
    -0
      react-ui/src/types/system/user.d.ts
  40. +86
    -12
      react-ui/src/utils/index.ts
  41. +23
    -0
      react-ui/src/utils/statusTableCell.tsx
  42. +1
    -1
      react-ui/src/utils/table.tsx
  43. +11
    -0
      react-ui/typedoc.json
  44. +1
    -0
      react-ui/types/tsconfig.tsbuildinfo
  45. +12
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ResourceOccupyTask.java
  46. +4
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ServiceService.java
  47. +4
    -7
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/JupyterServiceImpl.java
  48. +4
    -2
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ServiceServiceImpl.java
  49. +22
    -10
      ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ServiceDaoMapper.xml

+ 2
- 0
.gitignore View File

@@ -60,3 +60,5 @@ mvnw
**/node_modules

*storybook.log

/react-ui/docs

+ 1
- 1
react-ui/.storybook/main.ts View File

@@ -16,7 +16,7 @@ const config: StorybookConfig = {
name: '@storybook/react-webpack5',
options: {},
},
staticDirs: ['../public'],
staticDirs: ['../public', { from: '../docs', to: '/docs' }],
docs: {
defaultName: 'Documentation',
},


+ 1
- 133
react-ui/README.md View File

@@ -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)

<h1 align="center">Ant Design Pro</h1>

<div align="center">

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)

</div>

- 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.

| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>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

+ 12
- 1
react-ui/config/routes.ts View File

@@ -345,7 +345,6 @@ export default [
},
],
},

{
name: '应用开发',
path: '/appsDeployment',
@@ -498,6 +497,18 @@ export default [
},
],
},
{
name: '算力积分',
path: '/points',
routes: [
{
name: '算力积分',
path: '',
key: 'points',
component: './Points/index',
},
],
},
{
path: '*',
layout: false,


+ 5
- 3
react-ui/package.json View File

@@ -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 --entryPointStrategy expand --entryPoints 'src/utils' --skipErrorChecking --out docs",
"gh-pages": "gh-pages -d dist",
"i18n-remove": "pro i18n-remove --locale=zh-CN --write",
"postinstall": "max setup",
@@ -132,6 +133,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"
},


BIN
react-ui/public/fonts/DingTalk-JinBuTi.ttf View File


BIN
react-ui/public/fonts/DingTalk-JinBuTi.woff View File


BIN
react-ui/public/fonts/DingTalk-JinBuTi.woff2 View File


BIN
react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.otf View File


BIN
react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.ttf View File


BIN
react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff View File


BIN
react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff2 View File


+ 22
- 4
react-ui/public/fonts/font.css View File

@@ -1,5 +1,23 @@
@font-face {
font-family: Alibaba;
src: url('./ALIBABA-PUHUITI-MEDIUM.TTF');
font-display: swap;
}
font-family: Alibaba;
src: url('./ALIBABA-PUHUITI-MEDIUM.TTF');
font-display: swap;
}

@font-face {
font-family: 'TaoBaoMaiCaiTi';
src: url('./TaoBaoMaiCaiTi-Regular.woff2') format('woff2'), /* 最优先使用 woff2 */
url('./TaoBaoMaiCaiTi-Regular.woff') format('woff'), /* 兼容性较好的 woff */
url('./TaoBaoMaiCaiTi-Regular.ttf') format('truetype'), /* ttf 作为备选 */
url('./TaoBaoMaiCaiTi-Regular.otf') format('opentype'); /* otf 作为最后选项 */
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; /* 优化页面加载时的字体显示 */
}

BIN
react-ui/src/assets/img/user-points-bg.png View File

Before After
Width: 981  |  Height: 672  |  Size: 220 kB

BIN
react-ui/src/assets/img/workspace-experiment.png View File

Before After
Width: 147  |  Height: 148  |  Size: 17 kB Width: 216  |  Height: 216  |  Size: 24 kB

BIN
react-ui/src/assets/img/workspace-pipeline.png View File

Before After
Width: 169  |  Height: 159  |  Size: 21 kB Width: 219  |  Height: 216  |  Size: 31 kB

+ 1
- 1
react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx View File

@@ -137,7 +137,7 @@ function EditorCreate() {
<Col span={10}>
<Form.Item
label="资源规格"
name="standard"
name="computing_resource_id"
rules={[
{
required: true,


+ 1
- 1
react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx View File

@@ -347,7 +347,7 @@ function CreateServiceVersion() {
<Col span={10}>
<Form.Item
label="资源规格"
name="resource"
name="computing_resource_id"
rules={[
{
required: true,


+ 2
- 2
react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx View File

@@ -309,8 +309,8 @@ function ServiceInfo() {
},
{
title: '资源规格',
dataIndex: 'resource',
key: 'resource',
dataIndex: 'computing_resource_id',
key: 'computing_resource_id',
width: '20%',
render: tableCellRender(true, TableCellValueType.Custom, {
format: getResourceDescription,


+ 1
- 1
react-ui/src/pages/ModelDeployment/components/VersionBasicInfo/index.tsx View File

@@ -68,7 +68,7 @@ function VersionBasicInfo({ info }: BasicInfoProps) {
},
{
label: '资源规格',
value: info?.resource,
value: info?.computing_resource_id,
format: getResourceDescription,
},
{


+ 1
- 1
react-ui/src/pages/ModelDeployment/types.ts View File

@@ -24,7 +24,7 @@ export type ServiceVersionData = {
run_state: ServiceRunStatus; // 运行状态
image: string; // 镜像
replicas: number; // 副本数
resource: string; // 资源
computing_resource_id: number; // 资源
mount_path: string; // 挂载路径
model: {
// 模型


+ 31
- 0
react-ui/src/pages/Points/components/Statistics/index.less View File

@@ -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;
}
}
}

+ 38
- 0
react-ui/src/pages/Points/components/Statistics/index.tsx View File

@@ -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 (
<div className={styles['statistics']}>
{items.map((item, index) => (
<div
key={item.title}
className={classNames(styles['statistics__item'], {
[styles['statistics__item--border']]: index === 0,
})}
>
<span className={styles['statistics__item__value']}>{item.value}</span>
<span className={styles['statistics__item__title']}>{item.title}</span>
</div>
))}
</div>
);
}

export default Statistics;

+ 19
- 0
react-ui/src/pages/Points/index.less View File

@@ -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;
}
}
}

+ 256
- 0
react-ui/src/pages/Points/index.tsx View File

@@ -0,0 +1,256 @@
/*
* @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: 'dev_environment',
label: '开发环境',
},
{
value: 'workflow',
label: '实验',
},
{
value: 'ray',
label: '超参数自动寻优',
},
{
value: '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 <Link to={url}>{value}</Link>;
} else {
return <span>{value}</span>;
}
};

function PointsDetail() {
const [tableData, setTableData] = useState<PointsData[]>([]);
const [total, setTotal] = useState(0);
const [statistics, setStatistics] = useState<PointsStatistics>();
const [pagination, setPagination] = useState<TablePaginationConfig>({
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<string, any> = {
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<PointsData>['onChange'] = (
pagination,
_filters,
_sorter,
{ action },
) => {
if (action === 'paginate') {
setPagination(pagination);
}
};

const columns: TableProps<PointsData>['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'],
},
]),
},
];

return (
<div className={styles['points-detail']}>
<PageTitle title="算力积分明细"></PageTitle>
<div className={styles['points-detail__content']}>
<div className={styles['points-detail__content__top']}>
<Statistics
remaining={statistics?.userCredit}
consuming={statistics?.deduceCredit}
></Statistics>
</div>
<div
className={classNames('vertical-scroll-table', styles['points-detail__content__table'])}
>
<Table
dataSource={tableData}
columns={columns}
scroll={{ y: 'calc(100% - 55px)' }}
pagination={{
...pagination,
total: total,
showSizeChanger: true,
showQuickJumper: true,
showTotal: () => `共${total}条`,
}}
onChange={handleTableChange}
rowKey="id"
/>
</div>
</div>
</div>
);
}

export default PointsDetail;

+ 15
- 6
react-ui/src/pages/System/User/edit.tsx View File

@@ -2,6 +2,7 @@ import { DictValueEnumObj } from '@/components/DictTag';
import KFModal from '@/components/KFModal';
import {
ProForm,
ProFormDigit,
ProFormRadio,
ProFormSelect,
ProFormText,
@@ -64,6 +65,7 @@ const UserForm: React.FC<UserFormProps> = (props) => {
remark: props.values.remark,
gitLinkUsername: props.values.gitLinkUsername,
gitLinkPassword: props.values.gitLinkPassword,
credit: props.values.credit,
});
}, [form, props, statusOptions]);

@@ -219,12 +221,7 @@ const UserForm: React.FC<UserFormProps> = (props) => {
autoComplete: 'new-password',
}}
allowClear
rules={[
{
required: true,
message: <FormattedMessage id="请输入密码!" defaultMessage="请输入密码!" />,
},
]}
rules={props.values.userId ? [] : [{ required: true, message: '请输入密码!' }]}
/>
<ProFormSelect
valueEnum={sexOptions}
@@ -304,6 +301,18 @@ const UserForm: React.FC<UserFormProps> = (props) => {
}}
rules={props.values.userId ? [] : [{ required: true, message: '请输入 Git 密码!' }]}
/>
<ProFormDigit
name="credit"
label="算力积分"
placeholder="请输入算力积分"
colProps={{ xs: 24, md: 12, xl: 12 }}
rules={[
{
required: true,
message: '请输入算力积分',
},
]}
/>
<ProFormTextArea
name="remark"
label={intl.formatMessage({


+ 5
- 0
react-ui/src/pages/System/User/index.tsx View File

@@ -259,6 +259,11 @@ const UserTableList: React.FC = () => {
dataIndex: 'phonenumber',
valueType: 'text',
},
{
title: <FormattedMessage id="system.user.credit" defaultMessage="算力积分" />,
dataIndex: 'credit',
valueType: 'text',
},
{
title: <FormattedMessage id="system.user.status" defaultMessage="帐号状态" />,
dataIndex: 'status',


+ 1
- 0
react-ui/src/pages/Workspace/components/ExperimentChart/index.less View File

@@ -1,4 +1,5 @@
.experiment-chart {
flex: none;
width: 295px;
min-width: 295px;
height: 140px;


+ 5
- 5
react-ui/src/pages/Workspace/components/ExperimentTable/index.less View File

@@ -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 {


+ 4
- 16
react-ui/src/pages/Workspace/components/TotalStatistics/index.less View File

@@ -1,16 +1,12 @@
.total-statistics {
display: flex;
align-items: center;
justify-content: center;
width: 400px;
height: 140px;
background: @workspace-background;
border-radius: 4px;
padding: 0 16px;

&__icon {
width: 85px;
height: 80px;
margin-right: 40px;
width: 63px;
margin-right: 15px;
}

&__title {
@@ -20,18 +16,10 @@
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-family: DingTalk-JinBuTi;
}
}

+ 3
- 3
react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx View File

@@ -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 (
<div className={styles['total-statistics']} style={style}>
<img className={styles['total-statistics__icon']} src={icon} draggable={false} alt="" />
<div>
<Flex vertical align="center">
<div className={styles['total-statistics__title']}>
<span>{title}</span>
<div className={styles['total-statistics__title-shadow']}></div>
</div>
<div className={styles['total-statistics__count']}>{count ?? '--'}</div>
</div>
</Flex>
</div>
);
}


+ 36
- 0
react-ui/src/pages/Workspace/components/UserPoints/index.less View File

@@ -0,0 +1,36 @@
.user-points {
display: flex;
flex: none;
flex-direction: column;
align-items: center;

width: 326px;
height: 228px;
.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 {
margin-top: 8px;
margin-bottom: 12px;
color: @primary-color;
font-size: 36px;
font-family: DingTalk-JinBuTi;
line-height: 43px;
}

&__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;
}
}

+ 40
- 0
react-ui/src/pages/Workspace/components/UserPoints/index.tsx View File

@@ -0,0 +1,40 @@
import { PointsStatistics } from '@/pages/Points/index';
import { getPointsStatisticsReq } from '@/services/points';
import { to } from '@/utils/promise';
import { useNavigate } from '@umijs/max';
import { useEffect, useState } from 'react';
import styles from './index.less';

function UserPoints() {
const [statistics, setStatistics] = useState<PointsStatistics>();
const navigate = useNavigate();

useEffect(() => {
// 获取积分统计
const getPointsStatistics = async () => {
const [res] = await to(getPointsStatisticsReq());
if (res && res.data) {
setStatistics(res.data);
}
};

getPointsStatistics();
}, []);

return (
<div className={styles['user-points']}>
<span className={styles['user-points__label']}>当前可用算力积分</span>
<span className={styles['user-points__value']}>{statistics?.userCredit ?? '--'}</span>
<div
className={styles['user-points__button']}
onClick={() => {
navigate('/points');
}}
>
查看详情
</div>
</div>
);
}

export default UserPoints;

+ 11
- 2
react-ui/src/pages/Workspace/index.less View File

@@ -6,6 +6,7 @@
background: linear-gradient(#ecf2fe, #f9fafb);

&__overview {
flex: 1;
gap: 15px;
margin-bottom: 16px;
padding: 20px 30px;
@@ -21,11 +22,19 @@

&__content {
display: flex;

flex-wrap: wrap;
gap: 15px;
align-items: center;

@media screen and (max-width: 1800px) {
flex-wrap: wrap;
&__statistics {
flex: none;
background: linear-gradient(
123.08deg,
rgba(138, 138, 138, 0.06) 1.32%,
rgba(22, 100, 255, 0.02) 58.35%
);
border-radius: 4px;
}
}
}


+ 34
- 20
react-ui/src/pages/Workspace/index.tsx View File

@@ -2,6 +2,7 @@ import { useDraggable } from '@/hooks/draggable';
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 (
<div className={styles.workspace}>
<WorkspaceIntro></WorkspaceIntro>
<div className={styles['workspace__overview']}>
<div className={styles['workspace__overview__title']}>运行概览</div>
<div className={styles['workspace__overview__content']}>
<TotalStatistics
icon={require('@/assets/img/workspace-pipeline.png')}
title="流水线总数"
count={overviewData?.workflowCount}
/>
<TotalStatistics
icon={require('@/assets/img/workspace-experiment.png')}
title="正在运行实例总数"
count={overviewData?.runningExperimentInsCount}
/>
<ExperitableTable
tableData={overviewData?.latestExperimentInsList || []}
></ExperitableTable>
{overviewData?.experimentInsStatus && (
<ExperimentChart chartData={overviewData?.experimentInsStatus}></ExperimentChart>
)}
<Flex gap={'0 15px'} wrap>
<div className={styles['workspace__overview']}>
<div className={styles['workspace__overview__title']}>运行概览</div>
<div className={styles['workspace__overview__content']}>
<Flex align="center" className={styles['workspace__overview__content__statistics']}>
<TotalStatistics
icon={require('@/assets/img/workspace-pipeline.png')}
title="流水线总数"
count={overviewData?.workflowCount}
/>
<Divider
type="vertical"
dashed
style={{ color: '1px dashed rgba(96, 107, 122, 0.19)', height: 68 }}
/>
<TotalStatistics
icon={require('@/assets/img/workspace-experiment.png')}
title="正在运行实例总数"
count={overviewData?.runningExperimentInsCount}
/>
</Flex>

<ExperitableTable
tableData={overviewData?.latestExperimentInsList || []}
></ExperitableTable>
{overviewData?.experimentInsStatus && (
<ExperimentChart chartData={overviewData?.experimentInsStatus}></ExperimentChart>
)}
</div>
</div>
</div>
<UserPoints />
</Flex>
<div className={styles['workspace__quick-start']}>
<QuickStart></QuickStart>
<div className={styles['workspace__user']}>


+ 22
- 0
react-ui/src/services/points/index.ts View File

@@ -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',
});
}

+ 5
- 0
react-ui/src/stories/docs/Utils.mdx View File

@@ -0,0 +1,5 @@
import { Meta } from '@storybook/blocks';

<Meta title="Documentation/Utils" />

<a href="/docs/index.html" target='_blank'>工具栏文档</a>

+ 8
- 0
react-ui/src/styles/theme.less View File

@@ -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;


+ 1
- 0
react-ui/src/types/system/user.d.ts View File

@@ -21,6 +21,7 @@ declare namespace API.System {
remark: string;
gitLinkUsername?: string;
gitLinkPassword?: string;
credit?: number;
}

export interface UserListParams {


+ 86
- 12
react-ui/src/utils/index.ts View File

@@ -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<string, any>) {
if (!isPlainObject(obj)) {
return obj;
@@ -66,7 +90,14 @@ export function underscoreToCamelCase(obj: Record<string, any>) {
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<string, any>) {
if (!isPlainObject(obj)) {
return obj;
@@ -87,7 +118,14 @@ export function camelCaseToUnderscore(obj: Record<string, any>) {
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<string, any> | null) {
if (obj === null) {
return undefined;
@@ -113,7 +151,15 @@ export function nullToUndefined(obj: Record<string, any> | 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<string, any>) {
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;


+ 23
- 0
react-ui/src/utils/statusTableCell.tsx View File

@@ -0,0 +1,23 @@
/*
* @Author: 赵伟
* @Date: 2025-03-20 14:33:01
* @Description: 通用的 Table 状态单元格
*/

export type StatusInfo = {
value: number | string;
label: string;
color?: string;
};

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 <span>--</span>;
}
return <span style={{ color: info.color }}>{info.label}</span>;
};
}

export default statusTableCell;

+ 1
- 1
react-ui/src/utils/table.tsx View File

@@ -1,7 +1,7 @@
/*
* @Author: 赵伟
* @Date: 2024-06-26 10:05:52
* @Description: Table cell 自定义 render
* @Description: Table Cell 自定义 render
*/

import { isEmpty } from '@/utils';


+ 11
- 0
react-ui/typedoc.json View File

@@ -0,0 +1,11 @@
{
"entryPoints": ["./src/utils"],
"entryPointStrategy": "expand",
"out": "docs",
"excludePrivate": true,
"excludeProtected": false,
"excludeExternals": true,
"includeVersion": true,
"categorizeByGroup": true,
"name": "工具类文档"
}

+ 1
- 0
react-ui/types/tsconfig.tsbuildinfo
File diff suppressed because it is too large
View File


+ 12
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ResourceOccupyTask.java View File

@@ -7,12 +7,15 @@ import com.ruoyi.platform.mapper.DevEnvironmentDao;
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 org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component()
public class ResourceOccupyTask {
@@ -26,6 +29,9 @@ public class ResourceOccupyTask {
@Resource
private ServiceDao serviceDao;

@Resource
private ServiceService serviceService;

@Resource
private JupyterService jupyterService;

@@ -50,8 +56,13 @@ public class ResourceOccupyTask {
@Scheduled(cron = "0 0/1 * * * ?") // 每1分钟执行一次
public void serviceDeduceCredit() {
List<ServiceVersion> serviceVersions = serviceDao.getRunning();
List<String> deploymentNames = serviceVersions.stream().map(ServiceVersion::getDeploymentName).collect(Collectors.toList());
Map<String, String> runStates = serviceService.getRunState(deploymentNames);
serviceService.updateRunState(runStates, serviceVersions);
for (ServiceVersion serviceVersion : serviceVersions) {
resourceOccupyService.deducing(Constant.TaskType_Service, null, serviceVersion.getId(), null, null);
if (Constant.Running.equals(serviceVersion.getRunState())) {
resourceOccupyService.deducing(Constant.TaskType_Service, null, serviceVersion.getId(), null, null);
}
}
}
}

+ 4
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ServiceService.java View File

@@ -45,4 +45,8 @@ public interface ServiceService {
Map<String, Object> getServiceVersionDocs(Long id);

List<ServiceVersion> serviceVersionList(Long id);

Map<String, String> getRunState(List<String> deploymentNames);

void updateRunState(Map<String, String> runStates, List<ServiceVersion> serviceVersionList);
}

+ 4
- 7
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/JupyterServiceImpl.java View File

@@ -97,9 +97,8 @@ public class JupyterServiceImpl implements JupyterService {
// String modelPath = "argo-workflow" + "/" + model.get("path");
String modelPath = (String) model.get("path");

LoginUser loginUser = SecurityUtils.getLoginUser();
//构造pod名称
String podName = loginUser.getUsername().toLowerCase() + "-editor-pod" + "-" + id;
String podName = devEnvironment.getCreateBy() + "-editor-pod" + "-" + id;
//新建编辑器的pvc
// String pvcName = loginUser.getUsername().toLowerCase() + "-editor-pvc";
// V1PersistentVolumeClaim pvc = k8sClientUtil.createPvc(namespace, pvcName, storage, storageClassName);
@@ -123,10 +122,9 @@ public class JupyterServiceImpl implements JupyterService {
if (devEnvironment == null) {
throw new Exception("开发环境配置不存在");
}
LoginUser loginUser = SecurityUtils.getLoginUser();
//构造pod和svc名称
String podName = loginUser.getUsername().toLowerCase() + "-editor-pod" + "-" + id;
String svcName = loginUser.getUsername().toLowerCase() + "-editor-pod" + "-" + id + "-svc";
String podName = devEnvironment.getCreateBy() + "-editor-pod" + "-" + id;
String svcName = devEnvironment.getCreateBy() + "-editor-pod" + "-" + id + "-svc";
//得到pod
V1Pod pod = k8sClientUtil.getNSPodList(namespace, podName);
if (pod == null) {
@@ -155,8 +153,7 @@ public class JupyterServiceImpl implements JupyterService {
if (devEnvironment == null) {
return JupyterStatusVo;
}
LoginUser loginUser = SecurityUtils.getLoginUser();
String podName = loginUser.getUsername().toLowerCase() + "-editor-pod" + "-" + devEnvironment.getId();
String podName = devEnvironment.getCreateBy() + "-editor-pod" + "-" + devEnvironment.getId();

try {
// 查询相应pod状态


+ 4
- 2
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ServiceServiceImpl.java View File

@@ -401,7 +401,8 @@ public class ServiceServiceImpl implements ServiceService {
return serviceVersionVo;
}

Map<String, String> getRunState(List<String> deploymentNames) {
@Override
public Map<String, String> getRunState(List<String> deploymentNames) {
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("deployment_names", deploymentNames);
String req = HttpUtils.sendPost(argoUrl + modelService + "/getStatus", JSON.toJSONString(paramMap));
@@ -417,7 +418,8 @@ public class ServiceServiceImpl implements ServiceService {
}
}

void updateRunState(Map<String, String> runStates, List<ServiceVersion> serviceVersionList) {
@Override
public void updateRunState(Map<String, String> runStates, List<ServiceVersion> serviceVersionList) {
for (ServiceVersion sv : serviceVersionList) {
String runState = runStates.get(sv.getDeploymentName());
sv.setRunState(runState);


+ 22
- 10
ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ServiceDaoMapper.xml View File

@@ -56,9 +56,9 @@
</sql>

<select id="getServiceById" resultType="com.ruoyi.platform.domain.Service">
select a.*,count(b.id) as version_count
select a.*, count(b.id) as version_count
from service a
left join (select * from service_version where state = 1) b on a.id = b.service_id
left join (select * from service_version where state = 1) b on a.id = b.service_id
where a.id = #{id}
</select>

@@ -75,31 +75,43 @@
</select>

<select id="getServiceByName" resultType="com.ruoyi.platform.domain.Service">
select * from service where service_name = #{serviceName} and state = 1
select *
from service
where service_name = #{serviceName}
and state = 1
</select>

<select id="getSvByVersion" resultType="com.ruoyi.platform.domain.ServiceVersion">
select *
from service_version
where service_id = #{serviceId} and version = #{version} and state = 1
where service_id = #{serviceId}
and version = #{version}
and state = 1
</select>

<select id="getRunning" resultType="com.ruoyi.platform.domain.ServiceVersion">
select *
from service_version where state = 1 and run_state = 'Running'
from service_version
where state = 1
and (run_state = 'Running' or run_state = 'Pending' or run_state = 'Init')
</select>

<insert id="insertService" keyProperty="id" useGeneratedKeys="true">
insert into service(service_name, service_type, description, create_by, update_by)
values (#{service.serviceName}, #{service.serviceType}, #{service.description}, #{service.createBy}, #{service.updateBy})
values (#{service.serviceName}, #{service.serviceType}, #{service.description}, #{service.createBy},
#{service.updateBy})
</insert>

<insert id="insertServiceVersion" keyProperty="id" useGeneratedKeys="true">
insert into service_version(service_id, version, model, description, image, resource, computing_resource_id, replicas, mount_path, env_variables,
insert into service_version(service_id, version, model, description, image, resource, computing_resource_id,
replicas, mount_path, env_variables,
code_config, command, create_by, update_by, deploy_type)
values (#{serviceVersion.serviceId}, #{serviceVersion.version}, #{serviceVersion.model}, #{serviceVersion.description}, #{serviceVersion.image},
#{serviceVersion.resource}, #{serviceVersion.computingResourceId}, #{serviceVersion.replicas}, #{serviceVersion.mountPath}, #{serviceVersion.envVariables},
#{serviceVersion.codeConfig}, #{serviceVersion.command}, #{serviceVersion.createBy}, #{serviceVersion.updateBy}, #{serviceVersion.deployType})
values (#{serviceVersion.serviceId}, #{serviceVersion.version}, #{serviceVersion.model},
#{serviceVersion.description}, #{serviceVersion.image},
#{serviceVersion.resource}, #{serviceVersion.computingResourceId}, #{serviceVersion.replicas},
#{serviceVersion.mountPath}, #{serviceVersion.envVariables},
#{serviceVersion.codeConfig}, #{serviceVersion.command}, #{serviceVersion.createBy},
#{serviceVersion.updateBy}, #{serviceVersion.deployType})
</insert>

<update id="updateService">


Loading…
Cancel
Save