diff --git a/webapp/.env.mock b/webapp/.env.mock new file mode 100644 index 0000000..f913c6a --- /dev/null +++ b/webapp/.env.mock @@ -0,0 +1,4 @@ +ENV='development' +VUE_APP_MOCK=true +VUE_APP_BASE_API = '' +VUE_APP_DATA_API = '/mock' diff --git a/webapp/.eslintignore b/webapp/.eslintignore index 71a5886..5f8e217 100644 --- a/webapp/.eslintignore +++ b/webapp/.eslintignore @@ -2,4 +2,5 @@ build/*.js src/assets public dist -src/components/Crud \ No newline at end of file +src/components/Crud +mock \ No newline at end of file diff --git a/webapp/.npmrc b/webapp/.npmrc new file mode 100644 index 0000000..cafe685 --- /dev/null +++ b/webapp/.npmrc @@ -0,0 +1 @@ +package-lock=true diff --git a/webapp/CHANGELOG.md b/webapp/CHANGELOG.md index 4de36e2..b01e4c4 100644 --- a/webapp/CHANGELOG.md +++ b/webapp/CHANGELOG.md @@ -1,3 +1,18 @@ +## 0.2.1 (2020-11-16) + +### Features + +- 页面布局中的footer可配置 +- 新增前端开发时mock后端接口的功能 +- [数据管理] 创建数据集时选择标签组、标签组管理查看标签详情体验优化 +- [训练管理] 提取前端参数配置到公共配置文件 (config/index.js) + +### Bug Fixs + +- 锁定Element UI版本,修复其新版不兼容升级导致的功能异常 +- [训练管理] 分布式训练默认节点数调整, 节点数下限改为2 +- [训练管理] 修复模型下载、模型保存、断点续训目录树弹窗loading效果 + ## 0.2.0 (2020-10-26) ### Breaking Change diff --git a/webapp/README.md b/webapp/README.md index b189f9e..5eddbc3 100644 --- a/webapp/README.md +++ b/webapp/README.md @@ -79,6 +79,15 @@ npm install npm run dev ``` +## 接口 Mock + +当前项目自动集成了接口 mock 服务,用户可以通过 `npm run mock` 启动数据 mock 服务。 + +- 普通接口:在 `mock` 目录下创建根据请求 url 创建对应文件,比如请求路径是`api/data/datasets`,在就直接创建 `mock/api/data/datasets.js` 文件,并导出 mock 文件 +- RESTful 风格接口:在 `mock/mock-map` 文件下创建对应的文件 map, key 为符合[path-to-regexp](https://github.com/pillarjs/path-to-regexp) 风格的路径,value 为对应的实际 mock 文件地址 + +如果用户未创建 mock 文件,请求会转发到 `development` 环境指定的 api 地址。 + ## 项目结构 ``` diff --git a/webapp/mock/api/data/datasets.js b/webapp/mock/api/data/datasets.js new file mode 100644 index 0000000..0a90cac --- /dev/null +++ b/webapp/mock/api/data/datasets.js @@ -0,0 +1,56 @@ +module.exports = { + "code": 200, + "msg": null, + "data": { + "result": [{ + "id": 56, + "name": "bag_data", + "remark": "不可删除,不可删除", + "type": 0, + "uri": null, + "dataType": 0, + "annotateType": 2, + "status": 104, + "createTime": "2020-10-21 15:39:01", + "updateTime": "2020-10-22 14:13:10", + "team": null, + "createUser": null, + "updateUser": null, + "progress": null, + "currentVersionName": null, + "decompressState": 0, + "labelGroupId": 1, + "labelGroupName": "COCO", + "labelGroupType": 1, + "import": false, + "top": true + }, { + "id": 346, + "name": "test432", + "remark": "test432", + "type": 0, + "uri": null, + "dataType": 0, + "annotateType": 1, + "status": 101, + "createTime": "2020-10-27 15:20:58", + "updateTime": "2020-10-27 15:20:58", + "team": null, + "createUser": null, + "updateUser": null, + "progress": null, + "currentVersionName": null, + "decompressState": 0, + "labelGroupId": 468, + "labelGroupName": "test432", + "labelGroupType": 0, + "import": false, + "top": false + }], + "page": { + "size": 10, + "current": 1, + "total": 218 + }, + } +} diff --git a/webapp/mock/api/data/labelGroup/getList/id.js b/webapp/mock/api/data/labelGroup/getList/id.js new file mode 100644 index 0000000..0a68b30 --- /dev/null +++ b/webapp/mock/api/data/labelGroup/getList/id.js @@ -0,0 +1,5 @@ +module.exports = { + "code": 200, + "msg": null, + "data": [] +} \ No newline at end of file diff --git a/webapp/mock/mock-map.js b/webapp/mock/mock-map.js new file mode 100644 index 0000000..ee14253 --- /dev/null +++ b/webapp/mock/mock-map.js @@ -0,0 +1,4 @@ +// 定义 RESTful 接口和实际代码的映射 +module.exports = { + 'GET::/api/data/labelGroup/getList/(\\d+)': '/api/data/labelGroup/getList/id', +}; diff --git a/webapp/package.json b/webapp/package.json index c8eddae..5604797 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,6 +1,6 @@ { "name": "dubhe-web", - "version": "0.2.0", + "version": "0.2.1", "description": "之江天枢人工智能开源平台", "author": "zhejianglab", "keywords": [ @@ -11,6 +11,7 @@ "人工智能" ], "scripts": { + "mock": "vue-cli-service serve --mode mock --open", "dev": "vue-cli-service serve --open", "build:prod": "vue-cli-service build", "build:test": "vue-cli-service build --mode test", @@ -51,7 +52,7 @@ "date-fns": "^2.13.0", "echarts": "4.2.1", "echarts-gl": "^1.1.1", - "element-ui": "^2.13.2", + "element-ui": "2.13.2", "file-saver": "^2.0.2", "filereader-stream": "^2.0.0", "jquery": "^3.5.1", @@ -66,6 +67,7 @@ "normalize.css": "7.0.0", "nprogress": "0.2.0", "p-map": "^4.0.0", + "path-to-regexp": "^6.2.0", "prismjs": "^1.20.0", "promise.allsettled": "^1.0.2", "qs": "^6.9.1", @@ -105,6 +107,7 @@ "eslint-plugin-import": "^2.20.2", "eslint-plugin-prettier": "^2.3.1", "eslint-plugin-vue": "^6.2.2", + "express-http-proxy": "^1.6.2", "html-webpack-plugin": "3.2.0", "husky": "^4.2.5", "less": "^3.11.3", diff --git a/webapp/src/components/Training/jobForm.vue b/webapp/src/components/Training/jobForm.vue index 2542f0f..5b80ef1 100644 --- a/webapp/src/components/Training/jobForm.vue +++ b/webapp/src/components/Training/jobForm.vue @@ -222,8 +222,8 @@ @@ -282,7 +282,7 @@ id="delayCreateTime" v-model="form.delayCreateTime" :min="0" - :max="168" + :max="trainConfig.delayCreateTimeMax" :step-strictly="true" /> 小时 @@ -295,7 +295,7 @@ id="delayDeleteTime" v-model="form.delayDeleteTime" :min="0" - :max="168" + :max="trainConfig.delayDeleteTimeMax" :step-strictly="true" /> 小时 @@ -374,6 +374,7 @@ import { list as getAlgorithmList } from '@/api/algorithm/algorithm'; import { harborProjectNames, harborImageNames } from '@/api/system/harbor'; import { list as getModelName } from '@/api/model/model'; import { list as getModelTag } from '@/api/model/modelVersion'; +import { trainConfig } from '@/config'; import RunParamForm from './runParamForm'; import DataSourceSelector from './dataSourceSelector'; @@ -442,6 +443,7 @@ export default { dictReady: false, delayCreateDelete: false, selectedAlgorithm: null, + trainConfig, form: { ...defaultForm }, rules: { @@ -814,9 +816,7 @@ export default { this.onResourcesPoolTypeChange(); }, onTrainTypeChange(trainType) { - if (trainType === 0) { - this.form.resourcesPoolNode = 1; - } + this.form.resourcesPoolNode = trainType === 0 ? 1 : 2; }, }, }; diff --git a/webapp/src/config/index.js b/webapp/src/config/index.js index 6255f1c..ed79491 100644 --- a/webapp/src/config/index.js +++ b/webapp/src/config/index.js @@ -14,31 +14,52 @@ * ============================================================= */ -module.exports = { - minIO: { - development: { - config: { - endPoint: '', // MinIO 服务地址 - port: 9000, - useSSL: false, - }, - bucketName: 'dubhe-dev', +// minIO 参数配置 +export const minIO = { + development: { + config: { + endPoint: '', // MinIO 服务地址 + port: 9000, + useSSL: false, }, - test: { - config: { - endPoint: '', - port: 9000, - useSSL: false, - }, - bucketName: 'dubhe-test', + bucketName: 'dubhe-dev', + }, + test: { + config: { + endPoint: '', + port: 9000, + useSSL: false, }, - production: { - config: { - endPoint: '', - port: 9000, - useSSL: false, - }, - bucketName: 'dubhe-prod', + bucketName: 'dubhe-test', + }, + production: { + config: { + endPoint: '', + port: 9000, + useSSL: false, }, + bucketName: 'dubhe-prod', }, }; + +// 训练管理模块参数配置 +export const trainConfig = { + trainNodeMax: Infinity, // 分布式训练节点上限 + delayCreateTimeMax: 168, // 延时启动时间上限 + delayDeleteTimeMax: 168, // 训练时长上限 +}; + +// 算法管理参数配置 +export const algorithmConfig = { + uploadFileAcceptSize: 1024, // 上传算法文件大小限制,单位为 MB,0 表示不限制大小 +}; + +// 镜像管理参数配置 +export const imageConfig = { + uploadFileAcceptSize: 0, // 上传镜像文件大小限制,单位为 MB,0 表示不限制大小 +}; + +// 模型管理模块参数配置 +export const modelConfig = { + uploadFileAcceptSize: 0, // 上传模型文件大小限制,单位为 MB,0 表示不限制大小 +}; diff --git a/webapp/src/layout/BaseLayout.vue b/webapp/src/layout/BaseLayout.vue index 9bfd700..9ebc7df 100644 --- a/webapp/src/layout/BaseLayout.vue +++ b/webapp/src/layout/BaseLayout.vue @@ -26,11 +26,19 @@ + @@ -38,7 +46,7 @@ + + diff --git a/webapp/src/layout/components/index.js b/webapp/src/layout/components/index.js index 590baa5..df87f7e 100644 --- a/webapp/src/layout/components/index.js +++ b/webapp/src/layout/components/index.js @@ -17,4 +17,5 @@ export { default as AppMain } from './AppMain'; export { default as Navbar } from './Navbar'; export { default as Sidebar } from './Sidebar'; +export { default as Guideline } from './Guideline'; export { default as Feedback } from './Feedback'; diff --git a/webapp/src/settings.js b/webapp/src/settings.js index 5813ff8..fdde555 100644 --- a/webapp/src/settings.js +++ b/webapp/src/settings.js @@ -58,9 +58,13 @@ module.exports = { /** * RSA公钥 */ - publicKey: 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ==', + publicKey: '', /** * 用户社区 */ Community: 'http://www.aiiaos.cn/index.php?s=/forum/index/forum/id/45.html', + /** + * 使用文档 + */ + DocLink: 'http://docs.dubhe.ai/docs/' , }; diff --git a/webapp/src/utils/minIO.js b/webapp/src/utils/minIO.js index f0502b7..2981f21 100644 --- a/webapp/src/utils/minIO.js +++ b/webapp/src/utils/minIO.js @@ -16,10 +16,10 @@ import { getMinIOAuth } from '@/api/auth'; import { decrypt } from '@/utils/rsaEncrypt'; +import { minIO } from '@/config'; const Minio = require('minio'); const toArray = require('stream-to-array'); -const Config = require('@/config'); const env = process.env.NODE_ENV || 'development'; @@ -36,7 +36,7 @@ const makeBucket = (client, bucketName) => { }); }; -const minIOConfig = Config.minIO[env]; +const minIOConfig = minIO[env]; // 导出 bucketName export const {bucketName} = minIOConfig; diff --git a/webapp/src/utils/utils.js b/webapp/src/utils/utils.js index fca1c16..d89ed76 100644 --- a/webapp/src/utils/utils.js +++ b/webapp/src/utils/utils.js @@ -343,3 +343,11 @@ export const getTreeListFromFilepath = async (filepath) => { export function getUniqueId() { return parseTime(new Date(), '{y}{m}{d}{h}{i}{s}{S}') + nanoid(4); } + +// 以 MB 为入参单位,格式化上传大小文本 +export function uploadSizeFomatter(size) { + if (size >= 1024) { + return `${size / 1024} GB`; + } + return `${size} MB`; +} diff --git a/webapp/src/views/algorithm/index.vue b/webapp/src/views/algorithm/index.vue index 5e00ac8..0ca4411 100644 --- a/webapp/src/views/algorithm/index.vue +++ b/webapp/src/views/algorithm/index.vue @@ -181,8 +181,8 @@ ref="upload" action="fakeApi" accept=".zip" - :acceptSize="1024" - :acceptSizeFormat="(size) => `${size/1024} GB`" + :acceptSize="algorithmConfig.uploadFileAcceptSize" + :acceptSizeFormat="uploadSizeFomatter" list-type="text" :show-file-count="false" :params="uploadParams" @@ -263,7 +263,7 @@ diff --git a/webapp/src/views/dataset/annotate/settingContainer/index.vue b/webapp/src/views/dataset/annotate/settingContainer/index.vue index fbfacf8..1cfadc9 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/index.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/index.vue @@ -240,7 +240,6 @@ export default {