From 4f046172c08057127e07d9f6953a79656b09f209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=8B=E6=B1=9F=E5=AE=9E=E9=AA=8C=E5=AE=A4?= Date: Thu, 14 Jan 2021 18:14:12 +0800 Subject: [PATCH] update webapp --- webapp/.env.development | 23 +- webapp/.env.mock | 22 +- webapp/.env.production | 30 +- webapp/.env.test | 24 +- webapp/CHANGELOG.md | 25 + webapp/README.md | 5 +- webapp/mock/api/data/datasets.js | 56 - webapp/mock/api/data/datasets/count.js | 8 + webapp/mock/api/data/labelGroup/getList/id.js | 5 - webapp/mock/mock-map.js | 2 +- webapp/package.json | 11 +- webapp/src/App.vue | 4 +- webapp/src/api/algorithm/algorithm.js | 12 +- webapp/src/api/algorithm/algorithmUsage.js | 2 +- .../api/{system/menu.js => atlas/index.js} | 34 +- webapp/src/api/auth.js | 2 +- webapp/src/api/cloudServing/batch.js | 89 + webapp/src/api/cloudServing/index.js | 114 + webapp/src/api/development/notebook.js | 2 +- webapp/src/api/model/model.js | 10 +- webapp/src/api/model/modelVersion.js | 2 +- webapp/src/api/modelOptimize/optimize.js | 107 + .../harbor.js => modelOptimize/record.js} | 36 +- webapp/src/api/preparation/annotation.js | 2 +- webapp/src/api/preparation/datafile.js | 2 +- webapp/src/api/preparation/datalabel.js | 6 +- webapp/src/api/preparation/dataset.js | 22 +- webapp/src/api/preparation/labelGroup.js | 5 +- webapp/src/api/preparation/medical.js | 170 + webapp/src/api/preparation/textData.js | 63 + webapp/src/api/system/dict.js | 2 +- webapp/src/api/system/dictDetail.js | 2 +- webapp/src/api/system/node.js | 2 +- webapp/src/api/system/pod.js | 2 +- webapp/src/api/system/role.js | 9 +- webapp/src/api/system/user.js | 2 +- webapp/src/api/trainingImage/index.js | 21 +- webapp/src/api/trainingJob/job.js | 10 +- webapp/src/api/trainingJob/params.js | 2 +- webapp/src/api/user.js | 2 +- webapp/src/api/visual/index.js | 2 +- .../assets/images/dataset/medicalDataset.png | Bin 0 -> 37162 bytes .../assets/images/dataset/normalDataset.png | Bin 0 -> 28399 bytes webapp/src/assets/styles/atomic.scss | 83 +- webapp/src/assets/styles/common.scss | 15 + webapp/src/assets/styles/mixin.scss | 9 + webapp/src/boot/errorHandle.js | 2 +- webapp/src/boot/index.js | 2 +- webapp/src/components/BaseModal/index.js | 11 +- webapp/src/components/Card/info.vue | 2 +- webapp/src/components/Drag/drag.vue | 2 +- webapp/src/components/Drag/index.js | 2 +- .../src/components/DropdownHeader/index.vue | 9 +- webapp/src/components/Exception/index.vue | 2 +- webapp/src/components/IconFont/icon.js | 2 +- webapp/src/components/IconFont/iconfont.js | 2 +- webapp/src/components/IconFont/index.js | 4 +- webapp/src/components/IconFont/utils.js | 2 +- webapp/src/components/ImageGallery/index.vue | 2 +- webapp/src/components/InfoSelect/index.js | 2 +- .../src/components/InfoSelect/info-select.vue | 2 +- webapp/src/components/InfoTable/column.js | 2 +- webapp/src/components/InfoTable/index.js | 2 +- .../src/components/InfoTable/info-table.vue | 31 +- .../src/components/InlineTableEdit/index.vue | 9 +- webapp/src/components/LogContainer/index.vue | 8 +- .../LogContainer/podLogContainer.vue | 364 + webapp/src/components/LoginPublic/index.vue | 2 +- webapp/src/components/Prism/index.vue | 3 +- webapp/src/components/SortingMenu/index.vue | 2 +- .../components/Training/algorithmDetail.vue | 4 +- .../Training/dataSourceSelector.vue | 2 +- webapp/src/components/Training/jobForm.vue | 479 +- webapp/src/components/Training/paramPair.vue | 8 +- .../src/components/Training/runParamForm.vue | 20 +- .../components/Training/saveModelDialog.vue | 2 +- .../UploadForm/FileFilter.js} | 14 +- webapp/src/components/UploadForm/form.js | 91 +- webapp/src/components/UploadForm/index.vue | 32 +- webapp/src/components/UploadForm/inline.vue | 34 +- webapp/src/components/UploadForm/style.scss | 2 +- webapp/src/components/UploadForm/util.js | 32 +- .../src/components/UploadProgress/index.vue | 6 +- webapp/src/components/ZoomContainer/index.vue | 2 +- webapp/src/components/svg/brush/Brush.js | 2 +- .../src/components/svg/brush/BrushCorner.js | 2 +- .../src/components/svg/brush/BrushHandle.js | 2 +- .../components/svg/brush/BrushSelection.js | 2 +- webapp/src/components/svg/brush/index.js | 2 +- webapp/src/components/svg/group/index.js | 2 +- webapp/src/components/svg/index.js | 2 +- webapp/src/components/textEditor.vue | 51 + webapp/src/config/index.js | 40 +- webapp/src/directives/index.js | 2 +- webapp/src/directives/modules/clickOnce.js | 2 +- .../directives/modules/elSelectLoadMore.js | 2 +- webapp/src/directives/modules/mouseWheel.js | 2 +- webapp/src/hooks/brush/BasicBrush.js | 2 +- webapp/src/hooks/brush/index.js | 2 +- webapp/src/hooks/brush/useBrush.js | 2 +- webapp/src/hooks/image/index.js | 2 +- webapp/src/hooks/index.js | 2 +- webapp/src/hooks/tooltip/BasicTooltip.js | 2 +- webapp/src/hooks/tooltip/TooltipContainer.js | 2 +- webapp/src/hooks/tooltip/index.js | 2 +- webapp/src/hooks/tooltip/style.scss | 2 +- webapp/src/hooks/tooltip/tableTooltip.js | 10 +- webapp/src/hooks/tooltip/useTooltip.js | 2 +- webapp/src/hooks/utils.js | 2 +- webapp/src/hooks/zoom/index.js | 2 +- webapp/src/hooks/zoom/useZoom.js | 2 +- webapp/src/layout/BaseLayout.vue | 6 +- webapp/src/layout/DatasetLayout.vue | 40 +- webapp/src/layout/DetailLayout.vue | 2 +- webapp/src/layout/FullpageLayout.vue | 30 + webapp/src/layout/SubpageLayout.vue | 2 +- .../src/layout/components/AppMain/index.vue | 2 +- .../src/layout/components/Feedback/index.vue | 2 +- .../src/layout/components/Guideline/index.vue | 5 +- .../src/layout/components/Navbar/BackIcon.vue | 2 +- webapp/src/layout/components/index.js | 2 +- webapp/src/layout/index.vue | 5 +- webapp/src/main.js | 5 +- webapp/src/mixins/baseMixin.js | 2 +- webapp/src/mixins/datePickerMixin.js | 2 +- webapp/src/mixins/openNotebookMixin.js | 105 + webapp/src/router/index.js | 38 +- webapp/src/router/modules/atlas.js | 68 + webapp/src/router/modules/cloudserving.js | 92 + webapp/src/router/modules/dashboard.js | 37 + webapp/src/router/modules/data.js | 265 + webapp/src/router/modules/development.js | 56 + webapp/src/router/modules/index.js | 27 + webapp/src/router/modules/model.js | 80 + webapp/src/router/modules/system.js | 80 + webapp/src/router/modules/training.js | 80 + webapp/src/router/routes.js | 2 +- webapp/src/settings.js | 2 +- webapp/src/store/getters.js | 2 + webapp/src/store/modules/Visual/custom.js | 2 +- webapp/src/store/modules/Visual/embedding.js | 2 +- webapp/src/store/modules/Visual/exception.js | 2 +- webapp/src/store/modules/Visual/graph.js | 2 +- webapp/src/store/modules/Visual/hyperparm.js | 2 +- webapp/src/store/modules/Visual/layout.js | 2 +- webapp/src/store/modules/Visual/media.js | 2 +- webapp/src/store/modules/Visual/scalar.js | 2 +- webapp/src/store/modules/Visual/statistic.js | 2 +- webapp/src/store/modules/cloudServing.js | 66 + webapp/src/store/modules/dataset.js | 15 +- webapp/src/store/modules/modelOptimize.js | 46 + webapp/src/utils/VisualUtils/api.js | 2 +- webapp/src/utils/VisualUtils/constants.js | 2 +- webapp/src/utils/VisualUtils/download.js | 2 +- webapp/src/utils/VisualUtils/request.js | 2 +- webapp/src/utils/base.js | 36 +- webapp/src/utils/constant.js | 46 +- webapp/src/utils/download.js | 2 +- webapp/src/utils/event.js | 16 +- webapp/src/utils/index.js | 2 +- webapp/src/utils/minIO.js | 15 +- webapp/src/utils/request.js | 17 +- webapp/src/utils/utils.js | 52 + webapp/src/utils/validate.js | 59 +- webapp/src/views/algorithm/index.vue | 6 +- webapp/src/views/atlas/graphList.vue | 161 + webapp/src/views/atlas/graphVisual.vue | 395 + webapp/src/views/atlas/measure.vue | 339 + webapp/src/views/atlas/util.js | 22 + webapp/src/views/cloudServing/batch.vue | 507 ++ webapp/src/views/cloudServing/batchDetail.vue | 344 + .../components/forms/batchServingForm.vue | 461 ++ .../components/forms/batchUploadDialog.vue | 193 + .../components/forms/servingForm.vue | 332 + .../components/forms/servingModelConfig.vue | 481 ++ .../components/keyValueTable/index.vue | 74 + .../components/modelDetail/index.vue | 127 + .../components/servingCallGuide/index.vue | 145 + .../servingCallGuide/servingApiInfo.vue | 58 + .../servingDeploymentRecord/index.vue | 194 + .../components/servingLog/index.vue | 338 + .../components/servingMonitor/index.vue | 113 + .../servingMonitor/servingMonitorCard.vue | 158 + .../servingMonitorUsageUnit.vue | 85 + .../components/servingPredict/index.vue | 187 + webapp/src/views/cloudServing/detail.vue | 372 + webapp/src/views/cloudServing/formPage.vue | 183 + webapp/src/views/cloudServing/index.vue | 519 ++ webapp/src/views/cloudServing/util.js | 186 + .../views/dashboard/components/CardPanel.vue | 2 +- .../views/dashboard/components/Welcome.vue | 2 +- webapp/src/views/dashboard/dashboard.vue | 2 +- webapp/src/views/dataset/annotate/index.vue | 8 +- .../annotate/settingContainer/annotations.vue | 4 +- .../annotate/settingContainer/editLabel.vue | 2 +- .../annotate/settingContainer/enhance.vue | 2 +- .../annotate/settingContainer/enhanceTip.vue | 2 +- .../annotate/settingContainer/footer.vue | 2 +- .../annotate/settingContainer/index.vue | 5 +- .../annotate/settingContainer/label.vue | 2 +- .../settingContainer/labelList/edit.vue | 4 +- .../settingContainer/labelList/index.vue | 17 +- .../annotate/settingContainer/labelTip.vue | 2 +- .../annotate/settingContainer/selectLabel.vue | 2 +- .../dataset/annotate/thumbContainer/index.vue | 3 +- .../dataset/annotate/thumbContainer/list.vue | 2 +- .../annotate/thumbContainer/listItem.js | 2 +- .../workSpaceContainer/annotationId.js | 2 +- .../annotate/workSpaceContainer/bbox.js | 2 +- .../workSpaceContainer/bboxWrapper.js | 2 +- .../annotate/workSpaceContainer/brushTip.js | 2 +- .../workSpaceContainer/dropdownLabel/index.js | 2 +- .../dropdownLabel/style.scss | 2 +- .../annotate/workSpaceContainer/index.vue | 2 +- .../annotate/workSpaceContainer/score.js | 2 +- .../annotate/workSpaceContainer/tag.js | 2 +- .../annotate/workSpaceContainer/toolbar.vue | 34 +- webapp/src/views/dataset/classify.vue | 67 +- .../dataset/components/picInfoModal/index.vue | 2 +- .../dataset/components/searchLabel/index.vue | 4 +- .../views/dataset/components/tenant/index.vue | 63 + .../components/textInfoModal/index.vue | 227 + webapp/src/views/dataset/entrance.vue | 121 + webapp/src/views/dataset/fork.vue | 39 + webapp/src/views/dataset/list/action.js | 60 +- .../src/views/dataset/list/create-dataset.vue | 220 +- .../src/views/dataset/list/data-enhance.vue | 2 +- .../src/views/dataset/list/edit-dataset.vue | 72 +- .../src/views/dataset/list/import-dataset.vue | 79 +- webapp/src/views/dataset/list/index.vue | 191 +- webapp/src/views/dataset/list/publish.vue | 2 +- webapp/src/views/dataset/list/status.js | 2 +- .../views/dataset/list/upload-datafile.vue | 129 +- webapp/src/views/dataset/medical/action.js | 105 + webapp/src/views/dataset/medical/constant.js | 74 + .../views/dataset/medical/create-dataset.vue | 294 + .../views/dataset/medical/edit-dataset.vue | 127 + .../src/views/dataset/medical/lib/actions.js | 166 + webapp/src/views/dataset/medical/lib/gui.js | 20 + webapp/src/views/dataset/medical/lib/index.js | 271 + .../views/dataset/medical/lib/overlays.json | 22 + webapp/src/views/dataset/medical/list.vue | 650 ++ webapp/src/views/dataset/medical/status.js | 71 + .../views/dataset/medical/viewer/action.vue | 362 + .../views/dataset/medical/viewer/controls.vue | 209 + .../views/dataset/medical/viewer/helpInfo.vue | 118 + .../views/dataset/medical/viewer/index.vue | 780 ++ .../dataset/medical/viewer/infoLayer.vue | 164 + .../dataset/medical/viewer/lesionInfo.vue | 215 + .../views/dataset/medical/viewer/toolbar.vue | 90 + .../dataset/medical/viewer/toolbarButton.vue | 80 + .../dataset/medical/viewer/toolbarItem.js | 67 + .../dataset/medical/viewer/toolbarMore.vue | 181 + .../views/dataset/nlp/annotation/index.vue | 439 ++ .../dataset/nlp/annotation/sidebar/add.vue | 131 + .../dataset/nlp/annotation/sidebar/index.vue | 63 + .../nlp/annotation/sidebar/labelList.vue | 157 + .../nlp/annotation/workspace/index.vue | 158 + .../views/dataset/nlp/textClassify/action.js | 76 + .../views/dataset/nlp/textClassify/index.vue | 597 ++ .../dataset/nlp/textClassify/textStatus.js | 71 + webapp/src/views/dataset/style/list.scss | 11 +- webapp/src/views/dataset/util.js | 111 +- webapp/src/views/dataset/version/actions.vue | 16 +- webapp/src/views/dataset/version/index.vue | 2 +- .../development/components/CreateDialog.vue | 110 +- .../development/components/NotebookDetail.vue | 2 +- webapp/src/views/development/notebook.vue | 21 +- webapp/src/views/home/imagePublic.vue | 2 +- webapp/src/views/home/index.vue | 2 +- webapp/src/views/labelGroup/dynamicField.vue | 41 +- webapp/src/views/labelGroup/index.vue | 58 +- .../src/views/labelGroup/labelGroupAction.js | 2 +- .../src/views/labelGroup/labelGroupForm.vue | 68 +- webapp/src/views/labelGroup/util.js | 25 + webapp/src/views/login.vue | 2 +- .../views/model/components/addModelDialog.vue | 28 +- webapp/src/views/model/index.vue | 63 +- webapp/src/views/model/version.vue | 46 +- .../modelOptimize/components/builtInForm.vue | 233 + .../components/customizeForm.vue | 403 + .../modelOptimize/components/optimizeForm.vue | 268 + .../components/optimizeResult.vue | 134 + .../components/quickUploadPopover.vue | 216 + .../modelOptimize/components/recordDetail.vue | 114 + webapp/src/views/modelOptimize/index.vue | 408 + webapp/src/views/modelOptimize/record.vue | 527 ++ webapp/src/views/modelOptimize/util.js | 64 + webapp/src/views/register.vue | 2 +- webapp/src/views/resetpassword.vue | 2 +- webapp/src/views/system/menu/index.vue | 265 - webapp/src/views/system/node/index.vue | 2 +- webapp/src/views/system/role/index.vue | 5 +- webapp/src/views/system/user/index.vue | 2 +- webapp/src/views/trainingImage/index.vue | 127 +- webapp/src/views/trainingJob/add.vue | 2 +- .../trainingJob/components/jobDetail.vue | 64 +- .../trainingJob/components/jobDrawer.vue | 38 +- .../components/pathSelectDialog.vue | 5 +- webapp/src/views/trainingJob/detail.vue | 2 +- webapp/src/views/trainingJob/index.vue | 2 +- webapp/src/views/trainingJob/jobList.vue | 2 +- webapp/src/views/trainingJob/jobParam.vue | 2 +- webapp/src/views/trainingJob/utils.js | 16 +- webapp/src/views/user/center.vue | 3 + webapp/src/views/visual/Layout.vue | 2 +- .../views/visual/Visual/customs/Category.vue | 2 +- .../views/visual/Visual/customs/Customs.vue | 2 +- .../visual/Visual/customs/CustomsPanel.vue | 2 +- .../src/views/visual/Visual/customs/index.js | 2 +- .../Visual/embeddings/EmbeddingDraw.vue | 2 +- .../visual/Visual/embeddings/Embeddings.vue | 2 +- .../Visual/embeddings/EmbeddingsPanel.vue | 2 +- .../views/visual/Visual/embeddings/index.js | 2 +- .../visual/Visual/exception/Exception.vue | 2 +- .../Visual/exception/ExceptionPanel.vue | 2 +- .../Visual/exception/excepContainer.vue | 2 +- .../views/visual/Visual/exception/index.js | 2 +- .../views/visual/Visual/features/Features.vue | 2 +- .../visual/Visual/features/FeaturesPanel.vue | 2 +- .../src/views/visual/Visual/features/index.js | 2 +- .../src/views/visual/Visual/graphs/Graphs.vue | 2 +- .../visual/Visual/graphs/GraphsPanel.vue | 2 +- .../src/views/visual/Visual/graphs/index.js | 2 +- .../visual/Visual/hyperparms/HyperPara.vue | 2 +- .../visual/Visual/hyperparms/Hyperparms.vue | 2 +- .../Visual/hyperparms/HyperparmsPanel.vue | 2 +- .../views/visual/Visual/hyperparms/index.js | 2 +- .../src/views/visual/Visual/medias/Medias.vue | 2 +- .../visual/Visual/medias/MediasPanel.vue | 2 +- .../visual/Visual/medias/audio/Audios.vue | 2 +- .../audio/audioContainer/AudioContainer.vue | 2 +- .../medias/audio/audioContainer/index.js | 2 +- .../views/visual/Visual/medias/audio/index.js | 2 +- .../visual/Visual/medias/image/Images.vue | 2 +- .../image/imagecontainer/ImageContainer.vue | 2 +- .../medias/image/imagecontainer/index.js | 2 +- .../views/visual/Visual/medias/image/index.js | 2 +- .../src/views/visual/Visual/medias/index.js | 2 +- .../views/visual/Visual/medias/text/Texts.vue | 2 +- .../views/visual/Visual/medias/text/index.js | 2 +- .../text/textContainer/TextContainer.vue | 2 +- .../Visual/medias/text/textContainer/index.js | 2 +- webapp/src/views/visual/Visual/rocs/ROCs.vue | 2 +- .../views/visual/Visual/rocs/ROCsPanel.vue | 2 +- webapp/src/views/visual/Visual/rocs/index.js | 2 +- .../views/visual/Visual/scalars/Scalars.vue | 2 +- .../visual/Visual/scalars/ScalarsPanel.vue | 2 +- .../src/views/visual/Visual/scalars/index.js | 2 +- .../scalarcontainer/ScalarContainer.vue | 2 +- .../scalars/scalarcontainer/ScalarCustom.vue | 2 +- .../Visual/scalars/scalarcontainer/index.js | 2 +- .../scalarchart/Scalarchart.vue | 2 +- .../scalarcontainer/scalarchart/index.js | 2 +- .../Visual/scalars/subscalar/SubScalars.vue | 2 +- .../visual/Visual/scalars/subscalar/index.js | 2 +- .../visual/Visual/statistics/Statistics.vue | 2 +- .../Visual/statistics/StatisticsPanel.vue | 2 +- .../statistics/drawStatistic/HisOrtho.vue | 2 +- .../statistics/drawStatistic/HisOverlook.vue | 2 +- .../statistics/drawStatistic/HisThreeD.vue | 2 +- .../Visual/statistics/drawStatistic/index.js | 2 +- .../drawStatistic/statisticContainer.vue | 2 +- .../views/visual/Visual/statistics/index.js | 2 +- .../statistics/substatistic/SubStatistics.vue | 2 +- .../Visual/statistics/substatistic/index.js | 2 +- webapp/vue.config.js | 2 - webapp/yarn.lock | 6934 +++++++++-------- 368 files changed, 22682 insertions(+), 4874 deletions(-) delete mode 100644 webapp/mock/api/data/datasets.js create mode 100644 webapp/mock/api/data/datasets/count.js delete mode 100644 webapp/mock/api/data/labelGroup/getList/id.js rename webapp/src/api/{system/menu.js => atlas/index.js} (77%) create mode 100644 webapp/src/api/cloudServing/batch.js create mode 100644 webapp/src/api/cloudServing/index.js create mode 100644 webapp/src/api/modelOptimize/optimize.js rename webapp/src/api/{system/harbor.js => modelOptimize/record.js} (61%) create mode 100644 webapp/src/api/preparation/medical.js create mode 100644 webapp/src/api/preparation/textData.js create mode 100644 webapp/src/assets/images/dataset/medicalDataset.png create mode 100644 webapp/src/assets/images/dataset/normalDataset.png create mode 100644 webapp/src/components/LogContainer/podLogContainer.vue rename webapp/src/{api/dashboard/index.js => components/UploadForm/FileFilter.js} (75%) create mode 100644 webapp/src/components/textEditor.vue create mode 100644 webapp/src/layout/FullpageLayout.vue create mode 100644 webapp/src/mixins/openNotebookMixin.js create mode 100644 webapp/src/router/modules/atlas.js create mode 100644 webapp/src/router/modules/cloudserving.js create mode 100644 webapp/src/router/modules/dashboard.js create mode 100644 webapp/src/router/modules/data.js create mode 100644 webapp/src/router/modules/development.js create mode 100644 webapp/src/router/modules/index.js create mode 100644 webapp/src/router/modules/model.js create mode 100644 webapp/src/router/modules/system.js create mode 100644 webapp/src/router/modules/training.js create mode 100644 webapp/src/store/modules/cloudServing.js create mode 100644 webapp/src/store/modules/modelOptimize.js create mode 100644 webapp/src/views/atlas/graphList.vue create mode 100644 webapp/src/views/atlas/graphVisual.vue create mode 100644 webapp/src/views/atlas/measure.vue create mode 100644 webapp/src/views/atlas/util.js create mode 100644 webapp/src/views/cloudServing/batch.vue create mode 100644 webapp/src/views/cloudServing/batchDetail.vue create mode 100644 webapp/src/views/cloudServing/components/forms/batchServingForm.vue create mode 100644 webapp/src/views/cloudServing/components/forms/batchUploadDialog.vue create mode 100644 webapp/src/views/cloudServing/components/forms/servingForm.vue create mode 100644 webapp/src/views/cloudServing/components/forms/servingModelConfig.vue create mode 100644 webapp/src/views/cloudServing/components/keyValueTable/index.vue create mode 100644 webapp/src/views/cloudServing/components/modelDetail/index.vue create mode 100644 webapp/src/views/cloudServing/components/servingCallGuide/index.vue create mode 100644 webapp/src/views/cloudServing/components/servingCallGuide/servingApiInfo.vue create mode 100644 webapp/src/views/cloudServing/components/servingDeploymentRecord/index.vue create mode 100644 webapp/src/views/cloudServing/components/servingLog/index.vue create mode 100644 webapp/src/views/cloudServing/components/servingMonitor/index.vue create mode 100644 webapp/src/views/cloudServing/components/servingMonitor/servingMonitorCard.vue create mode 100644 webapp/src/views/cloudServing/components/servingMonitor/servingMonitorUsageUnit.vue create mode 100644 webapp/src/views/cloudServing/components/servingPredict/index.vue create mode 100644 webapp/src/views/cloudServing/detail.vue create mode 100644 webapp/src/views/cloudServing/formPage.vue create mode 100644 webapp/src/views/cloudServing/index.vue create mode 100644 webapp/src/views/cloudServing/util.js create mode 100644 webapp/src/views/dataset/components/tenant/index.vue create mode 100644 webapp/src/views/dataset/components/textInfoModal/index.vue create mode 100644 webapp/src/views/dataset/entrance.vue create mode 100644 webapp/src/views/dataset/fork.vue create mode 100644 webapp/src/views/dataset/medical/action.js create mode 100644 webapp/src/views/dataset/medical/constant.js create mode 100644 webapp/src/views/dataset/medical/create-dataset.vue create mode 100644 webapp/src/views/dataset/medical/edit-dataset.vue create mode 100644 webapp/src/views/dataset/medical/lib/actions.js create mode 100644 webapp/src/views/dataset/medical/lib/gui.js create mode 100644 webapp/src/views/dataset/medical/lib/index.js create mode 100644 webapp/src/views/dataset/medical/lib/overlays.json create mode 100644 webapp/src/views/dataset/medical/list.vue create mode 100644 webapp/src/views/dataset/medical/status.js create mode 100644 webapp/src/views/dataset/medical/viewer/action.vue create mode 100644 webapp/src/views/dataset/medical/viewer/controls.vue create mode 100644 webapp/src/views/dataset/medical/viewer/helpInfo.vue create mode 100644 webapp/src/views/dataset/medical/viewer/index.vue create mode 100644 webapp/src/views/dataset/medical/viewer/infoLayer.vue create mode 100644 webapp/src/views/dataset/medical/viewer/lesionInfo.vue create mode 100644 webapp/src/views/dataset/medical/viewer/toolbar.vue create mode 100644 webapp/src/views/dataset/medical/viewer/toolbarButton.vue create mode 100644 webapp/src/views/dataset/medical/viewer/toolbarItem.js create mode 100644 webapp/src/views/dataset/medical/viewer/toolbarMore.vue create mode 100644 webapp/src/views/dataset/nlp/annotation/index.vue create mode 100644 webapp/src/views/dataset/nlp/annotation/sidebar/add.vue create mode 100644 webapp/src/views/dataset/nlp/annotation/sidebar/index.vue create mode 100644 webapp/src/views/dataset/nlp/annotation/sidebar/labelList.vue create mode 100644 webapp/src/views/dataset/nlp/annotation/workspace/index.vue create mode 100644 webapp/src/views/dataset/nlp/textClassify/action.js create mode 100644 webapp/src/views/dataset/nlp/textClassify/index.vue create mode 100644 webapp/src/views/dataset/nlp/textClassify/textStatus.js create mode 100644 webapp/src/views/labelGroup/util.js create mode 100644 webapp/src/views/modelOptimize/components/builtInForm.vue create mode 100644 webapp/src/views/modelOptimize/components/customizeForm.vue create mode 100644 webapp/src/views/modelOptimize/components/optimizeForm.vue create mode 100644 webapp/src/views/modelOptimize/components/optimizeResult.vue create mode 100644 webapp/src/views/modelOptimize/components/quickUploadPopover.vue create mode 100644 webapp/src/views/modelOptimize/components/recordDetail.vue create mode 100644 webapp/src/views/modelOptimize/index.vue create mode 100644 webapp/src/views/modelOptimize/record.vue create mode 100644 webapp/src/views/modelOptimize/util.js delete mode 100644 webapp/src/views/system/menu/index.vue diff --git a/webapp/.env.development b/webapp/.env.development index 702f9a5..bcbbe28 100644 --- a/webapp/.env.development +++ b/webapp/.env.development @@ -3,11 +3,24 @@ ENV = 'development' # 默认BASE URL VUE_APP_BASE_API = '' -# 数据管理 -VUE_APP_DATA_API = '' - # minio -VUE_APP_MINIO_API = '' // 建议使用与当前 web 服务域名的域名 +VUE_APP_MINIO_API = 'http://{HOST}/minio' -# atlas 模型炼知 +# atlas 服务,需要单独部署 VUE_APP_ATLAS_HOST = '' + +# 医疗影像 DCM4CHEE 服务访问地址 +# 部署文档参考:http://docs.dubhe.ai/docs/setup/deploy-algorithm +VUE_APP_DCM_API = 'http://{HOST}/dcm4chee/dcm4chee-arc/aets/DCM4CHEE_ADMIN' + +# minIO 服务 IP +VUE_APP_MINIO_ENDPOINT = '' + +# minIO 服务 端口 +VUE_APP_MINIO_PORT = '9000' + +# 是否开启 SSL +VUE_APP_MINIO_USESSL = 'false' + +# bucketName +VUE_APP_MINIO_BUCKETNAME = 'dubhe-dev' diff --git a/webapp/.env.mock b/webapp/.env.mock index f913c6a..dadee4d 100644 --- a/webapp/.env.mock +++ b/webapp/.env.mock @@ -1,4 +1,22 @@ ENV='development' + +# 开启 mock 模式 VUE_APP_MOCK=true -VUE_APP_BASE_API = '' -VUE_APP_DATA_API = '/mock' + +# 默认BASE URL,需要自行配置 +VUE_APP_BASE_API = '/mock' + +# 用户 minio 访问地址 +VUE_APP_MINIO_API = 'http://{HOST}/minio' + +# minIO 服务 IP +VUE_APP_MINIO_ENDPOINT = '' + +# minIO 服务 端口 +VUE_APP_MINIO_PORT = '9000' + +# 是否开启 SSL +VUE_APP_MINIO_USESSL = 'false' + +# bucketName +VUE_APP_MINIO_BUCKETNAME = 'dubhe-dev' diff --git a/webapp/.env.production b/webapp/.env.production index bf67105..8df70ee 100644 --- a/webapp/.env.production +++ b/webapp/.env.production @@ -1,13 +1,27 @@ ENV = 'production' -# 默认BASE URL -VUE_APP_BASE_API = '/' +# 默认BASE URL, 后端服务地址 +VUE_APP_BASE_API = 'http://127.0.0.1:8000' -# 数据管理 -VUE_APP_DATA_API = '/' +# 用户 minio 访问地址 +VUE_APP_MINIO_API = 'http://{HOST}/minio' -# minio -VUE_APP_MINIO_API = '' +# atlas 服务,需要单独部署 +VUE_APP_ATLAS_HOST = 'http://127.0.0.1:8000' -# atlas -VUE_APP_ATLAS_HOST = '' +# 医疗影像 DCM4CHEE 服务访问地址 +# 部署文档参考:http://docs.dubhe.ai/docs/setup/deploy-algorithm +VUE_APP_DCM_API = 'http://{HOST}/dcm4chee/dcm4chee-arc/aets/DCM4CHEE_ADMIN' + +# minIO 服务 IP +# 部署文档参考:http://docs.dubhe.ai/docs/setup/deploy-minio +VUE_APP_MINIO_ENDPOINT = '{IP}' + +# minIO 服务 端口 +VUE_APP_MINIO_PORT = '9000' + +# 是否开启 SSL +VUE_APP_MINIO_USESSL = 'false' + +# bucketName +VUE_APP_MINIO_BUCKETNAME = 'dubhe-prod' diff --git a/webapp/.env.test b/webapp/.env.test index 5fa6d82..f4d80b0 100644 --- a/webapp/.env.test +++ b/webapp/.env.test @@ -3,11 +3,25 @@ ENV = 'test' # 默认BASE URL VUE_APP_BASE_API = '' -# 数据管理 -VUE_APP_DATA_API = '' - -# minio +# 用户 minio 访问地址 VUE_APP_MINIO_API = '' -# atlas +# atlas 服务,需要单独部署 VUE_APP_ATLAS_HOST = '' + +# 医疗影像 DCM4CHEE 服务访问地址 +# 部署文档参考:http://docs.dubhe.ai/docs/setup/deploy-algorithm +VUE_APP_DCM_API = 'http://{HOST}/dcm4chee/dcm4chee-arc/aets/DCM4CHEE_ADMIN' + +# minIO 服务 IP +VUE_APP_MINIO_ENDPOINT = '' + +# minIO 服务 端口 +VUE_APP_MINIO_PORT = '9000' + +# 是否开启 SSL +VUE_APP_MINIO_USESSL = 'false' + +# BucketName +VUE_APP_MINIO_BUCKETNAME = 'dubhe-test' + diff --git a/webapp/CHANGELOG.md b/webapp/CHANGELOG.md index b01e4c4..884d08e 100644 --- a/webapp/CHANGELOG.md +++ b/webapp/CHANGELOG.md @@ -1,3 +1,28 @@ +## 0.3.0 (2021-01-14) + +### Breaking Change + +- [模型管理] 完成内置优化、我的优化功能,支持模型量化、剪枝、蒸馏 +- [云端Serving] 完成在线服务、批量服务功能,在线服务支持 HTTP 请求、GRPC 请求、灰度分流、服务回滚 +- [模型炼知] 移植重构图谱可视化、图谱列表功能,完成度量管理功能 + +### Features + +- 路由迁移到本地管理,移除在线「菜单管理」页面 +- MinIO 配置更新 +- [数据管理] 增加 NLP 文本分类数据标注功能 +- [数据管理] 增加医疗影像数据标注,支持自动器官分割和病灶识别 +- [训练管理] 支持使用教师模型、学生模型进行模型炼知 +- [训练管理] 镜像管理支持管理员上传Notebook镜像, 并可以设置为默认Notebook镜像 +- [训练管理] 模型、算法、镜像等文件上传时不允许文件名包含不合法字符 +- [训练管理] 运行日志展示组件重构。以 K8S 的 pod 为单位进行日志查询展示 +- [模型管理] 增加炼知模型管理 + +### Bug Fixs + +- [模型开发] 修复 Notebook 页面重置按钮失效的问题 +- [训练管理] 修复模型下载文件路径问题 + ## 0.2.1 (2020-11-16) ### Features diff --git a/webapp/README.md b/webapp/README.md index 5eddbc3..ffa07e5 100644 --- a/webapp/README.md +++ b/webapp/README.md @@ -26,8 +26,9 @@ cd dubhe-web 根据需要修改如下配置文件 ``` -config/index.js -settings.js +.env.mock +.env.development +.env.test .env.production ``` diff --git a/webapp/mock/api/data/datasets.js b/webapp/mock/api/data/datasets.js deleted file mode 100644 index 0a90cac..0000000 --- a/webapp/mock/api/data/datasets.js +++ /dev/null @@ -1,56 +0,0 @@ -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/datasets/count.js b/webapp/mock/api/data/datasets/count.js new file mode 100644 index 0000000..8483a4d --- /dev/null +++ b/webapp/mock/api/data/datasets/count.js @@ -0,0 +1,8 @@ +module.exports = { + code: 200, + msg: null, + data: { + "finished": 10, + "unfinished": 0 + } +} \ No newline at end of file diff --git a/webapp/mock/api/data/labelGroup/getList/id.js b/webapp/mock/api/data/labelGroup/getList/id.js deleted file mode 100644 index 0a68b30..0000000 --- a/webapp/mock/api/data/labelGroup/getList/id.js +++ /dev/null @@ -1,5 +0,0 @@ -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 index ee14253..383afe6 100644 --- a/webapp/mock/mock-map.js +++ b/webapp/mock/mock-map.js @@ -1,4 +1,4 @@ // 定义 RESTful 接口和实际代码的映射 module.exports = { - 'GET::/api/data/labelGroup/getList/(\\d+)': '/api/data/labelGroup/getList/id', + 'GET::/api/data/datasets/(\\d+)/count': 'api/data/datasets/count', }; diff --git a/webapp/package.json b/webapp/package.json index 5604797..5ff6c1e 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,6 +1,6 @@ { "name": "dubhe-web", - "version": "0.2.1", + "version": "0.3.0", "description": "之江天枢人工智能开源平台", "author": "zhejianglab", "keywords": [ @@ -41,15 +41,19 @@ "@riophae/vue-treeselect": "0.1.0", "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", "@vue/composition-api": "^0.5.0", + "@wulucxy/dwv": "0.28.1-beta.9", "add-dom-event-listener": "^1.1.0", "axios": "0.18.1", "chroma-js": "^2.1.0", "classnames": "^2.2.6", + "clipboard": "^2.0.6", "d3": "^5.16.0", "d3-selection": "^1.4.1", "d3-zoom": "^1.8.3", "dagre-d3": "^0.6.4", "date-fns": "^2.13.0", + "dicom-parser": "^1.8.7", + "dicomweb-client": "^0.6.0", "echarts": "4.2.1", "echarts-gl": "^1.1.1", "element-ui": "2.13.2", @@ -59,18 +63,21 @@ "jquery-contextmenu": "^2.9.1", "js-beautify": "^1.13.0", "js-cookie": "2.2.0", + "jschardet": "^2.2.1", "jsencrypt": "^3.0.0-rc.1", "json2csv": "^5.0.1", "lodash": "^4.17.15", - "minio": "^7.0.16", + "minio": "7.0.16", "nanoid": "^3.1.3", "normalize.css": "7.0.0", "nprogress": "0.2.0", "p-map": "^4.0.0", "path-to-regexp": "^6.2.0", + "portal-vue": "^2.1.7", "prismjs": "^1.20.0", "promise.allsettled": "^1.0.2", "qs": "^6.9.1", + "screenfull": "^5.0.2", "stream-to-array": "^2.3.0", "streamsaver": "^2.0.4", "v-click-outside": "^3.0.1", diff --git a/webapp/src/App.vue b/webapp/src/App.vue index 3cf15e0..b67cdaa 100644 --- a/webapp/src/App.vue +++ b/webapp/src/App.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ diff --git a/webapp/src/api/algorithm/algorithm.js b/webapp/src/api/algorithm/algorithm.js index 26732d3..5f9ea71 100644 --- a/webapp/src/api/algorithm/algorithm.js +++ b/webapp/src/api/algorithm/algorithm.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,14 +48,6 @@ export function del(ids) { }); } -export function listImage(params) { - return request({ - url: 'api/v1/ptImage', - method: 'get', - params, - }); -} - export function myAlgorithmCount() { return request({ url: `api/v1/algorithm/myAlgorithmCount`, @@ -63,4 +55,4 @@ export function myAlgorithmCount() { }); } -export default { list, add, del, listImage }; +export default { list, add, del }; diff --git a/webapp/src/api/algorithm/algorithmUsage.js b/webapp/src/api/algorithm/algorithmUsage.js index 83c6fc1..55a7736 100644 --- a/webapp/src/api/algorithm/algorithmUsage.js +++ b/webapp/src/api/algorithm/algorithmUsage.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/system/menu.js b/webapp/src/api/atlas/index.js similarity index 77% rename from webapp/src/api/system/menu.js rename to webapp/src/api/atlas/index.js index e42020c..cbd42a6 100644 --- a/webapp/src/api/system/menu.js +++ b/webapp/src/api/atlas/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,18 +14,12 @@ * ============================================================= */ +/* eslint-disable no-unreachable */ import request from '@/utils/request'; -export function getMenusTree() { - return request({ - url: 'api/v1/menus/tree', - method: 'get', - }); -} - export function list(params) { return request({ - url: 'api/v1/menus', + url: 'api/v1/ptMeasure', method: 'get', params, }); @@ -33,26 +27,32 @@ export function list(params) { export function add(data) { return request({ - url: 'api/v1/menus', + url: 'api/v1/ptMeasure', method: 'post', data, }); } +export function edit(data) { + return request({ + url: 'api/v1/ptMeasure', + method: 'put', + data, + }); +} + export function del(ids) { return request({ - url: 'api/v1/menus', + url: 'api/v1/ptMeasure', method: 'delete', data: { ids }, }); } -export function edit(data) { +export function getGraphs(name) { return request({ - url: 'api/v1/menus', - method: 'put', - data, + url: 'api/v1/ptMeasure/byName', + method: 'get', + params: { name }, }); } - -export default { list, add, edit, del, getMenusTree }; diff --git a/webapp/src/api/auth.js b/webapp/src/api/auth.js index baafe9c..56f9ad4 100644 --- a/webapp/src/api/auth.js +++ b/webapp/src/api/auth.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/cloudServing/batch.js b/webapp/src/api/cloudServing/batch.js new file mode 100644 index 0000000..6529123 --- /dev/null +++ b/webapp/src/api/cloudServing/batch.js @@ -0,0 +1,89 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +import request from '@/utils/request'; + +export function list(params) { + return request({ + url: 'api/batchServing', + method: 'get', + params, + }); +} + +export function add(data) { + return request({ + url: 'api/batchServing', + method: 'post', + data, + }); +} + +export function edit(data) { + return request({ + url: 'api/batchServing', + method: 'put', + data, + }); +} + +export function del(id) { + return request({ + url: `api/batchServing`, + method: 'delete', + data: { id }, + }); +} + +export function detail(id) { + return request({ + url: `api/batchServing/detail`, + method: 'get', + params: { id }, + }); +} + +export function start(id) { + return request({ + url: `api/batchServing/start`, + method: 'post', + data: { id }, + }); +} + +export function stop(id) { + return request({ + url: `api/batchServing/stop`, + method: 'post', + data: { id }, + }); +} + +export function getBatchServingPods(id) { + return request({ + url: `api/batchServing/pod/${id}`, + method: 'get', + }); +} + +export function getServiceProgress(id) { + return request({ + url: `api/batchServing/queryById/${id}`, + method: 'get', + }); +} + +export default { list, add, edit, del }; diff --git a/webapp/src/api/cloudServing/index.js b/webapp/src/api/cloudServing/index.js new file mode 100644 index 0000000..1267b68 --- /dev/null +++ b/webapp/src/api/cloudServing/index.js @@ -0,0 +1,114 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +import request from '@/utils/request'; + +export function list(params) { + return request({ + url: 'api/serving', + method: 'get', + params, + }); +} + +export function add(data) { + return request({ + url: 'api/serving', + method: 'post', + data, + }); +} + +export function edit(data) { + return request({ + url: 'api/serving', + method: 'put', + data, + }); +} + +export function del(id) { + return request({ + url: `api/serving`, + method: 'delete', + data: { id }, + }); +} + +export function detail(id) { + return request({ + url: `api/serving/detail`, + method: 'get', + params: { id }, + }); +} + +export function start(id) { + return request({ + url: `api/serving/start`, + method: 'post', + data: { id }, + }); +} + +export function stop(id) { + return request({ + url: `api/serving/stop`, + method: 'post', + data: { id }, + }); +} + +export function getPredictParam(id) { + return request({ + url: `api/serving/predictParam`, + method: 'get', + params: { id }, + }); +} + +export function getMetrics(id) { + return request({ + url: `api/serving/metrics/${id}`, + method: 'get', + }); +} + +export function getServingPods(configId) { + return request({ + url: `api/serving/servingConfig/pod/${configId}`, + method: 'get', + }); +} + +export function getRollbackList(servingId) { + return request({ + url: `api/serving/rollback/${servingId}`, + method: 'get', + }); +} + +export function predict(data, params) { + return request({ + url: `api/serving/predict`, + method: 'post', + headers: { 'Content-Type': 'multipart/form-data' }, + params, + data, + }); +} + +export default { list, add, edit, del }; diff --git a/webapp/src/api/development/notebook.js b/webapp/src/api/development/notebook.js index a6a3d55..8a62af2 100644 --- a/webapp/src/api/development/notebook.js +++ b/webapp/src/api/development/notebook.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/model/model.js b/webapp/src/api/model/model.js index 02f02ad..04771f5 100644 --- a/webapp/src/api/model/model.js +++ b/webapp/src/api/model/model.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,4 +48,12 @@ export function del(data) { }); } +export function getModelByResource(modelResource) { + return request({ + url: 'api/ptModelInfo/byResource', + method: 'get', + params: { modelResource }, + }); +} + export default { list, add, edit, del }; diff --git a/webapp/src/api/model/modelVersion.js b/webapp/src/api/model/modelVersion.js index 7555930..0b25754 100644 --- a/webapp/src/api/model/modelVersion.js +++ b/webapp/src/api/model/modelVersion.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/modelOptimize/optimize.js b/webapp/src/api/modelOptimize/optimize.js new file mode 100644 index 0000000..42d3242 --- /dev/null +++ b/webapp/src/api/modelOptimize/optimize.js @@ -0,0 +1,107 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +import request from '@/utils/request'; + +export function list(params) { + return request({ + url: 'api/modelOpt/task', + method: 'get', + params, + }); +} + +export function add(data) { + return request({ + url: 'api/modelOpt/task', + method: 'post', + data, + }); +} + +export function edit(data) { + return request({ + url: 'api/modelOpt/task', + method: 'put', + data, + }); +} + +export function del(data) { + return request({ + url: `api/modelOpt/task`, + method: 'delete', + data, + }); +} + +export function getOptimizeAlgorithms(params) { + return request({ + url: 'api/modelOpt/task/getAlgorithm', + method: 'get', + params, + }); +} + +export function getBuiltInModel(params) { + return request({ + url: 'api/modelOpt/task/getBuiltInModel', + method: 'get', + params, + }); +} + +export function getOptimizeDatasets(params) { + return request({ + url: 'api/modelOpt/task/getDataset', + method: 'get', + params, + }); +} + +export function getCustomizeDatasets(params) { + return request({ + url: 'api/modelOpt/task/MyDataset', + method: 'get', + params, + }); +} + +export function addCustomizeDatasets(data) { + return request({ + url: 'api/modelOpt/task/MyDataset', + method: 'post', + data, + }); +} + +export function addCustomizeModel(data) { + return request({ + url: 'api/ptModelInfo/uploadModel', + method: 'post', + data, + }); +} + +export function submit(data) { + return request({ + url: `api/modelOpt/task/submit`, + method: 'post', + data, + }); +} + +export default { list, add, edit, del }; diff --git a/webapp/src/api/system/harbor.js b/webapp/src/api/modelOptimize/record.js similarity index 61% rename from webapp/src/api/system/harbor.js rename to webapp/src/api/modelOptimize/record.js index 15fe6ce..fae4a12 100644 --- a/webapp/src/api/system/harbor.js +++ b/webapp/src/api/modelOptimize/record.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,40 +16,42 @@ import request from '@/utils/request'; -export function harborProjectNames() { +export function list(params) { return request({ - url: `api/v1/ptImage/imageNameList`, + url: 'api/modelOpt/taskInstance', method: 'get', + params, }); } -export function harborImageNames(params) { +export function del(data) { return request({ - url: `api/v1/ptImage`, - method: 'get', - params, + url: `api/modelOpt/taskInstance`, + method: 'delete', + data, }); } -export function harborProjects(source = 0) { +export function getInstance(params) { return request({ - url: `api/v1/harbor/projects/${source}`, + url: `api/modelOpt/taskInstance/detail`, method: 'get', + params, }); } -export function harborImages(params) { +export function cancel(data) { return request({ - url: `api/v1/harbor/images`, - method: 'get', - params, + url: `api/modelOpt/taskInstance/cancel`, + method: 'put', + data, }); } -export function allImages(params) { +export function resubmit(data) { return request({ - url: `api/v1/harbor/image_page`, - method: 'get', - params, + url: `api/modelOpt/taskInstance/resubmit`, + method: 'post', + data, }); } diff --git a/webapp/src/api/preparation/annotation.js b/webapp/src/api/preparation/annotation.js index 5edc191..0a73a4a 100644 --- a/webapp/src/api/preparation/annotation.js +++ b/webapp/src/api/preparation/annotation.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/preparation/datafile.js b/webapp/src/api/preparation/datafile.js index 1f224bb..9af5703 100644 --- a/webapp/src/api/preparation/datafile.js +++ b/webapp/src/api/preparation/datafile.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/preparation/datalabel.js b/webapp/src/api/preparation/datalabel.js index 390b051..4e95849 100644 --- a/webapp/src/api/preparation/datalabel.js +++ b/webapp/src/api/preparation/datalabel.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,9 +39,9 @@ export function editLabel(id, label) { }); } -export function getAutoLabels() { +export function getAutoLabels(labelGroupType) { return request({ - url: 'api/data/datasets/labels/auto', + url: `api/data/datasets/labels/auto/${labelGroupType}`, method: 'get', }); } diff --git a/webapp/src/api/preparation/dataset.js b/webapp/src/api/preparation/dataset.js index 02eca08..eedd085 100644 --- a/webapp/src/api/preparation/dataset.js +++ b/webapp/src/api/preparation/dataset.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -139,6 +139,24 @@ export function queryFileOffset(datasetId, fileId, query = {}) { }); } +// 查询数据集标签 +export function queryLabels(datasetId, params) { + return request({ + url: `api/data/datasets/${datasetId}/labels`, + method: 'get', + params, + }); +} + +// 创建数据集标签 +export function createLabel (datasetId, data) { + return request({ + url: `api/data/datasets/${datasetId}/labels`, + method: 'post', + data, + }); +} + // 查询预置标签 export function queryPresetLabels() { return request({ @@ -150,7 +168,7 @@ export function queryPresetLabels() { // 查询数据增强字典 export function queryDataEnhanceList() { return request({ - baseURL: process.env.VUE_APP_DATA_API, + baseURL: process.env.VUE_APP_BASE_API, url: `api/v1/user/dict/dataset_enhance`, method: 'get', }); diff --git a/webapp/src/api/preparation/labelGroup.js b/webapp/src/api/preparation/labelGroup.js index 0a6e172..1da5cfd 100644 --- a/webapp/src/api/preparation/labelGroup.js +++ b/webapp/src/api/preparation/labelGroup.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,8 +64,9 @@ export function list(params) { // 标签组列表的简况查询 用于详情页选择标签组列举 export function getLabelGroupList(params) { return request({ - url: `/api/data/labelGroup/getList/${params}`, + url: `/api/data/labelGroup/getList`, method: 'get', + params, }); } diff --git a/webapp/src/api/preparation/medical.js b/webapp/src/api/preparation/medical.js new file mode 100644 index 0000000..d1d4282 --- /dev/null +++ b/webapp/src/api/preparation/medical.js @@ -0,0 +1,170 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +import request from '@/utils/request'; + +// 获取数据集对应的 studyInstanceUID 和 seriesInstanceUID +export function getCaseInfo(datasetId) { + return request({ + url: `api/data/datasets/medical/detail/${datasetId}`, + method: 'get', + }); +} + +// 获取自动标注详情 +export const queryAutoResult = (datasetId) => { + return request({ + url: `api/data/datasets/medical/getAuto/${datasetId}`, + method: 'get', + }); +}; + +// 获取手动标注详情 +export const queryManualResult = (datasetId) => { + return request({ + url: `api/data/datasets/medical/getFinished/${datasetId}`, + method: 'get', + }); +}; + +export function list(params) { + return request({ + url: '/api/data/datasets/medical', + method: 'get', + params, + }); +} + +// 数据集详情 +export function detail(id) { + return request({ + url: `/api/data/datasets/medical/${id}`, + method: 'get', + }); +} + +// 创建数据集 +export function add(data) { + return request({ + url: 'api/data/datasets/medical', + method: 'post', + data, + }); +} + +// 保存标注 +export function save(data) { + return request({ + url: '/api/data/datasets/medical/annotation/save', + method: 'post', + data, + }); +} + +// 上传文件 +export function upload(datasetId, params) { + return request({ + url: '/api/data/datasets/medical/files', + method: 'post', + data: { + id: datasetId, + dataMedicineFileCreateList: params, + }, + }); +} + +export function del(ids) { + const delData = { ids }; + return request({ + url: 'api/data/datasets/medical', + method: 'delete', + data: delData, + }); +} + +export function editDataset(data) { + return request({ + url: `api/data/datasets/medical/${data.medicalId}`, + method: 'put', + data, + }); +} + +// 导入自定义数据集 +export function addCustomDataset(data) { + return request({ + url: `api/data/datasets/medical/custom`, + method: 'post', + data, + }); +} + +export function autoAnnotate(id) { + const data = { medicalId: id }; + return request({ + url: 'api/data/datasets/medical/annotation/auto', + method: 'post', + data, + }); +} + +// 查询数据集状态 +export function queryDatasetsProgress(params) { + return request({ + url: `/api/data/datasets/medical/annotation/schedule`, + method: 'get', + params, + }); +} + +// 保存病灶信息 +export function saveLesions(medicalId, data) { + return request({ + url: `/api/data/datasets/medical/lesion/${medicalId}`, + method: 'post', + data, + }); +} + +// 查询病灶信息 +export function queryLesions(medicalId, params) { + return request({ + url: `/api/data/datasets/medical/lesion/${medicalId}`, + method: 'get', + params, + }); +} + +// 删除病灶信息 +export function deleteLesion(id) { + return request({ + url: `/api/data/datasets/medical/lesion`, + method: 'delete', + data: { id }, + }); +} + +// 修改病灶信息 +export function updateLesion(id) { + return request({ + url: `/api/data/datasets/medical/lesion`, + method: 'put', + data: { id }, + }); +} + +export default { list, add, del }; + diff --git a/webapp/src/api/preparation/textData.js b/webapp/src/api/preparation/textData.js new file mode 100644 index 0000000..c32ee2c --- /dev/null +++ b/webapp/src/api/preparation/textData.js @@ -0,0 +1,63 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================= + */ + +import request from '@/utils/request'; + +export function list(params) { + const { datasetId } = params; + return request({ + url: `api/data/datasets/${datasetId}/files/txt`, + method: 'get', + params, + }); +} + +export function count(datasetId) { + return request({ + url: `/api/data/datasets/${datasetId}/count`, + }); +} + +// 获取分页信息 +export function queryFiles(datasetId, params) { + return request({ + url: `/api/data/datasets/${datasetId}/files/txt`, + params, + }); +} + +// 删除文件 +export function deleteFile(datasetId, fileId) { + return request({ + url: `/api/data/datasets/files`, + method: 'delete', + data: { + datasetIds: [Number(datasetId)], + fileIds: [Number(fileId)], + }, + }); +} + +// 保存 +export function save(datasetId, fileId, data){ + return request({ + url: `/api/data/datasets/files/${datasetId}/${fileId}/annotations/finish`, + method: 'post', + data, + }); +} + +export default { list }; \ No newline at end of file diff --git a/webapp/src/api/system/dict.js b/webapp/src/api/system/dict.js index 33bf3b4..0bed26f 100644 --- a/webapp/src/api/system/dict.js +++ b/webapp/src/api/system/dict.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/system/dictDetail.js b/webapp/src/api/system/dictDetail.js index 73697d7..55a2f57 100644 --- a/webapp/src/api/system/dictDetail.js +++ b/webapp/src/api/system/dictDetail.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/system/node.js b/webapp/src/api/system/node.js index 39b05a3..f8a2fa5 100644 --- a/webapp/src/api/system/node.js +++ b/webapp/src/api/system/node.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/system/pod.js b/webapp/src/api/system/pod.js index 969d5e8..bf2fb5b 100644 --- a/webapp/src/api/system/pod.js +++ b/webapp/src/api/system/pod.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/system/role.js b/webapp/src/api/system/role.js index 6dfa9d6..bf694cb 100644 --- a/webapp/src/api/system/role.js +++ b/webapp/src/api/system/role.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -71,4 +71,11 @@ export function editMenu(data) { }); } +export function getMenusTree() { + return request({ + url: 'api/v1/menus/tree', + method: 'get', + }); +} + export default { list, add, edit, del, get, editMenu }; diff --git a/webapp/src/api/system/user.js b/webapp/src/api/system/user.js index 4f811f7..d2026b7 100644 --- a/webapp/src/api/system/user.js +++ b/webapp/src/api/system/user.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/trainingImage/index.js b/webapp/src/api/trainingImage/index.js index b04a497..c4f47d2 100644 --- a/webapp/src/api/trainingImage/index.js +++ b/webapp/src/api/trainingImage/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,10 +48,27 @@ export function del(ids) { }); } -export function imageNameList() { +export function getImageNameList(params) { return request({ url: 'api/v1/ptImage/imageNameList', method: 'get', + params, + }); +} + +export function getImageTagList(params) { + return request({ + url: 'api/v1/ptImage', + method: 'get', + params, + }); +} + +export function setPrecast(params) { + return request({ + url: 'api/v1/ptImage/imageResource', + method: 'put', + params, }); } diff --git a/webapp/src/api/trainingJob/job.js b/webapp/src/api/trainingJob/job.js index 08eaf95..5a44e13 100644 --- a/webapp/src/api/trainingJob/job.js +++ b/webapp/src/api/trainingJob/job.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -116,4 +116,12 @@ export function getPods(jobId) { }); } +export function getTrainModel(params) { + return request({ + url: `api/v1/trainJob/model`, + method: 'get', + params, + }); +} + export default { list, add, edit, del }; diff --git a/webapp/src/api/trainingJob/params.js b/webapp/src/api/trainingJob/params.js index 1dd386a..53e7418 100644 --- a/webapp/src/api/trainingJob/params.js +++ b/webapp/src/api/trainingJob/params.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/user.js b/webapp/src/api/user.js index 04085db..50603df 100644 --- a/webapp/src/api/user.js +++ b/webapp/src/api/user.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/api/visual/index.js b/webapp/src/api/visual/index.js index 366f50c..19469b2 100644 --- a/webapp/src/api/visual/index.js +++ b/webapp/src/api/visual/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/assets/images/dataset/medicalDataset.png b/webapp/src/assets/images/dataset/medicalDataset.png new file mode 100644 index 0000000000000000000000000000000000000000..08313c270a059846cce5fe7969f481c689aa8693 GIT binary patch literal 37162 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 literal 0 HcmV?d00001 diff --git a/webapp/src/assets/images/dataset/normalDataset.png b/webapp/src/assets/images/dataset/normalDataset.png new file mode 100644 index 0000000000000000000000000000000000000000..10cc49b3f43f2d5676435fe810476d58085b54ad GIT binary patch literal 28399 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.cancelText} ) } - {this.okText} + { this.showOk && ( + {this.okText} + ) + } ); }; diff --git a/webapp/src/components/Card/info.vue b/webapp/src/components/Card/info.vue index c69dec8..13b3536 100644 --- a/webapp/src/components/Card/info.vue +++ b/webapp/src/components/Card/info.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/Drag/drag.vue b/webapp/src/components/Drag/drag.vue index d1d5da6..cc01dbd 100644 --- a/webapp/src/components/Drag/drag.vue +++ b/webapp/src/components/Drag/drag.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/Drag/index.js b/webapp/src/components/Drag/index.js index 010364e..04547fb 100644 --- a/webapp/src/components/Drag/index.js +++ b/webapp/src/components/Drag/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/DropdownHeader/index.vue b/webapp/src/components/DropdownHeader/index.vue index e613184..9ed71b4 100644 --- a/webapp/src/components/DropdownHeader/index.vue +++ b/webapp/src/components/DropdownHeader/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ {{ title }} - + { diff --git a/webapp/src/components/Exception/index.vue b/webapp/src/components/Exception/index.vue index ccbe530..f9635ee 100644 --- a/webapp/src/components/Exception/index.vue +++ b/webapp/src/components/Exception/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/IconFont/icon.js b/webapp/src/components/IconFont/icon.js index 7a37892..1dcd215 100644 --- a/webapp/src/components/IconFont/icon.js +++ b/webapp/src/components/IconFont/icon.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/IconFont/iconfont.js b/webapp/src/components/IconFont/iconfont.js index 8558d3b..1d981f4 100644 --- a/webapp/src/components/IconFont/iconfont.js +++ b/webapp/src/components/IconFont/iconfont.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/IconFont/index.js b/webapp/src/components/IconFont/index.js index 0070d1a..62bf6ea 100644 --- a/webapp/src/components/IconFont/index.js +++ b/webapp/src/components/IconFont/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ import create from './iconfont'; const IconFont = create({ - scriptUrl: '//at.alicdn.com/t/font_1756495_k4j524i5vng.js', + scriptUrl: '//at.alicdn.com/t/font_1756495_6jl45md8krp.js', extraIconProps: { class: 'svg-icon' }, }); diff --git a/webapp/src/components/IconFont/utils.js b/webapp/src/components/IconFont/utils.js index 36318cf..e1f5122 100644 --- a/webapp/src/components/IconFont/utils.js +++ b/webapp/src/components/IconFont/utils.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/ImageGallery/index.vue b/webapp/src/components/ImageGallery/index.vue index 7023def..558e8b7 100644 --- a/webapp/src/components/ImageGallery/index.vue +++ b/webapp/src/components/ImageGallery/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/InfoSelect/index.js b/webapp/src/components/InfoSelect/index.js index 407fc4d..d226bd7 100644 --- a/webapp/src/components/InfoSelect/index.js +++ b/webapp/src/components/InfoSelect/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/InfoSelect/info-select.vue b/webapp/src/components/InfoSelect/info-select.vue index ac1f972..87c93d7 100644 --- a/webapp/src/components/InfoSelect/info-select.vue +++ b/webapp/src/components/InfoSelect/info-select.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/InfoTable/column.js b/webapp/src/components/InfoTable/column.js index d6acf54..7f8500c 100644 --- a/webapp/src/components/InfoTable/column.js +++ b/webapp/src/components/InfoTable/column.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/InfoTable/index.js b/webapp/src/components/InfoTable/index.js index 8b2f3c7..4edb553 100644 --- a/webapp/src/components/InfoTable/index.js +++ b/webapp/src/components/InfoTable/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/InfoTable/info-table.vue b/webapp/src/components/InfoTable/info-table.vue index 426f206..c52e215 100644 --- a/webapp/src/components/InfoTable/info-table.vue +++ b/webapp/src/components/InfoTable/info-table.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ { if (state.loading) { return; @@ -153,11 +158,17 @@ export default { }; onMounted(() => { - queryList(); - if (typeof actionRef === 'function') { - actionRef().value = { - refresh: queryList, - }; + // 首先判断是否为异步请求 + if(typeof request === 'function') { + queryList(); + if (typeof actionRef === 'function') { + actionRef().value = { + refresh: queryList, + }; + } + } else if(Array.isArray(props.dataSource)) { + // 检测是否为静态数据源 + setData(props.dataSource); } }); @@ -168,6 +179,12 @@ export default { lazy: true, }); + watch(() => props.dataSource, (next) => { + setData(next); + }, { + lazy: true, + }); + watch(() => pageInfo.current, () => { queryList(); }, { diff --git a/webapp/src/components/InlineTableEdit/index.vue b/webapp/src/components/InlineTableEdit/index.vue index e55bfd2..b16b242 100644 --- a/webapp/src/components/InlineTableEdit/index.vue +++ b/webapp/src/components/InlineTableEdit/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@

{{ errors[0] }}

- 取消 + 取消 确定
@@ -97,7 +97,10 @@ export default { if (!success) { return; } - ctx.emit('handleOk', state.value, props.row); + // 判断是否发生过变更 + if(String(state.value) !== String(props.row[valueBy])) { + ctx.emit('handleOk', state.value, props.row); + } handleCancel(); }); }; diff --git a/webapp/src/components/LogContainer/index.vue b/webapp/src/components/LogContainer/index.vue index 6534a34..7c4eaaa 100644 --- a/webapp/src/components/LogContainer/index.vue +++ b/webapp/src/components/LogContainer/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,6 +54,10 @@ export default { type: String, default: '', }, + disabled: { + type: Boolean, + default: false, + }, }, data() { return { @@ -66,7 +70,7 @@ export default { }, computed: { getLogDisabled() { - return this.logLoading || this.noMoreLog; + return this.logLoading || this.noMoreLog || this.disabled; }, logTxt() { return `${this.showMsg ? `${this.msg}\n` : ''}${this.logList.join('\n')}`; diff --git a/webapp/src/components/LogContainer/podLogContainer.vue b/webapp/src/components/LogContainer/podLogContainer.vue new file mode 100644 index 0000000..e257f00 --- /dev/null +++ b/webapp/src/components/LogContainer/podLogContainer.vue @@ -0,0 +1,364 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/components/LoginPublic/index.vue b/webapp/src/components/LoginPublic/index.vue index 286d17e..01a2d3e 100644 --- a/webapp/src/components/LoginPublic/index.vue +++ b/webapp/src/components/LoginPublic/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/Prism/index.vue b/webapp/src/components/Prism/index.vue index 5e12bc7..e3d9827 100644 --- a/webapp/src/components/Prism/index.vue +++ b/webapp/src/components/Prism/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,6 +47,7 @@ export default { code[class*="language-"], pre[class*="language-"] { + word-wrap: break-word; white-space: pre-wrap; } diff --git a/webapp/src/components/SortingMenu/index.vue b/webapp/src/components/SortingMenu/index.vue index f56d2a2..2597117 100644 --- a/webapp/src/components/SortingMenu/index.vue +++ b/webapp/src/components/SortingMenu/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/Training/algorithmDetail.vue b/webapp/src/components/Training/algorithmDetail.vue index d1b9a30..3d3515a 100644 --- a/webapp/src/components/Training/algorithmDetail.vue +++ b/webapp/src/components/Training/algorithmDetail.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,7 +89,7 @@
- 取消 + 取消 确定
diff --git a/webapp/src/components/Training/dataSourceSelector.vue b/webapp/src/components/Training/dataSourceSelector.vue index dd68f69..ea95339 100644 --- a/webapp/src/components/Training/dataSourceSelector.vue +++ b/webapp/src/components/Training/dataSourceSelector.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/components/Training/jobForm.vue b/webapp/src/components/Training/jobForm.vue index 5b80ef1..cbbc9a1 100644 --- a/webapp/src/components/Training/jobForm.vue +++ b/webapp/src/components/Training/jobForm.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,6 @@ id="algorithm_tab_0" :label="1" border - class="mr-0" >我的算法 - + - + - 我的模型 + 我的模型 预训练模型 + 炼知模型 - + + + + + + + + + + + + + + @@ -239,7 +292,6 @@ id="resourcesPoolType_tab_0" :label="0" border - class="mr-0" >CPU -
+
{{ preview }}
@@ -319,8 +371,23 @@ {{ form.imageName }} - - {{ form.modelName }} + + {{ trainModel.name }} + + + {{ teacherModelNames }} + + + {{ studentModelNames }} {{ form.dataSourceName }} @@ -359,7 +426,7 @@ {{ formSpecs && formSpecs.label }} -
+
{{ preview }}
@@ -369,15 +436,25 @@ - diff --git a/webapp/src/config/index.js b/webapp/src/config/index.js index ed79491..7ddf17d 100644 --- a/webapp/src/config/index.js +++ b/webapp/src/config/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,34 +14,6 @@ * ============================================================= */ -// minIO 参数配置 -export const minIO = { - development: { - config: { - endPoint: '', // MinIO 服务地址 - port: 9000, - useSSL: false, - }, - bucketName: 'dubhe-dev', - }, - test: { - config: { - endPoint: '', - port: 9000, - useSSL: false, - }, - bucketName: 'dubhe-test', - }, - production: { - config: { - endPoint: '', - port: 9000, - useSSL: false, - }, - bucketName: 'dubhe-prod', - }, -}; - // 训练管理模块参数配置 export const trainConfig = { trainNodeMax: Infinity, // 分布式训练节点上限 @@ -63,3 +35,13 @@ export const imageConfig = { export const modelConfig = { uploadFileAcceptSize: 0, // 上传模型文件大小限制,单位为 MB,0 表示不限制大小 }; + +// 云端 Serving 模块参数配置 +export const servingConfig = { + onlineServingNodeSumMax: 10, +}; + +// 模型炼知模块参数配置 +export const atlasConfig = { + uploadFileAcceptSize: 5, // 上传度量图文件大小限制,单位为 MB,0 表示不限制大小 +}; diff --git a/webapp/src/directives/index.js b/webapp/src/directives/index.js index ff38453..b021fef 100644 --- a/webapp/src/directives/index.js +++ b/webapp/src/directives/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/directives/modules/clickOnce.js b/webapp/src/directives/modules/clickOnce.js index 69d91d2..5470b85 100644 --- a/webapp/src/directives/modules/clickOnce.js +++ b/webapp/src/directives/modules/clickOnce.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/directives/modules/elSelectLoadMore.js b/webapp/src/directives/modules/elSelectLoadMore.js index 2263623..213918a 100644 --- a/webapp/src/directives/modules/elSelectLoadMore.js +++ b/webapp/src/directives/modules/elSelectLoadMore.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/directives/modules/mouseWheel.js b/webapp/src/directives/modules/mouseWheel.js index 821da0f..0c3fc7a 100644 --- a/webapp/src/directives/modules/mouseWheel.js +++ b/webapp/src/directives/modules/mouseWheel.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/brush/BasicBrush.js b/webapp/src/hooks/brush/BasicBrush.js index 145df66..b8c8368 100644 --- a/webapp/src/hooks/brush/BasicBrush.js +++ b/webapp/src/hooks/brush/BasicBrush.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/brush/index.js b/webapp/src/hooks/brush/index.js index 5c26d1f..e1807f0 100644 --- a/webapp/src/hooks/brush/index.js +++ b/webapp/src/hooks/brush/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/brush/useBrush.js b/webapp/src/hooks/brush/useBrush.js index 567d1e8..14c808c 100644 --- a/webapp/src/hooks/brush/useBrush.js +++ b/webapp/src/hooks/brush/useBrush.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/image/index.js b/webapp/src/hooks/image/index.js index 7f1c653..c08743f 100644 --- a/webapp/src/hooks/image/index.js +++ b/webapp/src/hooks/image/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/index.js b/webapp/src/hooks/index.js index 608d457..3780386 100644 --- a/webapp/src/hooks/index.js +++ b/webapp/src/hooks/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/tooltip/BasicTooltip.js b/webapp/src/hooks/tooltip/BasicTooltip.js index c6f1612..113acef 100644 --- a/webapp/src/hooks/tooltip/BasicTooltip.js +++ b/webapp/src/hooks/tooltip/BasicTooltip.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/tooltip/TooltipContainer.js b/webapp/src/hooks/tooltip/TooltipContainer.js index 6e0757b..eaff85f 100644 --- a/webapp/src/hooks/tooltip/TooltipContainer.js +++ b/webapp/src/hooks/tooltip/TooltipContainer.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/tooltip/index.js b/webapp/src/hooks/tooltip/index.js index c13eaca..a13ca3c 100644 --- a/webapp/src/hooks/tooltip/index.js +++ b/webapp/src/hooks/tooltip/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/tooltip/style.scss b/webapp/src/hooks/tooltip/style.scss index f92c152..5f65c8f 100644 --- a/webapp/src/hooks/tooltip/style.scss +++ b/webapp/src/hooks/tooltip/style.scss @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/tooltip/tableTooltip.js b/webapp/src/hooks/tooltip/tableTooltip.js index ea61721..a2d5fb6 100644 --- a/webapp/src/hooks/tooltip/tableTooltip.js +++ b/webapp/src/hooks/tooltip/tableTooltip.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,9 +33,6 @@ export default { type: [Array, Object], required: true, }, - annotateType: { - type: Number, - }, className: { type: String, }, @@ -57,7 +54,7 @@ export default { }, render(h, context) { const { props } = context; - const { className, keys, title, colorScale, keyAccessor, valueAccessor, showIcon, data, annotateType } = props; + const { className, keys, title, colorScale, keyAccessor, valueAccessor, showIcon, data } = props; if (!keys.length) return null; const klass = cx('tt-wrapper', { [className]: !!className, @@ -72,9 +69,6 @@ export default { backgroundColor: colorScale ? colorScale(key) : '', }, }; - if(annotateType !== 5 && idx === 3 ) { - return null; - } return (
diff --git a/webapp/src/hooks/tooltip/useTooltip.js b/webapp/src/hooks/tooltip/useTooltip.js index ddee345..f991afa 100644 --- a/webapp/src/hooks/tooltip/useTooltip.js +++ b/webapp/src/hooks/tooltip/useTooltip.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/utils.js b/webapp/src/hooks/utils.js index 5bff321..69e8f8e 100644 --- a/webapp/src/hooks/utils.js +++ b/webapp/src/hooks/utils.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/zoom/index.js b/webapp/src/hooks/zoom/index.js index 2604ab8..f85fd38 100644 --- a/webapp/src/hooks/zoom/index.js +++ b/webapp/src/hooks/zoom/index.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/hooks/zoom/useZoom.js b/webapp/src/hooks/zoom/useZoom.js index e655ab8..756ffc6 100644 --- a/webapp/src/hooks/zoom/useZoom.js +++ b/webapp/src/hooks/zoom/useZoom.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/layout/BaseLayout.vue b/webapp/src/layout/BaseLayout.vue index 9ebc7df..0b0d1a5 100644 --- a/webapp/src/layout/BaseLayout.vue +++ b/webapp/src/layout/BaseLayout.vue @@ -19,7 +19,7 @@
-
+
+ + diff --git a/webapp/src/views/atlas/graphVisual.vue b/webapp/src/views/atlas/graphVisual.vue new file mode 100644 index 0000000..3c32966 --- /dev/null +++ b/webapp/src/views/atlas/graphVisual.vue @@ -0,0 +1,395 @@ + + + + + + + \ No newline at end of file diff --git a/webapp/src/views/atlas/measure.vue b/webapp/src/views/atlas/measure.vue new file mode 100644 index 0000000..92c6d17 --- /dev/null +++ b/webapp/src/views/atlas/measure.vue @@ -0,0 +1,339 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/atlas/util.js b/webapp/src/views/atlas/util.js new file mode 100644 index 0000000..7bee32b --- /dev/null +++ b/webapp/src/views/atlas/util.js @@ -0,0 +1,22 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +export const ERROR_MSG = { + NO_NODES: '度量图中不存在节点信息,请检查后重试', + NO_EDGES: '度量图中不存在边信息,请检查后重试', + NODES_NOT_ARRAY: '度量图中的节点信息结构错误,请检查后重试', + EDGES_NOT_ARRAY: '度量图中的边信息结构错误,请检查后重试', +}; diff --git a/webapp/src/views/cloudServing/batch.vue b/webapp/src/views/cloudServing/batch.vue new file mode 100644 index 0000000..5de0564 --- /dev/null +++ b/webapp/src/views/cloudServing/batch.vue @@ -0,0 +1,507 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/batchDetail.vue b/webapp/src/views/cloudServing/batchDetail.vue new file mode 100644 index 0000000..5c4eb33 --- /dev/null +++ b/webapp/src/views/cloudServing/batchDetail.vue @@ -0,0 +1,344 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/forms/batchServingForm.vue b/webapp/src/views/cloudServing/components/forms/batchServingForm.vue new file mode 100644 index 0000000..1483909 --- /dev/null +++ b/webapp/src/views/cloudServing/components/forms/batchServingForm.vue @@ -0,0 +1,461 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/cloudServing/components/forms/batchUploadDialog.vue b/webapp/src/views/cloudServing/components/forms/batchUploadDialog.vue new file mode 100644 index 0000000..b839b65 --- /dev/null +++ b/webapp/src/views/cloudServing/components/forms/batchUploadDialog.vue @@ -0,0 +1,193 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/forms/servingForm.vue b/webapp/src/views/cloudServing/components/forms/servingForm.vue new file mode 100644 index 0000000..c903d24 --- /dev/null +++ b/webapp/src/views/cloudServing/components/forms/servingForm.vue @@ -0,0 +1,332 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/forms/servingModelConfig.vue b/webapp/src/views/cloudServing/components/forms/servingModelConfig.vue new file mode 100644 index 0000000..32bdc06 --- /dev/null +++ b/webapp/src/views/cloudServing/components/forms/servingModelConfig.vue @@ -0,0 +1,481 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/keyValueTable/index.vue b/webapp/src/views/cloudServing/components/keyValueTable/index.vue new file mode 100644 index 0000000..60b6c94 --- /dev/null +++ b/webapp/src/views/cloudServing/components/keyValueTable/index.vue @@ -0,0 +1,74 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/modelDetail/index.vue b/webapp/src/views/cloudServing/components/modelDetail/index.vue new file mode 100644 index 0000000..90fe5dc --- /dev/null +++ b/webapp/src/views/cloudServing/components/modelDetail/index.vue @@ -0,0 +1,127 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/cloudServing/components/servingCallGuide/index.vue b/webapp/src/views/cloudServing/components/servingCallGuide/index.vue new file mode 100644 index 0000000..835d848 --- /dev/null +++ b/webapp/src/views/cloudServing/components/servingCallGuide/index.vue @@ -0,0 +1,145 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/servingCallGuide/servingApiInfo.vue b/webapp/src/views/cloudServing/components/servingCallGuide/servingApiInfo.vue new file mode 100644 index 0000000..47b1527 --- /dev/null +++ b/webapp/src/views/cloudServing/components/servingCallGuide/servingApiInfo.vue @@ -0,0 +1,58 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/servingDeploymentRecord/index.vue b/webapp/src/views/cloudServing/components/servingDeploymentRecord/index.vue new file mode 100644 index 0000000..fcccc7c --- /dev/null +++ b/webapp/src/views/cloudServing/components/servingDeploymentRecord/index.vue @@ -0,0 +1,194 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/servingLog/index.vue b/webapp/src/views/cloudServing/components/servingLog/index.vue new file mode 100644 index 0000000..3db1139 --- /dev/null +++ b/webapp/src/views/cloudServing/components/servingLog/index.vue @@ -0,0 +1,338 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/servingMonitor/index.vue b/webapp/src/views/cloudServing/components/servingMonitor/index.vue new file mode 100644 index 0000000..039c3e6 --- /dev/null +++ b/webapp/src/views/cloudServing/components/servingMonitor/index.vue @@ -0,0 +1,113 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + \ No newline at end of file diff --git a/webapp/src/views/cloudServing/components/servingMonitor/servingMonitorCard.vue b/webapp/src/views/cloudServing/components/servingMonitor/servingMonitorCard.vue new file mode 100644 index 0000000..cbb3b9b --- /dev/null +++ b/webapp/src/views/cloudServing/components/servingMonitor/servingMonitorCard.vue @@ -0,0 +1,158 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/servingMonitor/servingMonitorUsageUnit.vue b/webapp/src/views/cloudServing/components/servingMonitor/servingMonitorUsageUnit.vue new file mode 100644 index 0000000..f19a7e3 --- /dev/null +++ b/webapp/src/views/cloudServing/components/servingMonitor/servingMonitorUsageUnit.vue @@ -0,0 +1,85 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/components/servingPredict/index.vue b/webapp/src/views/cloudServing/components/servingPredict/index.vue new file mode 100644 index 0000000..7d64bf0 --- /dev/null +++ b/webapp/src/views/cloudServing/components/servingPredict/index.vue @@ -0,0 +1,187 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/detail.vue b/webapp/src/views/cloudServing/detail.vue new file mode 100644 index 0000000..e8a4408 --- /dev/null +++ b/webapp/src/views/cloudServing/detail.vue @@ -0,0 +1,372 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/formPage.vue b/webapp/src/views/cloudServing/formPage.vue new file mode 100644 index 0000000..d68fcb8 --- /dev/null +++ b/webapp/src/views/cloudServing/formPage.vue @@ -0,0 +1,183 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/index.vue b/webapp/src/views/cloudServing/index.vue new file mode 100644 index 0000000..6bc2889 --- /dev/null +++ b/webapp/src/views/cloudServing/index.vue @@ -0,0 +1,519 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/cloudServing/util.js b/webapp/src/views/cloudServing/util.js new file mode 100644 index 0000000..61f02b9 --- /dev/null +++ b/webapp/src/views/cloudServing/util.js @@ -0,0 +1,186 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +export const SERVING_STATUS_ENUM = { + EXCEPTION: '0', + IN_DEPLOYMENT: '1', + WORKING: '2', + STOP: '3', + COMPLETED: '4', + UNKNOWN: '5', +}; + +export const ONLINE_SERVING_STATUS_MAP = { + [SERVING_STATUS_ENUM.IN_DEPLOYMENT]: { name: '部署中', tagMap: '' }, + [SERVING_STATUS_ENUM.WORKING]: { name: '运行中', tagMap: 'success' }, + [SERVING_STATUS_ENUM.STOP]: { name: '已停止', tagMap: 'info' }, + [SERVING_STATUS_ENUM.EXCEPTION]: { name: '运行失败', tagMap: 'danger' }, +}; + +export const BATCH_SERVING_STATUS_MAP = { + [SERVING_STATUS_ENUM.IN_DEPLOYMENT]: { name: '部署中', tagMap: '' }, + [SERVING_STATUS_ENUM.WORKING]: { name: '运行中', tagMap: '' }, + [SERVING_STATUS_ENUM.STOP]: { name: '已停止', tagMap: 'info' }, + [SERVING_STATUS_ENUM.EXCEPTION]: { name: '运行失败', tagMap: 'danger' }, + [SERVING_STATUS_ENUM.COMPLETED]: { name: '运行完成', tagMap: 'success' }, + [SERVING_STATUS_ENUM.UNKNOWN]: { name: '未知', tagMap: 'info' }, +}; + +export function generateMap(originMap, field) { + const map = {}; + Object.keys(originMap).forEach(key => { + map[key] = originMap[key][field]; + }); + return map; +} + +export const ONLINE_SERVING_TYPE = { + HTTP: 0, + GRPC: 1, +}; + +export const serviceTypeMap = { + [ONLINE_SERVING_TYPE.HTTP]: 'HTTP 模式', + [ONLINE_SERVING_TYPE.GRPC]: 'GRPC 模式', +}; + +export function map2Array(obj) { + const result = []; + if (typeof obj !== 'object' || obj === null) { + return result; + } + for (const key of Object.keys(obj)) { + result.push({ + name: key, + type: obj[key], + }); + } + return result; +} + +export function numFormatter(num) { + return num < 10000 ? `${num}` : `${Math.round(num / 1000) / 10}万`; +} + +function getResponseBody(xhr) { + const response = xhr.response || xhr.responseText; + try { + return JSON.parse(response); + } catch (e) { + return response; + } +} + +// 自定义了上传方法,用于支持多文件上传预测 +export function upload(options) { + const xhr = new XMLHttpRequest(); + const formData = new FormData(); + for (const file of options.fileList) { + formData.append(options.uploadName, file, file.name); + } + + if (xhr.upload && options.onUploadProgress) { + xhr.upload.onprogress = function progress(e) { + if (e.total > 0) { + e.percent = e.loaded / e.total * 100; + } + options.onUploadProgress(e); + }; + } + + xhr.onreadystatechange = () => { + if (xhr.readyState === 4) { + const response = getResponseBody(xhr); + if (xhr.status < 200 || xhr.status >= 300) { + const error = new Error(response.msg || '未知错误'); + return options.onUploadError(error); + } + options.onUploadSuccess(response); + } + }; + + xhr.open('post', options.requestUrl, true); + xhr.send(formData); + return xhr; +} + +export function cpuFormatter(num, unit) { + // 如果单位为空,则直接以“核”为单位展示,否则以 m 为单位展示 + if (!unit) { + return `${num}核`; + } + if (unit === 'n') { + num /= 1e6; + unit = 'm'; + } + if (unit === 'm') { + return `${Math.round(num * 10) / 10}m`; + } + // 如果单位不为 核、m、n 其中的一个,则直接返回格式 + return num + unit; +} + +export function cpuPercentage(used, usedUnit, total, totalUnit) { + const _transition = (num, unit) => { + switch (unit) { + case '': + num *= 1e9; + break; + case 'm': + num *= 1e6; + break; + // no default + } + return num; + }; + return Math.round(_transition(used, usedUnit) / _transition(total, totalUnit) * 10000) / 100; +} + +export function memFormatter(num, unit) { + if (unit === 'Ki' && num > 1024) { + unit = 'Mi'; + num /= 1024; + } + if (unit === 'Mi' && num > 1024) { + unit = 'Gi'; + num /= 1024; + } + return Math.round(num * 10) / 10 + unit; +} + +export function memPercentage(used, usedUnit, total, totalUnit) { + const _transition = (num, unit) => { + switch (unit) { + case 'Gi': + num *= 2 ** 20; + break; + case 'Mi': + num *= 2 ** 10; + break; + // no default + } + return num; + }; + return Math.round(_transition(used, usedUnit) / _transition(total, totalUnit) * 10000) / 100; +} + +export const batchServingProgressColor = [ + { color: '#67c23a', percentage: 100 }, +]; + +export function getPollId() { + return new Date().getTime(); +}; diff --git a/webapp/src/views/dashboard/components/CardPanel.vue b/webapp/src/views/dashboard/components/CardPanel.vue index f018664..a660f1e 100644 --- a/webapp/src/views/dashboard/components/CardPanel.vue +++ b/webapp/src/views/dashboard/components/CardPanel.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/dashboard/components/Welcome.vue b/webapp/src/views/dashboard/components/Welcome.vue index 6729dee..5f61e8c 100644 --- a/webapp/src/views/dashboard/components/Welcome.vue +++ b/webapp/src/views/dashboard/components/Welcome.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/dashboard/dashboard.vue b/webapp/src/views/dashboard/dashboard.vue index 279456c..a971838 100644 --- a/webapp/src/views/dashboard/dashboard.vue +++ b/webapp/src/views/dashboard/dashboard.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/dataset/annotate/index.vue b/webapp/src/views/dataset/annotate/index.vue index fc006f6..8c52807 100644 --- a/webapp/src/views/dataset/annotate/index.vue +++ b/webapp/src/views/dataset/annotate/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,7 +63,7 @@ import { Message, MessageBox } from 'element-ui'; import { isEmpty, isFunction, omit, isNil } from 'lodash'; -import { detail, detectFileList, queryFileOffset, queryDataEnhanceList, getEnhanceFileList } from '@/api/preparation/dataset'; +import { detail, detectFileList, queryFileOffset, queryDataEnhanceList, getEnhanceFileList, queryLabels as queryLabelApi, createLabel as createLabelApi } from '@/api/preparation/dataset'; import request from '@/utils/request'; import { generateUuid, generateBbox, bbox2Extent, extent2Bbox, endsWith, replace, remove, AssertError } from '@/utils'; import { parseAnnotation, labelsSymbol, enhanceSymbol, stringifyAnnotations, annotationMap, transformFiles, withExtent } from '../util'; @@ -170,13 +170,13 @@ export default { // 查询标签 const queryLabels = async(requestParams = {}) => { - const labels = await request(`api/data/datasets/${params.datasetId}/labels`, { params: requestParams }); + const labels = await queryLabelApi(params.datasetId, requestParams); return labels || []; }; // 新建标签 const createLabel = async(labelParams = {}) => { - const result = await request.post(`api/data/datasets/${params.datasetId}/labels`, labelParams); + const result = await createLabelApi(params.datasetId, labelParams); return result; }; diff --git a/webapp/src/views/dataset/annotate/settingContainer/annotations.vue b/webapp/src/views/dataset/annotate/settingContainer/annotations.vue index 74952b4..cfa5d1c 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/annotations.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/annotations.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ diff --git a/webapp/src/views/dataset/annotate/settingContainer/editLabel.vue b/webapp/src/views/dataset/annotate/settingContainer/editLabel.vue index 0688b62..c2f2ae2 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/editLabel.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/editLabel.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/dataset/annotate/settingContainer/enhance.vue b/webapp/src/views/dataset/annotate/settingContainer/enhance.vue index bd2a060..259060e 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/enhance.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/enhance.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/dataset/annotate/settingContainer/enhanceTip.vue b/webapp/src/views/dataset/annotate/settingContainer/enhanceTip.vue index 39ca958..a1466de 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/enhanceTip.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/enhanceTip.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/dataset/annotate/settingContainer/footer.vue b/webapp/src/views/dataset/annotate/settingContainer/footer.vue index 305bc75..45547cb 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/footer.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/footer.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/dataset/annotate/settingContainer/index.vue b/webapp/src/views/dataset/annotate/settingContainer/index.vue index 1cfadc9..8bad7b9 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/index.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -82,6 +82,7 @@ import { isNil } from 'lodash'; import { getAutoLabels, editLabel } from '@/api/preparation/datalabel'; import { labelsSymbol } from '@/views/dataset/util'; +import { labelGroupTypeCodeMap } from '@/views/labelGroup/util'; import SelectLabel from './selectLabel'; import LabelList from './labelList'; @@ -168,7 +169,7 @@ export default { }; const getSystemLabel = () => { - getAutoLabels().then(res => { + getAutoLabels(labelGroupTypeCodeMap.VISUAL).then(res => { const labelsObj = res.map((item) => ({ value: item.id, label: item.name, diff --git a/webapp/src/views/dataset/annotate/settingContainer/label.vue b/webapp/src/views/dataset/annotate/settingContainer/label.vue index 22a0201..9e6245c 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/label.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/label.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/dataset/annotate/settingContainer/labelList/edit.vue b/webapp/src/views/dataset/annotate/settingContainer/labelList/edit.vue index 17bae7f..014b2d3 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/labelList/edit.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/labelList/edit.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,7 +77,7 @@ export default { // 表单规则 const rules = { name: [ - { required: true, message: '请输入数据集名称', trigger: ['change', 'blur'] }, + { required: true, message: '请输入标签名称', trigger: ['change', 'blur'] }, { validator: validateName, trigger: ['change', 'blur'] }, ], }; diff --git a/webapp/src/views/dataset/annotate/settingContainer/labelList/index.vue b/webapp/src/views/dataset/annotate/settingContainer/labelList/index.vue index 2af9eae..5c48779 100644 --- a/webapp/src/views/dataset/annotate/settingContainer/labelList/index.vue +++ b/webapp/src/views/dataset/annotate/settingContainer/labelList/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,8 @@ diff --git a/webapp/src/views/dataset/entrance.vue b/webapp/src/views/dataset/entrance.vue new file mode 100644 index 0000000..d3460d7 --- /dev/null +++ b/webapp/src/views/dataset/entrance.vue @@ -0,0 +1,121 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + diff --git a/webapp/src/views/dataset/fork.vue b/webapp/src/views/dataset/fork.vue new file mode 100644 index 0000000..0a13b6c --- /dev/null +++ b/webapp/src/views/dataset/fork.vue @@ -0,0 +1,39 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + diff --git a/webapp/src/views/dataset/list/action.js b/webapp/src/views/dataset/list/action.js index 79f1aa8..f6dccd5 100644 --- a/webapp/src/views/dataset/list/action.js +++ b/webapp/src/views/dataset/list/action.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * ============================================================= */ -import { statusCodeMap, dataTypeCodeMap } from '../util'; +import { statusCodeMap, dataTypeCodeMap, annotationCodeMap, isPublishDataset } from '../util'; export default { name: 'DatasetAction', @@ -42,6 +42,10 @@ export default { return ( 操作 + +
如果文本数据集关联的不是预置标签组,
自动标注按钮可能无法使用
+ +
); }, @@ -62,8 +66,14 @@ export default { if (row.dataType === dataTypeCodeMap.VIDEO && statusCodeMap[row.status] === 'AUTO_ANNOTATED') { showCheckButton = false; } - // 查看标注按钮 - const checkButton = ( + // 查看标注按钮根据版本发布的状态决定是否置灰加提示 + const checkButton = isPublishDataset(row) ? ( + + + 查看标注 + + + ) : ( goDetail(row)}> 查看标注 @@ -71,6 +81,10 @@ export default { // 自动标注按钮只在 未标注 标注中 时显示 let showAutoButton = ['UNANNOTATED', 'ANNOTATING'].includes(statusCodeMap[row.status]); + // 如果是文本分类,只有使用了预置标签组的数据集可以进行自动标注,autoAnnotation字段 + if(row.dataType === dataTypeCodeMap.TEXT && !row.autoAnnotation) { + showAutoButton = false; + } // 自动标注按钮 const autoButton = ( autoAnnotate(row)}> @@ -110,7 +124,8 @@ export default { 发布 ); - + + // 当类型为文本时,不显示发布按钮 // 当类型为视频时,状态为标注完成、目标跟踪完成时显示发布按钮,其余状态不显示发布按钮 // 当类型为图片时,状态为自动标注完成时显示有弹窗确认的发布按钮,为标注完成时显示发布按钮,其余状态不显示发布按钮 if (row.dataType === dataTypeCodeMap.VIDEO) { @@ -118,12 +133,14 @@ export default { showPublishButton = true; publishButton = publishDialogButton; } - } else if (statusCodeMap[row.status] === 'AUTO_ANNOTATED') { - showPublishButton = true; - publishButton = publishConfirmButton; - } else if (statusCodeMap[row.status] === 'ANNOTATED') { - showPublishButton = true; - publishButton = publishDialogButton; + } else if (row.dataType === dataTypeCodeMap.IMAGE) { + if (statusCodeMap[row.status] === 'AUTO_ANNOTATED') { + showPublishButton = true; + publishButton = publishConfirmButton; + } else if (statusCodeMap[row.status] === 'ANNOTATED') { + showPublishButton = true; + publishButton = publishDialogButton; + } } let showUploadButton = false; @@ -145,6 +162,10 @@ export default { // 当标注完成、目标跟踪完成,以及非视频的自动标注完成时显示重新自动标注按钮 (若为视频此时下游会进行目标跟踪) let showReAutoButton = ['ANNOTATED', 'TRACK_SUCCEED'].includes(statusCodeMap[row.status]) || (statusCodeMap[row.status] === 'AUTO_ANNOTATED' && row.dataType === dataTypeCodeMap.IMAGE); + // 文本不能重新自动标注 + if (row.dataType === dataTypeCodeMap.TEXT) { + showReAutoButton = false; + } // 重新自动标注按钮 const reAutoButton = ( track(row, false)}> @@ -223,6 +244,21 @@ export default { ) : null; + + // 数据集版本发布或者切换中 只允许置顶 修改 历史版本,查看标注置灰 + if (isPublishDataset(row)) { + showPublishButton = false; + showUploadButton = false; + showCheckButton = true; + showAutoButton = false; + showReAutoButton = false; + showTrackButton = false; + showReTrackButton = false; + showVersionButton = true; + showAugmentButton = false; + showTopButton = true; + showEditButton = true; + }; // 预置数据集只具备查看标注,历史版本功能。 if (row.type === 2) { diff --git a/webapp/src/views/dataset/list/create-dataset.vue b/webapp/src/views/dataset/list/create-dataset.vue index 2531dff..701b2d8 100644 --- a/webapp/src/views/dataset/list/create-dataset.vue +++ b/webapp/src/views/dataset/list/create-dataset.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,6 @@ v-model="form.annotateType" placeholder="标注类型" :dataSource="annotationList" - :disabled="form.dataType === dataTypeCodeMap.VIDEO" @change="handleAnnotateTypeChange" /> @@ -63,12 +62,13 @@ :props="{expandTrigger: 'hover'}" :show-all-levels="false" filterable - popper-class="group-cascader" - style="width:100%; line-height:32px;" + popper-class="group-cascader" + style="width: 100%; line-height: 32px;" @change="handleGroupChange" + @focus="handleGroupFocus" >
-
- + 查看详情 - -
+ +
+
{ - let disabled = false; + // 图片,可用图像分类和目标检测;视频,可用目标跟踪;文本,可用文本分类 + return rawAnnotationList.filter(d => { if (this.form.dataType === dataTypeCodeMap.IMAGE) { - disabled = d.value === annotationCodeMap.TRACK; - } else if (this.form.dataType === dataTypeCodeMap.VIDEO) { - disabled = d.value !== annotationCodeMap.TRACK; + return [annotationCodeMap.ANNOTATE, annotationCodeMap.CLASSIFY].includes(d.value); + } + if (this.form.dataType === dataTypeCodeMap.VIDEO) { + return d.value === annotationCodeMap.TRACK; } - return { - ...d, - disabled, - }; + if (this.form.dataType === dataTypeCodeMap.TEXT) { + return d.value === annotationCodeMap.TEXTCLASSIFY; + } + return true; }); }, @@ -348,30 +374,38 @@ export default { if(this.skipUpload) return true; return this.uploadStatus && ['success', 'exception'].includes(this.uploadStatus); }, - }, - created() { - this.crud.toQuery(); - getLabelGroupList(1).then(res => { - res.forEach((item) => { - this.labelGroupOptions[1].children.push({ - value: item.id, - label: item.name, - disabled: false, - }); - }); - }); - getLabelGroupList(0).then(res => { - res.forEach((item) => { - this.labelGroupOptions[0].children.push({ - value: item.id, - label: item.name, - disabled: false, - }); - }); - }); }, methods: { - handleGroupChange(val) { + handleGroupFocus() { + // 在未选择数据类型和标注类型之前,不对可用的标签组进行查询 + if(!isNil(this.form.dataType) && this.form.dataType !== '' && !isNil(this.form.annotateType) && this.form.annotateType !== ''){ + // 在数据类型和标注类型未改动的情况下 避免对可用的标签组列表进行重复查询 + if((this.labelGroupOptions[1].children).length === 0){ + getLabelGroupList({type: 1, dataType: this.form.dataType, annotateType: this.form.annotateType}).then(res => { + res.forEach((item) => { + this.labelGroupOptions[1].children.push({ + value: item.id, + label: item.name, + disabled: false, + }); + }); + }); + } + if((this.labelGroupOptions[0].children).length === 0){ + getLabelGroupList({type: 0, dataType: this.form.dataType, annotateType: this.form.annotateType}).then(res => { + res.forEach((item) => { + this.labelGroupOptions[0].children.push({ + value: item.id, + label: item.name, + disabled: false, + }); + }); + }); + } + } + }, + + handleGroupChange(val){ if(val.length === 0) { this.chosenGroup = null; this.chosenGroupId = null; @@ -402,43 +436,21 @@ export default { this.uploadPercent = 0; this.videoUploadProgress = 0; }, - + // 清空标签组可选列表 清除选中的标签组 + clearLabelGroupItem() { + this.labelGroupOptions[0].children = []; + this.labelGroupOptions[1].children = []; + this.chosenGroupId = null; + this.chosenGroup = null; + }, // step0 改变数据类型 handleDataTypeChange(dataType) { - // 数据类型选中为视频时,标注类型自动切换为目标跟踪,同时清除不符合类型的标签组 - if (dataType === dataTypeCodeMap.VIDEO) { - this.form.annotateType = annotationCodeMap.TRACK; - this.handleAnnotateTypeChange(annotationCodeMap.TRACK); - } else { - // 数据类型选中为其他时 去除限制 - this.form.annotateType = undefined; - this.labelGroupOptions[1].disabled = false; - this.labelGroupOptions[1].children.forEach( item => {item.disabled = false;}); - } + this.clearLabelGroupItem(); + this.form.annotateType = dataTypeAnnotateTypeMap.get(dataType); }, // step0 改变标注类型 - handleAnnotateTypeChange(annotateType) { - // 更改标注类型会清除不符合条件的标签组 - // 目标检测和目标跟踪可以选中预置标签组中的Coco(id=1) - if ([annotationCodeMap.ANNOTATE, annotationCodeMap.TRACK].includes(annotateType)) { - if(this.chosenGroupId !== 1){ - this.chosenGroup = null; - this.chosenGroupId = null; - } - this.labelGroupOptions[1].disabled = false; - this.labelGroupOptions[1].children.forEach( item => { - // 此处1是预置的coco标签组固定id为1 - if(item.value === 1){ - item.disabled = false; - } else { - item.disabled = true; - } - }); - } else { - // 其余可以使用任意标签组 - this.labelGroupOptions[1].disabled = false; - this.labelGroupOptions[1].children.forEach(item => {item.disabled = false;}); - } + handleAnnotateTypeChange() { + this.clearLabelGroupItem(); }, // step0 创建数据集调用 createDataset() { @@ -479,13 +491,16 @@ export default { // 文件上传 if (dataType === dataTypeCodeMap.IMAGE) { return submit(datasetId, files); - } + } if (dataType === dataTypeCodeMap.VIDEO) { return submitVideo(datasetId, { frameInterval: this.step1Form.frameInterval, url: files[0].url, }); } + if (dataType === dataTypeCodeMap.TEXT) { + return submit(datasetId, files); + } return Promise.reject(); }, // step1 上传成功 @@ -497,7 +512,14 @@ export default { if (this.form.dataType === dataTypeCodeMap.VIDEO) { this.videoUploadProgress = 100; } - const files = getImgFromMinIO(res); + + let files; + if (this.form.dataType === dataTypeCodeMap.TEXT) { + files = getTextFromMinIO(res); + } else { + files = getImgFromMinIO(res); + } + // 自动标注完成时 导入 提示信息不同 const successMessage = '上传文件成功'; if (files.length > 0) { @@ -511,11 +533,10 @@ export default { }); } }, - // step1 上传失败 - uploadError() { - this.uploadStatus = 'exception'; + // step1 上传失败 + uploadError(err) { this.$message({ - message: '上传文件失败', + message: err.message || '上传文件失败', type: 'error', }); }, @@ -527,16 +548,15 @@ export default { // step1 确定上传 uploadSubmit(formName) { this.$refs[formName].uploadSubmit((resolved, total) => { + if (this.crud.status.cu > 0) { + this.activeStep = 2; + } // eslint-disable-next-line func-names this.$nextTick(function() { this.uploadPercent = this.uploadPercent > 100 ? 100 : toFixed(resolved / total); }); }); - - if (this.crud.status.cu > 0) { - this.activeStep = 2; - } }, // step2 进度格式化 diff --git a/webapp/src/views/dataset/list/data-enhance.vue b/webapp/src/views/dataset/list/data-enhance.vue index bf6814e..8c4045b 100644 --- a/webapp/src/views/dataset/list/data-enhance.vue +++ b/webapp/src/views/dataset/list/data-enhance.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/dataset/list/edit-dataset.vue b/webapp/src/views/dataset/list/edit-dataset.vue index 8d6aa2d..dcb286f 100644 --- a/webapp/src/views/dataset/list/edit-dataset.vue +++ b/webapp/src/views/dataset/list/edit-dataset.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,7 +53,7 @@ filterable :clearable="deletable" popper-class="group-cascader" - style="width:100%; line-height:32px;" + style="width: 100%; line-height: 32px;" @change="handleGroupChange" >
@@ -70,7 +70,7 @@ 页面创建
-
+
import {isNil} from 'lodash'; -import { watch, reactive, computed, onMounted } from '@vue/composition-api'; +import { watch, reactive, computed } from '@vue/composition-api'; import BaseModal from '@/components/BaseModal'; import InfoSelect from '@/components/InfoSelect'; @@ -215,14 +215,15 @@ export default { label: annotationMap[d].name, value: Number(d), })); - // 如果是图片,目标跟踪不可用 - // 如果是视频,只能用目标跟踪 + // 图片,可用图像分类和目标检测;视频,可用目标跟踪;文本,可用文本分类 return rawAnnotationList.map(d => { let disabled = false; if (state.model.dataType === dataTypeCodeMap.IMAGE) { - disabled = d.value === annotationCodeMap.TRACK; + disabled = ![annotationCodeMap.ANNOTATE, annotationCodeMap.CLASSIFY].includes(d.value); } else if (state.model.dataType === dataTypeCodeMap.VIDEO) { disabled = d.value !== annotationCodeMap.TRACK; + } else { + disabled = d.value !== annotationCodeMap.TEXTCLASSIFY; } return { ...d, @@ -257,49 +258,30 @@ export default { } }; - onMounted(() => { - getLabelGroupList(1).then(res => { - res.forEach((item) => { - state.labelGroupOptions[1].children.push({ - value: item.id, - label: item.name, - disabled: false, - }); - }); - }); - getLabelGroupList(0).then(res => { - res.forEach((item) => { - state.labelGroupOptions[0].children.push({ - value: item.id, - label: item.name, - disabled: false, - }); - }); - }); - }); - watch(() => props.row, (next) => { Object.assign(state, { model: { ...state.model, ...next }, }); - // 图像分类可任意选择 - if(next?.annotateType === annotationCodeMap.CLASSIFY) { - state.labelGroupOptions[1].disabled = false; - state.labelGroupOptions[1].children.forEach( item => {item.disabled = false;}); + if(!isNil(state.model.dataType)){ + getLabelGroupList({type: 1, dataType: state.model.dataType, annotateType: state.model.annotateType}).then(res => { + res.forEach((item) => { + state.labelGroupOptions[1].children.push({ + value: item.id, + label: item.name, + disabled: false, + }); + }); + }); } - // 目标检测和目标跟踪 在预置标签组中只可选择coco - if([annotationCodeMap.ANNOTATE, annotationCodeMap.TRACK].includes(next?.annotateType)) { - if(state.chosenGroupId !== 1) { - state.chosenGroup = null; - state.chosenGroupId = null; - } - state.labelGroupOptions[1].disabled = false; - state.labelGroupOptions[1].children.forEach( item => { - if(item.value === 1){ - item.disabled = false; - } else { - item.disabled = true; - } + if(!isNil(state.model.dataType)){ + getLabelGroupList({type: 0, dataType: state.model.dataType, annotateType: state.model.annotateType}).then(res => { + res.forEach((item) => { + state.labelGroupOptions[0].children.push({ + value: item.id, + label: item.name, + disabled: false, + }); + }); }); } // 读取数据集已有标签组 diff --git a/webapp/src/views/dataset/list/import-dataset.vue b/webapp/src/views/dataset/list/import-dataset.vue index 9a2c20c..2b8d33e 100644 --- a/webapp/src/views/dataset/list/import-dataset.vue +++ b/webapp/src/views/dataset/list/import-dataset.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,17 +27,15 @@
- 请认真阅读下方说明,创建数据集完毕后,按照系统格式要求上传数据集文件,否则标注文件可能无法正确解析。 - 下载示例数据集模板 + 请参考下方说明文档,创建数据集完毕后,按照数据集模板格式上传数据集文件,否则标注文件可能无法正确解析。
-

1. 系统提供了一站式脚本服务用以快速导入本地已有数据集(使用文档),推荐使用 -

2. 本地数据集需要包括图片(origin 目录)、标注文件(annotation 目录)和标签文件三部分

-

3. 注意区分「图像分类」和「目标检测」类型数据集

-

4. 图片格式支持 jpg/png/bmp/jpeg,不大于 5M,位于 origin 目录下,不支持目录嵌套

-

5. 标注文件为 json 格式,位于 annotation 目录下,必须和文件同名(如果不存在标注,可不上传),不支持目录嵌套

-

6. 标签文件为 json 格式,命名要求为 label_{name}.json,其中 name 为标签组名称,不能与系统已有标签组重名

-

7. 更多参考示例数据集模板

+

1. 数据集脚本工具(文档) +

2. 图片数据集(文档

+

3. 文本数据集(文档

+

4. 图片数据集模板(下载

+

5. 文本数据集模板(下载

+

7. 更多参考(官网文档

@@ -52,7 +50,12 @@ - + ["1", "2"].includes(type)).map(d => ({ + // 原始标注列表 + const rawAnnotationList = Object.keys(annotationMap).map(d => ({ label: annotationMap[d].name, value: Number(d), })); - return activeList; + // 图片,可用图像分类和目标检测;视频,可用目标跟踪;文本,可用文本分类 + return rawAnnotationList.filter(d => { + if (this.form.dataType === dataTypeCodeMap.IMAGE) { + return [annotationCodeMap.ANNOTATE, annotationCodeMap.CLASSIFY].includes(d.value); + } + if (this.form.dataType === dataTypeCodeMap.VIDEO) { + return d.value === annotationCodeMap.TRACK; + } + if (this.form.dataType === dataTypeCodeMap.TEXT) { + return d.value === annotationCodeMap.TEXTCLASSIFY; + } + return true; + }); }, + + dataTypeList: () => + Object.keys(dataTypeMap) + .filter(type => [dataTypeCodeMap.IMAGE, dataTypeCodeMap.TEXT].includes(Number(type))) + .map(d => ({ + label: dataTypeMap[d], + value: Number(d), + }), + ), }, methods: { nextImportStep() { @@ -159,7 +191,7 @@ export default { return; } const customForm = { - name: this.form.name, + name: this.form.name, remark: this.form.remark, annotateType: this.form.annotateType, dataType: this.form.dataType, @@ -182,14 +214,17 @@ export default { resetFormFields() { this.formKey += 1; this.importStep = 0; - this.form = { + this.form = { name: "", - dataType: 0, - annotateType: 2, + dataType: "", + annotateType: "", status: 4, remark: "", }; }, + handleDataTypeChange(dataType) { + this.form.annotateType = dataTypeAnnotateTypeMap.get(dataType); + }, }, }; - \ No newline at end of file + diff --git a/webapp/src/views/dataset/list/index.vue b/webapp/src/views/dataset/list/index.vue index 362879b..bbc7954 100644 --- a/webapp/src/views/dataset/list/index.vue +++ b/webapp/src/views/dataset/list/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,21 +19,21 @@
- 创建数据集 - 导入数据集 @@ -64,29 +64,34 @@
- - -
+
- +
+ + + + +
{{ scope.row.id }} - - +
当前数据集为外部导入数据集
点击复制数据集 ID
使用文档
-
@@ -151,14 +154,14 @@ - \ No newline at end of file + diff --git a/webapp/src/views/dataset/medical/action.js b/webapp/src/views/dataset/medical/action.js new file mode 100644 index 0000000..05b233f --- /dev/null +++ b/webapp/src/views/dataset/medical/action.js @@ -0,0 +1,105 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +import { statusCodeMap } from '../util'; +import { medicalAnnotationCodeMap } from './constant'; + +export default { + name: 'DatasetAction', + functional: true, + props: { + goDetail: Function, + autoAnnotate: Function, + editDataset: Function, + }, + render(h, { data, props }) { + const { goDetail, autoAnnotate, editDataset } = props; + const columnProps = { + ...data, + scopedSlots: { + header: () => { + return ( + + 操作 + +
自动标注仅支持肺部CT影像
+ +
+
+ ); + }, + default: ({ row }) => { + const btnProps = { + props: { + type: 'text', + disabled: row.disabledAction, + }, + style: { + marginLeft: '0px', + marginRight: '10px', + }, + }; + + // 查看标注按钮在自动标注中时不显示 + let showCheckButton = !(statusCodeMap[row.status] === 'AUTO_ANNOTATING'); + // 查阅影像按钮 + const checkButton = ( + goDetail(row)}> + 查阅影像 + + ); + + // 自动标注按钮只在未标注且目前算法支持的情形下显示 + let showAutoButton = ['UNANNOTATED'].includes(statusCodeMap[row.status]) + && row.bodyPartExamined === "LUNG" + && row.modality === "CT" + && row.annotateType === medicalAnnotationCodeMap.OrganSegmentation; + // 自动标注按钮 + const autoButton = ( + autoAnnotate(row)}> + 自动标注 + + ); + + let showEditButton = true; + // 修改按钮总会显示 + const editButton = ( + editDataset(row)}> + 修改 + + ); + + // 预置数据集只具备查阅影像功能 + if (row.type === 2) { + showCheckButton = true; + showAutoButton = false; + showEditButton = false; + }; + + return ( + + {showCheckButton && checkButton} + {showAutoButton && autoButton} + {showEditButton && editButton} + + ); + }, + }, + }; + + return h('el-table-column', columnProps); + }, +}; diff --git a/webapp/src/views/dataset/medical/constant.js b/webapp/src/views/dataset/medical/constant.js new file mode 100644 index 0000000..9364e9d --- /dev/null +++ b/webapp/src/views/dataset/medical/constant.js @@ -0,0 +1,74 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +export const medicalProgressMap = { + unfinished: '未标注', + autoFinished: '自动标注完成', + manualAnnotating: '手动标注中', + finished: '标注完成', +}; + +export const medicalAnnotationCodeMap = { + 'OrganSegmentation': 1001, + 'LesionDetection': 2001, + 'Other': 2999, +}; + +export const medicalFirstLevelCodeMap = { + 1000: { name: '器官分割' }, + 2000: { name: '病灶识别' }, +}; + +export const medicalAnnotationMap = { + 1001: { name: '器官分割', urlPrefix: 'organSegmentation', parentName: '器官分割' }, + 2001: { name: '肺结节检测', urlPrefix: 'lesionDetection', parentName: '病灶识别' }, + 2999: { name: '其它', urlPrefix: 'other', parentName: '病灶识别' }, +}; + +export const modalityMap = { + 'CT': 'CT', + 'MR': 'MR', + 'US': 'US', + 'X-Ray': 'X-Ray', + 'OTHER': 'OTHER', +}; + +export const bodyPartMap = { + BRAIN: 'BRAIN', + LUNG: 'LUNG', + LIVER: 'LIVER', + SOFTTISSUE: 'SOFTTISSUE', + OTHER: 'OTHER', +}; + +// 医学数据集状态 +export const medicalStatusMap = { + 101: { name: '未标注', type: 'info' }, + 102: { name: '标注中', type: 'warning' }, + 103: { name: '自动标注中', type: 'danger' }, + 104: { name: '自动标注完成', type: '' }, + 105: { name: '标注完成', type: 'success' }, +}; + +// 标注类型 +export const getAnnotateType = (type) => { + // 2001-2999 病灶检测 + if(Number(type) > 2000 && Number(type) < 3000) return 1; + // 1001-1999 为器官分割 + if(Number(type) > 1000 && Number(type) < 2000) return 0; + // 历史数据 + return 0; +}; diff --git a/webapp/src/views/dataset/medical/create-dataset.vue b/webapp/src/views/dataset/medical/create-dataset.vue new file mode 100644 index 0000000..292c362 --- /dev/null +++ b/webapp/src/views/dataset/medical/create-dataset.vue @@ -0,0 +1,294 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + \ No newline at end of file diff --git a/webapp/src/views/dataset/medical/edit-dataset.vue b/webapp/src/views/dataset/medical/edit-dataset.vue new file mode 100644 index 0000000..b86c2b7 --- /dev/null +++ b/webapp/src/views/dataset/medical/edit-dataset.vue @@ -0,0 +1,127 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/dataset/medical/lib/actions.js b/webapp/src/views/dataset/medical/lib/actions.js new file mode 100644 index 0000000..da582c9 --- /dev/null +++ b/webapp/src/views/dataset/medical/lib/actions.js @@ -0,0 +1,166 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ +import { noop } from '@/utils'; +import { genDrawingFromAnnotations } from './index'; + +export const defaultWlPresets = { + SoftTissue: { + name: '软组织', + wc: 40, + ww: 400, + }, + Lung: { + name: '肺', + wc: -600, + ww: 1500, // todo: 为啥不一致 + }, + Liver: { + name: '肝脏', + wc: 90, + ww: 150, + }, + Brain: { + name: '大脑', + wc: 40, + ww: 80, + }, +}; + +// 可绘制形状配置 +export const drawOptions = { + Rectangle: { + name: '矩形', + }, + Roi: { + name: '自定义', + }, +}; + +const actions = [ + { + command: 'Scroll', + type: 'tool', + text: '滚动浏览', + icon: 'bars', + }, + { + command: 'ZoomAndPan', + type: 'tool', + text: '缩放', + icon: 'zoom', + }, + { + command: 'WindowLevel', + type: 'tool', + text: '窗宽/窗位', + icon: 'manual', + }, + { + command: 'Draw', + type: 'tool', + text: '标注', + icon: 'polygon', + options: drawOptions, + }, + { + command: 'Hidden', + type: 'command', + text: '隐藏信息', + icon: 'hidden', + }, + { + command: 'Visible', + type: 'command', + text: '展示信息', + icon: 'visible', + }, + { + command: 'Reset', + type: 'command', + text: '重置', + icon: 'reset', + }, + { + command: 'SetWlPreset', + type: 'command', + text: '预设窗口', + icon: 'body', + options: defaultWlPresets, + }, +]; + +export const viewerCommands = { + Hidden: (app, updateState) => { + updateState({ + showInfo: false, + }); + }, + Visible: (app, updateState) => { + updateState({ + showInfo: true, + }); + }, + Reset: (app, updateState) => { + app.resetDisplay(); + updateState((state) => { + const prevOverlayInfo = state.overlayInfo; + return { + wlPreset: '', + shape: '', + showInfo: true, + overlayInfo: { + ...prevOverlayInfo, + zoom: { scale: 1 }, + }, + }; + }); + }, + SetWlPreset: (app, updateState, tool) => { + updateState({ + wlPreset: tool.value, + }); + const wl = defaultWlPresets[tool.value]; + app.getViewController().setWindowLevel(wl.wc, wl.ww); + }, + SetPrecision: (app, updateState, tool, state) => { + updateState({ + precision: tool.precision, + }); + const { autoAnnotationIds } = state; + const drawLayer = app.getDrawController().getDrawLayer(); + const posGroups = drawLayer.getChildren(); + const kGroups = []; + + // 遍历所有的posGroups,并提供匹配的形状groups + posGroups.forEach(group => { + const subGroups = group.getChildren( + node => autoAnnotationIds.includes(node.id())); + kGroups.push(subGroups); + }); + + for(let i=0; i ({}); +const RSUrl = `${process.env.VUE_APP_DCM_API}/rs`; +const dwc = new DICOMwebClient.api.DICOMwebClient({ + url: RSUrl, + headers: getAuthorizationHeader(), +}); + +// 对一个序列下的文件进行排序 +export const sortInstances = (series) => { + return series.sort((a, b) => { + const instanceNumberA = a['00200013'].Value[0]; + const instanceNumberB = b['00200013'].Value[0]; + return instanceNumberA - instanceNumberB; + }); +}; + + +export const buildWADOUrl = ({studyInstanceUID, seriesInstanceUID, objectUID }) => { + return `${process.env.VUE_APP_DCM_API}/wado?requestType=WADO&studyUID=${studyInstanceUID}&seriesUID=${seriesInstanceUID}&objectUID=${objectUID}&contentType=application/dicom`; +}; + +export const getImageIdsForSeries = (seriesData) => { + if (!seriesData || !seriesData.length) { + return []; + } + + return sortInstances(seriesData).map(instance => { + const BulkDataURI = instance['7FE00010'].BulkDataURI.replace(/^https?:\/\//, ''); + const bulkDataArr = BulkDataURI.split('/'); + const studyIndex = bulkDataArr.findIndex(d => d === 'studies'); + const seriesIndex = bulkDataArr.findIndex(d => d === 'series'); + const instanceIndex = bulkDataArr.findIndex(d => d === 'instances'); + + if(studyIndex > -1 && seriesIndex > -1) { + const studyInstanceUID = bulkDataArr[studyIndex + 1]; + const seriesInstanceUID = bulkDataArr[seriesIndex + 1]; + const objectUID = bulkDataArr[instanceIndex + 1]; + return { studyInstanceUID, seriesInstanceUID, objectUID }; + } + throw new Error('找不到对应的 studyUID 或 seriesUID'); + }); +}; + +// 获取实例instanceID +export const getSOPInstanceUID = (data) => { + if (typeof data.x00020010 !== 'undefined') { + if (typeof data.x00080018 !== 'undefined') { + // SOPInstanceUID + return dwv.dicom.cleanString(data.x00080018.value[0]); + } + } + throw new Error('当前 dcm 文件不合法,无法找到 SOPInstanceUID'); +}; + +export const retrieveBulkData = imageId => { + return dwc.retrieveBulkData({ + BulkDataURI: imageId, + }); +}; + +export function readRawData(drawings) { + // update drawings + const data = {}; + const v02DAndD = dwv.v01Tov02DrawingsAndDetails(drawings); + data.drawings = dwv.v02Tov03Drawings( v02DAndD.drawings ).toObject(); + data.drawingsDetails = v02DAndD.drawingsDetails; + return data; +} + +// 解析dicom 文件 +export const parseDicom = (byteArray, filename) => { + try { + const dataSet = dicomParser.parseDicom(byteArray); + + const rows = dataSet.uint16('x00280010'); + const columns = dataSet.uint16('x00280011'); + const seriesInstanceUID = dataSet.string('x0020000e'); + const patientID = dataSet.string('x00100020'); + const studyInstanceUID = dataSet.string('x0020000d'); + const modality = dataSet.string('x00080060'); + const bodyPartExamined = dataSet.string('x00180015'); + const SOPInstanceUID = dataSet.string('x00080018'); + const pixelData = dataSet.elements.x7fe00010; + if(!pixelData) { + throw new Error(`文件信息不完整:7fe00010字段不存在`); + } + return {rows, columns, patientID, seriesInstanceUID, studyInstanceUID, modality, bodyPartExamined, filename, SOPInstanceUID}; + } catch(err) { + // parse返回错误信息为err.exception + return err instanceof Error ? err : new Error(err.exception || err); + } +}; + +// 读文件 +export const readDicom = (file) => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = e => { + const arrayBuffer = e.target.result; + const byteArray = new Uint8Array(arrayBuffer); + const info = parseDicom(byteArray, file.raw.name.slice(0, -4)); + if(info instanceof Error) { + reject(info); + } else { + resolve(info); + } + }; + + reader.readAsArrayBuffer(file.raw); + }); +}; + +// 读取上传文件信息 +export const readDicoms = async (files) => { + const mapper = (file) => new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = e => { + const arrayBuffer = e.target.result; + const byteArray = new Uint8Array(arrayBuffer); + const info = parseDicom(byteArray, file.raw.name.slice(0, -4)); + if(info instanceof Error) { + reject(info); + } else { + resolve(info); + } + }; + + reader.readAsArrayBuffer(file.raw); + }); + + try { + const result = await pMap(files, mapper, {concurrency: 10}); + return result; + } catch(err){ + return Promise.reject(err); + } +}; + +// 判断上传系列文件格式是否一致 +export const validateDicomSeries = (series) => { + if(series.length < 1) return '文件数量不能为空'; + const isEqualRows = isEqualBy(series, 'rows'); + if(!isEqualRows) return '文件系列 rows 必须一致'; + const isEqualColumns = isEqualBy(series, 'columns'); + if(!isEqualColumns) return '文件系列 columns 必须一致'; + return ''; +}; + +// 解析自动标注结果 +export const genDrawingFromAnnotations = (annotations, percent) => { + const draws = []; + const frames = 1; + const drawingIds = []; + // 记录标注对应的slice 和 标注 对应关系 + const sliceDrawingMap = {}; + // 遍历 slice + for(let k = 0; k < annotations.length; k+=1) { + const slice = []; + // 每个 slice 分别对应的标注 id + const sliceDrawingIds = []; + // 自动标注帧数为1 + for(let f = 0; f < frames; f+=1) { + const frame = []; + for(let g = 0; g < annotations[k].length; g+=1) { + const pos = annotations[k][g]; + // percent为精度 100%时步长为1,显示所有标注点。10%时步长为10,即10个标注点取1个点显示 + const step = 1/percent; + const points = everyStep(pos, step); + const guid = dwv.math.guid(); + frame.push({ + "attrs": { + "name": "roi-group", + "id": guid, + }, + "className": "Group", + "children": [{ + "attrs": { + "points": flatten(points), + "name": "shape", + "closed": true, + "strokeWidth": 3, + "draggable": true, + }, + "className": "Line", + }], + }); + drawingIds.push(guid); + sliceDrawingIds.push(guid); + } + slice.push(frame); + } + sliceDrawingMap[k] = sliceDrawingIds; + draws.push(slice); + } + const { drawings, drawingsDetails } = readRawData(draws); + // sliceDrawingMap: 每个slice 对应的 drawingId + return { drawings, drawingsDetails, drawingIds, sliceDrawingMap }; +}; + +// 保存标注时去掉 anchor 信息 +export const removeAnchorsFromDrawer = (drawLayer) => { + const pGroups = drawLayer.getChildren(dwv.draw.isPositionNode); + pGroups.forEach(group => { + const subGroups = group.getChildren(); + subGroups.forEach(shape => { + const anchors = shape.getChildren(node => node.name() === 'anchor'); + anchors.each(anchor => anchor.remove()); + }); + }); +}; + +// 获取当前的 drawLayer +export const getDrawLayer = (app) => { + const drawLayer = app.getDrawController().getDrawLayer(); + return drawLayer; +}; + +export const getShapeEditor = (app) => { + return app.getShapeEditor(); +}; + +// 选中效果 +export const activeShapeGroup = (app, selectedShape) => { + const shapeEditor = getShapeEditor(app); + shapeEditor.disable(); + shapeEditor.setShape(selectedShape); + shapeEditor.setImage(app.getImage()); + shapeEditor.enable(); +}; + +// 根据 drawId 返回 shapeGroup +export const getShapeGroup = (drawId, drawLayer) => { + const pGroups = drawLayer.getChildren(dwv.draw.isPositionNode); + let selectedShape = null; + for(const group of pGroups) { + const subGroups = group.getChildren(); + const groups = subGroups.filter(shape => drawId === shape.id()); + if(groups.length) { + [selectedShape] = groups[0].find(".shape"); + break; + } + } + return selectedShape; +}; + +export { dwc }; diff --git a/webapp/src/views/dataset/medical/lib/overlays.json b/webapp/src/views/dataset/medical/lib/overlays.json new file mode 100644 index 0000000..74dd871 --- /dev/null +++ b/webapp/src/views/dataset/medical/lib/overlays.json @@ -0,0 +1,22 @@ +[ + {"tags": ["x00100020"], "pos": "tl"}, + {"tags": ["x00100010", "x00100040"], "pos": "tl", "format": "{v0} [{v1}]"}, + {"tags": ["x00100030"], "pos": "tl"}, + + {"tags": ["x00200011", "x00200012", "x00200013"], "pos": "bl", "format": "{v0}:{v1}:{v2}"}, + {"tags": ["x00185100"], "pos": "bl"}, + {"tags": ["x00201041"], "pos": "bl", "format": "SL: {v0}"}, + {"tags": ["x00180050"], "pos": "bl", "format": "ST: {v0}"}, + {"tags": ["x00280010", "x00280011"], "pos": "bl", "format": "RES: {v0}x{v1}"}, + + {"tags": ["x00080080"], "pos": "tr"}, + {"tags": ["x00080020", "x00080030"], "pos": "tr", "format": "{v0} {v1}"}, + {"tags": ["x00080060"], "pos": "tr"}, + {"tags": ["x00180015"], "pos": "tr"}, + + {"value": "Wwwc", "pos": "br", "format": "{v0} / {v1}"}, + {"value": "zoom", "pos": "br", "format": "Z: {v0}"}, + {"value": "offset", "pos": "br", "format": "Off: {v0},{v1}"}, + {"value": "position", "pos": "br", "format": "Pos: {v0},{v1},{v2}"}, + {"value": "value", "pos": "br", "format": "Value: {v0}"} +] diff --git a/webapp/src/views/dataset/medical/list.vue b/webapp/src/views/dataset/medical/list.vue new file mode 100644 index 0000000..c3f8439 --- /dev/null +++ b/webapp/src/views/dataset/medical/list.vue @@ -0,0 +1,650 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + \ No newline at end of file diff --git a/webapp/src/views/dataset/medical/status.js b/webapp/src/views/dataset/medical/status.js new file mode 100644 index 0000000..f6720e2 --- /dev/null +++ b/webapp/src/views/dataset/medical/status.js @@ -0,0 +1,71 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +import { medicalStatusMap } from './constant'; + +export default { + name: 'DatasetStatus', + functional: true, + render(h, { data, props }) { + const { statusList, filterByDatasetStatus, datasetStatusFilter } = props; + const iconClass = ['el-icon-arrow-down', 'el-icon--right']; + const textClass = datasetStatusFilter === 'all' ? null : 'primary'; + const columnProps = { + ...data, + scopedSlots: { + header: () => { + return ( + + + 状态 + + + + {statusList.map(item => { + return ( + filterByDatasetStatus(item.value)} + > + {item.label} + + ); + })} + + + ); + }, + default: ({ row }) => { + const status = medicalStatusMap[row.status] || {}; + const colorProps = (!status.type && status.bgColor) && { + props: { + color: status.bgColor, + }, + style: { + color: status.color, + borderColor: status.bgColor, + }, + }; + return ( + {status.name} + ); + }, + }, + }; + + return h('el-table-column', columnProps); + }, +}; diff --git a/webapp/src/views/dataset/medical/viewer/action.vue b/webapp/src/views/dataset/medical/viewer/action.vue new file mode 100644 index 0000000..499631a --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/action.vue @@ -0,0 +1,362 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/dataset/medical/viewer/controls.vue b/webapp/src/views/dataset/medical/viewer/controls.vue new file mode 100644 index 0000000..e8769bc --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/controls.vue @@ -0,0 +1,209 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/dataset/medical/viewer/helpInfo.vue b/webapp/src/views/dataset/medical/viewer/helpInfo.vue new file mode 100644 index 0000000..2b480a5 --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/helpInfo.vue @@ -0,0 +1,118 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + \ No newline at end of file diff --git a/webapp/src/views/dataset/medical/viewer/index.vue b/webapp/src/views/dataset/medical/viewer/index.vue new file mode 100644 index 0000000..a9d7324 --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/index.vue @@ -0,0 +1,780 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + \ No newline at end of file diff --git a/webapp/src/views/dataset/medical/viewer/infoLayer.vue b/webapp/src/views/dataset/medical/viewer/infoLayer.vue new file mode 100644 index 0000000..d2cb660 --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/infoLayer.vue @@ -0,0 +1,164 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + \ No newline at end of file diff --git a/webapp/src/views/dataset/medical/viewer/lesionInfo.vue b/webapp/src/views/dataset/medical/viewer/lesionInfo.vue new file mode 100644 index 0000000..17dd0f0 --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/lesionInfo.vue @@ -0,0 +1,215 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + \ No newline at end of file diff --git a/webapp/src/views/dataset/medical/viewer/toolbar.vue b/webapp/src/views/dataset/medical/viewer/toolbar.vue new file mode 100644 index 0000000..a7527cc --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/toolbar.vue @@ -0,0 +1,90 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/dataset/medical/viewer/toolbarButton.vue b/webapp/src/views/dataset/medical/viewer/toolbarButton.vue new file mode 100644 index 0000000..90165fa --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/toolbarButton.vue @@ -0,0 +1,80 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/dataset/medical/viewer/toolbarItem.js b/webapp/src/views/dataset/medical/viewer/toolbarItem.js new file mode 100644 index 0000000..4440eb7 --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/toolbarItem.js @@ -0,0 +1,67 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +import ToolbarButton from './toolbarButton'; +import ToolbarControls from './controls'; + +const ToolbarItem = { + name: 'ToolbarItem', + inheritAttrs: false, + components: { + ToolbarButton, + ToolbarControls, + }, + props: { + item: Object, + activeTool: String, + wlPreset: String, + shape: String, + }, + render() { + const toolItemProps = { + props: { + item: this.item, + activeTool: this.activeTool, + }, + on: this.$listeners, + }; + if(this.item.command === 'Draw') { + return ( + + ); + } + + if(this.item.command === 'SetWlPreset') { + return ( + + ); + } + + return ( + + ); + }, +}; + +export default ToolbarItem; diff --git a/webapp/src/views/dataset/medical/viewer/toolbarMore.vue b/webapp/src/views/dataset/medical/viewer/toolbarMore.vue new file mode 100644 index 0000000..209ce6b --- /dev/null +++ b/webapp/src/views/dataset/medical/viewer/toolbarMore.vue @@ -0,0 +1,181 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/dataset/nlp/annotation/index.vue b/webapp/src/views/dataset/nlp/annotation/index.vue new file mode 100644 index 0000000..1ceacdc --- /dev/null +++ b/webapp/src/views/dataset/nlp/annotation/index.vue @@ -0,0 +1,439 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + \ No newline at end of file diff --git a/webapp/src/views/dataset/nlp/annotation/sidebar/add.vue b/webapp/src/views/dataset/nlp/annotation/sidebar/add.vue new file mode 100644 index 0000000..6eb25f7 --- /dev/null +++ b/webapp/src/views/dataset/nlp/annotation/sidebar/add.vue @@ -0,0 +1,131 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + diff --git a/webapp/src/views/dataset/nlp/annotation/sidebar/index.vue b/webapp/src/views/dataset/nlp/annotation/sidebar/index.vue new file mode 100644 index 0000000..b5b6875 --- /dev/null +++ b/webapp/src/views/dataset/nlp/annotation/sidebar/index.vue @@ -0,0 +1,63 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + \ No newline at end of file diff --git a/webapp/src/views/dataset/nlp/annotation/sidebar/labelList.vue b/webapp/src/views/dataset/nlp/annotation/sidebar/labelList.vue new file mode 100644 index 0000000..a2aaf83 --- /dev/null +++ b/webapp/src/views/dataset/nlp/annotation/sidebar/labelList.vue @@ -0,0 +1,157 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + diff --git a/webapp/src/views/dataset/nlp/annotation/workspace/index.vue b/webapp/src/views/dataset/nlp/annotation/workspace/index.vue new file mode 100644 index 0000000..c3be650 --- /dev/null +++ b/webapp/src/views/dataset/nlp/annotation/workspace/index.vue @@ -0,0 +1,158 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + \ No newline at end of file diff --git a/webapp/src/views/dataset/nlp/textClassify/action.js b/webapp/src/views/dataset/nlp/textClassify/action.js new file mode 100644 index 0000000..2809b0a --- /dev/null +++ b/webapp/src/views/dataset/nlp/textClassify/action.js @@ -0,0 +1,76 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +export default { + name: 'textAction', + functional: true, + props: { + showDetail: Function, + doDelete: Function, + }, + render(h, { data, props }) { + const { showDetail, doDelete } = props; + const columnProps = { + ...data, + scopedSlots: { + header: () => { + return ( + + 操作 + + ); + }, + default: ({ row, $index }) => { + const btnProps = { + props: { + type: 'text', + disabled: row.disabledAction, + }, + style: { + marginLeft: '0px', + marginRight: '10px', + }, + }; + + // 查看标注按钮总会显示 + const showCheckButton = true; + const checkButton = ( + showDetail(row, $index)}> + 查看 + + ); + + // 删除按钮总会显示 + const showDeleteButton = true; + const deleteButton = ( + doDelete([{id: row.id}])}> + 删除 + + ); + + return ( + + { showCheckButton && checkButton } + { showDeleteButton && deleteButton } + + ); + }, + }, + }; + + return h('el-table-column', columnProps); + }, +}; diff --git a/webapp/src/views/dataset/nlp/textClassify/index.vue b/webapp/src/views/dataset/nlp/textClassify/index.vue new file mode 100644 index 0000000..38a66a3 --- /dev/null +++ b/webapp/src/views/dataset/nlp/textClassify/index.vue @@ -0,0 +1,597 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + + + diff --git a/webapp/src/views/dataset/nlp/textClassify/textStatus.js b/webapp/src/views/dataset/nlp/textClassify/textStatus.js new file mode 100644 index 0000000..2ca1e34 --- /dev/null +++ b/webapp/src/views/dataset/nlp/textClassify/textStatus.js @@ -0,0 +1,71 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +import { fileCodeMap, textStatusMap } from '../../util'; + +export default { + name: 'TextStatus', + functional: true, + render(h, { data, props }) { + const { statusList, filterByTextStatus, textStatusFilter } = props; + const iconClass = ['el-icon-arrow-down', 'el-icon--right']; + const textClass = [fileCodeMap.UNFINISHED, fileCodeMap.FINISHED, null].includes(textStatusFilter) ? null : 'primary'; + const columnProps = { + ...data, + scopedSlots: { + header: () => { + return ( + + + 标注状态 + + + + {statusList.map(item => { + return ( + filterByTextStatus(item.value)} + > + {item.label} + + ); + })} + + + ); + }, + default: ({ row }) => { + const status = textStatusMap[row.status] || {}; + const colorProps = (!status.type && status.bgColor) && { + props: { + color: status.bgColor, + }, + style: { + color: status.color, + borderColor: status.bgColor, + }, + }; + return ( + {status.name} + ); + }, + }, + }; + + return h('el-table-column', columnProps); + }, +}; diff --git a/webapp/src/views/dataset/style/list.scss b/webapp/src/views/dataset/style/list.scss index 6741ece..276435a 100644 --- a/webapp/src/views/dataset/style/list.scss +++ b/webapp/src/views/dataset/style/list.scss @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ @import "~@/assets/styles/variables.scss"; -.group-cascader{ - .el-cascader-menu__wrap{ - max-height: 300px; - min-height: 100px; +.group-cascader { + .el-cascader-menu__wrap { max-width: 280px; + min-height: 100px; + max-height: 300px; } } @@ -95,6 +95,7 @@ } .requirement { + margin-left: 20px; font-size: 14px; color: $infoColor; } diff --git a/webapp/src/views/dataset/util.js b/webapp/src/views/dataset/util.js index c6b6103..ac3fd85 100644 --- a/webapp/src/views/dataset/util.js +++ b/webapp/src/views/dataset/util.js @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,9 +14,11 @@ * ============================================================= */ -import { parseBbox, flatBbox, generateUuid } from '@/utils'; +import { parseBbox, flatBbox, generateUuid, promisifyFileReader } from '@/utils'; import { bucketName, bucketHost } from '@/utils/minIO'; +const jschardet = require("jschardet"); + // 解析 annotation 信息 export const parseAnnotation = (annotationStr, labels) => { let result = []; @@ -86,11 +88,22 @@ export const stringifyAnnotations = (annotations) => { return resultString; }; +// 根据文件信息返回结果 +export const buildUrlItem = d => ({ + url: `${bucketName}/${d.data.objectName}`, + ...(d.data.meta || {}), // 附加的信息,目前只包括 width, height +}); + // 解析 minIO 返回的图片 const buildImgUrl = (list = []) => { - return list.map(d => ({ - url: `${bucketName}/${d.data.objectName}`, - ...(d.data.meta || {}), // 附加的信息,目前只包括 width, height + return list.map(buildUrlItem); +}; + +// 解析minIO 返回的文本 +const buildTextUrl = (list = []) => { + return list.map(res => ({ + url: `${bucketName}/${res.data.objectName}`, + ...(res.data.meta || {}), })); }; @@ -121,6 +134,10 @@ export const getImgFromMinIO = (res) => { return buildImgUrl(res); }; +export const getTextFromMinIO = (res) => { + return buildTextUrl(res); +}; + const defaultTransform = d => ({ id: d.id, url: `${bucketHost}/${d.url}`, @@ -191,11 +208,27 @@ export const enhanceSymbol = Symbol('enhance'); export const dataTypeMap = { 0: '图片', 1: '视频', + 2: '文本', }; export const dataTypeCodeMap = { 'IMAGE': 0, 'VIDEO': 1, + 'TEXT': 2, +}; + +// 存储用户选择数据集场景(视觉/文本场景:0,医学场景:1) +export const cacheDatasetType = (type) => localStorage.setItem('datasetListType', type); + +export const getDatasetType = () => { + let datasetListType; + try { + datasetListType = JSON.parse(localStorage.getItem('datasetListType')); + } catch (err) { + console.error(err); + throw err; + } + return datasetListType; }; // 文件状态 @@ -218,14 +251,15 @@ export const fileCodeMap = { 'MANUAL_ANNOTATED': 104, 'UNRECOGNIZED': 105, 'TRACK_SUCCEED': 201, - 'UNCOMPLETED': 301, - 'COMPLETED': 302, + 'UNFINISHED': 301, + 'FINISHED': 302, }; export const annotationCodeMap = { 'ANNOTATE': 1, 'CLASSIFY': 2, 'TRACK': 5, + 'TEXTCLASSIFY': 6, }; export const annotationMap = { @@ -234,8 +268,14 @@ export const annotationMap = { // 3: { name: '行为分析', urlPrefix: 'analysis' }, // 4: { name: '异常检测', urlPrefix: 'exception' }, 5: { name: '目标跟踪', urlPrefix: 'track', component: 'TrackDataset' }, + 6: { name: '文本分类', urlPrefix: 'textclassify', component: 'TextClassify'}, }; +// 数据类型和标注类型的对应关系 +export const dataTypeAnnotateTypeMap = new Map() + .set(dataTypeCodeMap.VIDEO, annotationCodeMap.TRACK) + .set(dataTypeCodeMap.TEXT, annotationCodeMap.TEXTCLASSIFY); + // 数据集状态 export const datasetStatusMap = { 101: { name: '未标注', type: 'info' }, @@ -268,6 +308,24 @@ export const statusCodeMap = { 402: 'IMPORTING', }; +// 文本数据集状态 +export const textStatusMap = { + 101: { name: '未标注', 'color': '#FFFFFF'}, + 103: { name: '自动标注完成', 'color': '#468CFF' }, + 104: { name: '手动标注完成', 'color': '#FF9943' }, + 105: { name: '未识别', 'color': '#FFFFFF'}, +}; + +export const textFinishedMap = { + 103: '自动标注完成', + 104: '手动标注完成', +}; + +export const textUnfinishedMap = { + 101: '未标注', + 105: '未识别', +}; + // 标注精度 export const annotationProgressMap = { finished: '已完成', @@ -284,6 +342,13 @@ export const decompressProgressMap = { 3: '解压失败', }; +export const publishStateMap = { + 4: 'PUBLISHING', +}; + +// 发布中 +export const isPublishDataset = row => publishStateMap[row.dataConversion] === 'PUBLISHING'; + // 数据增强类型 export const dataEnhanceMap = { 1: '', @@ -293,7 +358,33 @@ export const dataEnhanceMap = { }; // 根据value取key -export const findKey = (value, data, compare = (a, b) => a === b) => -{ +export const findKey = (value, data, compare = (a, b) => a === b) => +{ return Object.keys(data).find(k => compare(data[k], value)); -}; \ No newline at end of file +}; + +// TODO: 覆盖更多 case? +const charsetMap = { + 'gbk': ['windows-1253'], + 'utf-8': ['ascii', 'windows-1252'], +}; + +// 读取文本文件,解决中文文本字符编码乱码 +export const readTxt = async (url, encoding) => { + const result = await fetch(url); + const blob = await result.blob(); + const txt = await blob.text(); + + const chardet = jschardet.detect(txt); + let nextEncoding; + if(chardet.encoding) { + for(const [key, arr] of Object.entries(charsetMap)) { + if(arr.includes(chardet.encoding)) { + nextEncoding = key; + break; + } + } + } + const text = await promisifyFileReader(blob, encoding || nextEncoding || 'utf-8'); + return text; +}; diff --git a/webapp/src/views/dataset/version/actions.vue b/webapp/src/views/dataset/version/actions.vue index 8d526fa..c715a2d 100644 --- a/webapp/src/views/dataset/version/actions.vue +++ b/webapp/src/views/dataset/version/actions.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@
详情 - 查看标注 + 查看标注 删除 - + 导出 @@ -58,7 +58,7 @@ import { computed } from '@vue/composition-api'; import { Message } from 'element-ui'; import { toFixed, downloadZipFromObjectPath } from '@/utils'; -import { datasetStatusMap, annotationMap } from '@/views/dataset/util'; +import { datasetStatusMap, annotationMap, isPublishDataset } from '@/views/dataset/util'; import { toggleVersion, deleteVersion } from '@/api/preparation/dataset'; import { TableTooltip } from '@/hooks/tooltip'; @@ -77,9 +77,9 @@ export default { setup(props, ctx) { const { actions } = props; const { $router } = ctx.root; - - // 数据发布后,后台会进行文件转换,导出数据集需要图片和标注文件,无需二进制文件,故转换状态码为1,2,3 - const downloadDisabled = computed(() => [1, 2, 3].includes(props.row.dataConversion)); + + // 发布中 + const publishing = computed(() => isPublishDataset(props.row)); const isCurrent = computed(() => !!props.row.isCurrent); const title = computed(() => `${props.row.name}(${props.row.versionName})`); @@ -142,7 +142,7 @@ export default { const keyAccessor = (key, idx, data) => data[key].label; return { - downloadDisabled, + publishing, isCurrent, title, labels: Object.keys(list), diff --git a/webapp/src/views/dataset/version/index.vue b/webapp/src/views/dataset/version/index.vue index 9f0af08..e8fdbf6 100644 --- a/webapp/src/views/dataset/version/index.vue +++ b/webapp/src/views/dataset/version/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/development/components/CreateDialog.vue b/webapp/src/views/development/components/CreateDialog.vue index d572cd9..ffccc2c 100644 --- a/webapp/src/views/development/components/CreateDialog.vue +++ b/webapp/src/views/development/components/CreateDialog.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,9 +32,39 @@ - - - + + + + + + @@ -50,15 +80,20 @@ diff --git a/webapp/src/views/modelOptimize/components/customizeForm.vue b/webapp/src/views/modelOptimize/components/customizeForm.vue new file mode 100644 index 0000000..31ba51e --- /dev/null +++ b/webapp/src/views/modelOptimize/components/customizeForm.vue @@ -0,0 +1,403 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/modelOptimize/components/optimizeForm.vue b/webapp/src/views/modelOptimize/components/optimizeForm.vue new file mode 100644 index 0000000..ae43962 --- /dev/null +++ b/webapp/src/views/modelOptimize/components/optimizeForm.vue @@ -0,0 +1,268 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/modelOptimize/components/optimizeResult.vue b/webapp/src/views/modelOptimize/components/optimizeResult.vue new file mode 100644 index 0000000..ae6206a --- /dev/null +++ b/webapp/src/views/modelOptimize/components/optimizeResult.vue @@ -0,0 +1,134 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/modelOptimize/components/quickUploadPopover.vue b/webapp/src/views/modelOptimize/components/quickUploadPopover.vue new file mode 100644 index 0000000..0a666d1 --- /dev/null +++ b/webapp/src/views/modelOptimize/components/quickUploadPopover.vue @@ -0,0 +1,216 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + diff --git a/webapp/src/views/modelOptimize/components/recordDetail.vue b/webapp/src/views/modelOptimize/components/recordDetail.vue new file mode 100644 index 0000000..99c8a4b --- /dev/null +++ b/webapp/src/views/modelOptimize/components/recordDetail.vue @@ -0,0 +1,114 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/modelOptimize/index.vue b/webapp/src/views/modelOptimize/index.vue new file mode 100644 index 0000000..ebaf7e6 --- /dev/null +++ b/webapp/src/views/modelOptimize/index.vue @@ -0,0 +1,408 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/modelOptimize/record.vue b/webapp/src/views/modelOptimize/record.vue new file mode 100644 index 0000000..d1f4a08 --- /dev/null +++ b/webapp/src/views/modelOptimize/record.vue @@ -0,0 +1,527 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + + + + + + diff --git a/webapp/src/views/modelOptimize/util.js b/webapp/src/views/modelOptimize/util.js new file mode 100644 index 0000000..61afa80 --- /dev/null +++ b/webapp/src/views/modelOptimize/util.js @@ -0,0 +1,64 @@ +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============================================================= +*/ + +// 内置算法分类 +export const OPTIMIZE_ALGORITHM_TYPE_ENUM = { + PRUNE: 0, // 剪枝 + DISTILL: 1, // 蒸馏 + QUNTIFICAT: 2, // 量化 +}; + +export const OPTIMIZE_ALGORITHM_TYPE_MAP = { + [OPTIMIZE_ALGORITHM_TYPE_ENUM.PRUNE]: '剪枝', + [OPTIMIZE_ALGORITHM_TYPE_ENUM.DISTILL]: '蒸馏', + [OPTIMIZE_ALGORITHM_TYPE_ENUM.QUNTIFICAT]: '量化', +}; + +export const OPTIMIZE_STATUS_ENUM = { + WAITING: '-1', + RUNNING: '0', + FINISHED: '1', + CANCELED: '2', + FAILED: '3', +}; + +export const OPTIMIZE_STATUS_MAP = { + [OPTIMIZE_STATUS_ENUM.WAITING]: { name: '等待中' }, + [OPTIMIZE_STATUS_ENUM.RUNNING]: { name: '进行中' }, + [OPTIMIZE_STATUS_ENUM.FINISHED]: { name: '已完成', tagMap: 'success' }, + [OPTIMIZE_STATUS_ENUM.CANCELED]: { name: '已取消', tagMap: 'info' }, + [OPTIMIZE_STATUS_ENUM.FAILED]: { name: '执行失败', tagMap: 'danger' }, +}; + +export const OPTIIMZE_ALGORITHM_USAGE_NAME = '模型优化'; + +export const RESULT_NAME_MAP = { + 'accuracy': '准确度', + 'reasoningTime': '推理速度', + 'modelSize': '模型大小', +}; + +export const RESULT_STATUS_ENUM = { + NAGATIVE: '-1', + SAME: '0', + POSITIVE: '1', +}; + +export const RESULT_STATUS_MAP = { + [RESULT_STATUS_ENUM.NAGATIVE]: 'decline', + [RESULT_STATUS_ENUM.SAME]: '', + [RESULT_STATUS_ENUM.POSITIVE]: 'promote', +}; diff --git a/webapp/src/views/register.vue b/webapp/src/views/register.vue index 573a822..9e2f166 100644 --- a/webapp/src/views/register.vue +++ b/webapp/src/views/register.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/resetpassword.vue b/webapp/src/views/resetpassword.vue index 8465bf3..ee29bd4 100644 --- a/webapp/src/views/resetpassword.vue +++ b/webapp/src/views/resetpassword.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/system/menu/index.vue b/webapp/src/views/system/menu/index.vue deleted file mode 100644 index 211c141..0000000 --- a/webapp/src/views/system/menu/index.vue +++ /dev/null @@ -1,265 +0,0 @@ -/* -* Copyright 2019-2020 Zheng Jie -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - - - - diff --git a/webapp/src/views/system/node/index.vue b/webapp/src/views/system/node/index.vue index 96479af..ae540ce 100644 --- a/webapp/src/views/system/node/index.vue +++ b/webapp/src/views/system/node/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/system/role/index.vue b/webapp/src/views/system/role/index.vue index 7495061..c4afc83 100644 --- a/webapp/src/views/system/role/index.vue +++ b/webapp/src/views/system/role/index.vue @@ -82,7 +82,7 @@ @@ -126,8 +126,7 @@ import cdOperation from '@crud/CD.operation'; import udOperation from '@crud/UD.operation'; import pagination from '@crud/Pagination'; import { validateName } from '@/utils/validate'; -import crudRoles, {editMenu, get} from '@/api/system/role'; -import { getMenusTree } from '@/api/system/menu'; +import crudRoles, { editMenu, get, getMenusTree } from '@/api/system/role'; import BaseModal from '@/components/BaseModal'; import datePickerMixin from '@/mixins/datePickerMixin'; diff --git a/webapp/src/views/system/user/index.vue b/webapp/src/views/system/user/index.vue index e216800..ba3145b 100644 --- a/webapp/src/views/system/user/index.vue +++ b/webapp/src/views/system/user/index.vue @@ -252,7 +252,7 @@ export default { }, afterErrorMethod() { // 恢复select - this.crud.form.roleId = crud.form.roles[0]?.id || ''; + this.crud.form.roleId = this.crud.form.roles[0]?.id || ''; }, // 新增与编辑前做的操作 [CRUD.HOOK.afterToCU]() { diff --git a/webapp/src/views/trainingImage/index.vue b/webapp/src/views/trainingImage/index.vue index e97a921..c351040 100644 --- a/webapp/src/views/trainingImage/index.vue +++ b/webapp/src/views/trainingImage/index.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,8 +34,9 @@
- - + + + - + @@ -71,12 +72,32 @@ {{ parseTime(scope.row.createTime) }} - + + + + @@ -92,6 +113,7 @@ :loading="crud.status.cu === 2" :disabled="loading" width="600px" + @open="onDialogOpen" @close="onDialogClose" @cancel="crud.cancelCU" @ok="crud.submitCU" @@ -102,6 +124,12 @@ :rules="rules" label-width="120px" > + + + 训练镜像 + notebook镜像 + + + \ No newline at end of file diff --git a/webapp/src/views/trainingJob/add.vue b/webapp/src/views/trainingJob/add.vue index 2072c3c..2ae3d80 100644 --- a/webapp/src/views/trainingJob/add.vue +++ b/webapp/src/views/trainingJob/add.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/webapp/src/views/trainingJob/components/jobDetail.vue b/webapp/src/views/trainingJob/components/jobDetail.vue index 16e65c9..a6fee3a 100644 --- a/webapp/src/views/trainingJob/components/jobDetail.vue +++ b/webapp/src/views/trainingJob/components/jobDetail.vue @@ -1,4 +1,4 @@ -/** Copyright 2020 Zhejiang Lab. All Rights Reserved. +/** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ */