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 +- webapp/src/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 + .../{system/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 +- .../src/assets/images/dataset/medicalDataset.png | Bin 0 -> 37162 bytes webapp/src/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 +- webapp/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 +- webapp/src/components/InfoSelect/info-select.vue | 2 +- webapp/src/components/InfoTable/column.js | 2 +- webapp/src/components/InfoTable/index.js | 2 +- webapp/src/components/InfoTable/info-table.vue | 31 +- webapp/src/components/InlineTableEdit/index.vue | 9 +- webapp/src/components/LogContainer/index.vue | 8 +- .../components/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 +- webapp/src/components/Training/algorithmDetail.vue | 4 +- .../src/components/Training/dataSourceSelector.vue | 2 +- webapp/src/components/Training/jobForm.vue | 479 +- webapp/src/components/Training/paramPair.vue | 8 +- webapp/src/components/Training/runParamForm.vue | 20 +- webapp/src/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 +- webapp/src/components/UploadProgress/index.vue | 6 +- webapp/src/components/ZoomContainer/index.vue | 2 +- webapp/src/components/svg/brush/Brush.js | 2 +- webapp/src/components/svg/brush/BrushCorner.js | 2 +- webapp/src/components/svg/brush/BrushHandle.js | 2 +- webapp/src/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 +- webapp/src/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 +- webapp/src/layout/components/AppMain/index.vue | 2 +- webapp/src/layout/components/Feedback/index.vue | 2 +- webapp/src/layout/components/Guideline/index.vue | 5 +- webapp/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 + .../cloudServing/components/forms/servingForm.vue | 332 + .../components/forms/servingModelConfig.vue | 481 ++ .../components/keyValueTable/index.vue | 74 + .../cloudServing/components/modelDetail/index.vue | 127 + .../components/servingCallGuide/index.vue | 145 + .../components/servingCallGuide/servingApiInfo.vue | 58 + .../components/servingDeploymentRecord/index.vue | 194 + .../cloudServing/components/servingLog/index.vue | 338 + .../components/servingMonitor/index.vue | 113 + .../servingMonitor/servingMonitorCard.vue | 158 + .../servingMonitor/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 + .../src/views/dashboard/components/CardPanel.vue | 2 +- webapp/src/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 +- .../dataset/annotate/settingContainer/enhance.vue | 2 +- .../annotate/settingContainer/enhanceTip.vue | 2 +- .../dataset/annotate/settingContainer/footer.vue | 2 +- .../dataset/annotate/settingContainer/index.vue | 5 +- .../dataset/annotate/settingContainer/label.vue | 2 +- .../annotate/settingContainer/labelList/edit.vue | 4 +- .../annotate/settingContainer/labelList/index.vue | 17 +- .../dataset/annotate/settingContainer/labelTip.vue | 2 +- .../annotate/settingContainer/selectLabel.vue | 2 +- .../dataset/annotate/thumbContainer/index.vue | 3 +- .../views/dataset/annotate/thumbContainer/list.vue | 2 +- .../dataset/annotate/thumbContainer/listItem.js | 2 +- .../annotate/workSpaceContainer/annotationId.js | 2 +- .../dataset/annotate/workSpaceContainer/bbox.js | 2 +- .../annotate/workSpaceContainer/bboxWrapper.js | 2 +- .../annotate/workSpaceContainer/brushTip.js | 2 +- .../workSpaceContainer/dropdownLabel/index.js | 2 +- .../workSpaceContainer/dropdownLabel/style.scss | 2 +- .../dataset/annotate/workSpaceContainer/index.vue | 2 +- .../dataset/annotate/workSpaceContainer/score.js | 2 +- .../dataset/annotate/workSpaceContainer/tag.js | 2 +- .../annotate/workSpaceContainer/toolbar.vue | 34 +- webapp/src/views/dataset/classify.vue | 67 +- .../dataset/components/picInfoModal/index.vue | 2 +- .../views/dataset/components/searchLabel/index.vue | 4 +- .../src/views/dataset/components/tenant/index.vue | 63 + .../dataset/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 +- webapp/src/views/dataset/list/create-dataset.vue | 220 +- webapp/src/views/dataset/list/data-enhance.vue | 2 +- webapp/src/views/dataset/list/edit-dataset.vue | 72 +- webapp/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 +- webapp/src/views/dataset/list/upload-datafile.vue | 129 +- webapp/src/views/dataset/medical/action.js | 105 + webapp/src/views/dataset/medical/constant.js | 74 + .../src/views/dataset/medical/create-dataset.vue | 294 + webapp/src/views/dataset/medical/edit-dataset.vue | 127 + webapp/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 + webapp/src/views/dataset/medical/lib/overlays.json | 22 + webapp/src/views/dataset/medical/list.vue | 650 ++ webapp/src/views/dataset/medical/status.js | 71 + webapp/src/views/dataset/medical/viewer/action.vue | 362 + .../src/views/dataset/medical/viewer/controls.vue | 209 + .../src/views/dataset/medical/viewer/helpInfo.vue | 118 + webapp/src/views/dataset/medical/viewer/index.vue | 780 +++ .../src/views/dataset/medical/viewer/infoLayer.vue | 164 + .../views/dataset/medical/viewer/lesionInfo.vue | 215 + .../src/views/dataset/medical/viewer/toolbar.vue | 90 + .../views/dataset/medical/viewer/toolbarButton.vue | 80 + .../views/dataset/medical/viewer/toolbarItem.js | 67 + .../views/dataset/medical/viewer/toolbarMore.vue | 181 + webapp/src/views/dataset/nlp/annotation/index.vue | 439 ++ .../views/dataset/nlp/annotation/sidebar/add.vue | 131 + .../views/dataset/nlp/annotation/sidebar/index.vue | 63 + .../dataset/nlp/annotation/sidebar/labelList.vue | 157 + .../dataset/nlp/annotation/workspace/index.vue | 158 + .../src/views/dataset/nlp/textClassify/action.js | 76 + .../src/views/dataset/nlp/textClassify/index.vue | 597 ++ .../views/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 +- .../views/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 +- webapp/src/views/labelGroup/labelGroupAction.js | 2 +- webapp/src/views/labelGroup/labelGroupForm.vue | 68 +- webapp/src/views/labelGroup/util.js | 25 + webapp/src/views/login.vue | 2 +- .../src/views/model/components/addModelDialog.vue | 28 +- webapp/src/views/model/index.vue | 63 +- webapp/src/views/model/version.vue | 46 +- .../views/modelOptimize/components/builtInForm.vue | 233 + .../modelOptimize/components/customizeForm.vue | 403 ++ .../modelOptimize/components/optimizeForm.vue | 268 + .../modelOptimize/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 +- .../src/views/trainingJob/components/jobDetail.vue | 64 +- .../src/views/trainingJob/components/jobDrawer.vue | 38 +- .../trainingJob/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 +- .../src/views/visual/Visual/customs/Category.vue | 2 +- webapp/src/views/visual/Visual/customs/Customs.vue | 2 +- .../views/visual/Visual/customs/CustomsPanel.vue | 2 +- webapp/src/views/visual/Visual/customs/index.js | 2 +- .../visual/Visual/embeddings/EmbeddingDraw.vue | 2 +- .../views/visual/Visual/embeddings/Embeddings.vue | 2 +- .../visual/Visual/embeddings/EmbeddingsPanel.vue | 2 +- webapp/src/views/visual/Visual/embeddings/index.js | 2 +- .../views/visual/Visual/exception/Exception.vue | 2 +- .../visual/Visual/exception/ExceptionPanel.vue | 2 +- .../visual/Visual/exception/excepContainer.vue | 2 +- webapp/src/views/visual/Visual/exception/index.js | 2 +- .../src/views/visual/Visual/features/Features.vue | 2 +- .../views/visual/Visual/features/FeaturesPanel.vue | 2 +- webapp/src/views/visual/Visual/features/index.js | 2 +- webapp/src/views/visual/Visual/graphs/Graphs.vue | 2 +- .../src/views/visual/Visual/graphs/GraphsPanel.vue | 2 +- webapp/src/views/visual/Visual/graphs/index.js | 2 +- .../views/visual/Visual/hyperparms/HyperPara.vue | 2 +- .../views/visual/Visual/hyperparms/Hyperparms.vue | 2 +- .../visual/Visual/hyperparms/HyperparmsPanel.vue | 2 +- webapp/src/views/visual/Visual/hyperparms/index.js | 2 +- webapp/src/views/visual/Visual/medias/Medias.vue | 2 +- .../src/views/visual/Visual/medias/MediasPanel.vue | 2 +- .../views/visual/Visual/medias/audio/Audios.vue | 2 +- .../medias/audio/audioContainer/AudioContainer.vue | 2 +- .../Visual/medias/audio/audioContainer/index.js | 2 +- .../src/views/visual/Visual/medias/audio/index.js | 2 +- .../views/visual/Visual/medias/image/Images.vue | 2 +- .../medias/image/imagecontainer/ImageContainer.vue | 2 +- .../Visual/medias/image/imagecontainer/index.js | 2 +- .../src/views/visual/Visual/medias/image/index.js | 2 +- webapp/src/views/visual/Visual/medias/index.js | 2 +- .../src/views/visual/Visual/medias/text/Texts.vue | 2 +- .../src/views/visual/Visual/medias/text/index.js | 2 +- .../medias/text/textContainer/TextContainer.vue | 2 +- .../Visual/medias/text/textContainer/index.js | 2 +- webapp/src/views/visual/Visual/rocs/ROCs.vue | 2 +- webapp/src/views/visual/Visual/rocs/ROCsPanel.vue | 2 +- webapp/src/views/visual/Visual/rocs/index.js | 2 +- webapp/src/views/visual/Visual/scalars/Scalars.vue | 2 +- .../views/visual/Visual/scalars/ScalarsPanel.vue | 2 +- webapp/src/views/visual/Visual/scalars/index.js | 2 +- .../scalars/scalarcontainer/ScalarContainer.vue | 2 +- .../scalars/scalarcontainer/ScalarCustom.vue | 2 +- .../visual/Visual/scalars/scalarcontainer/index.js | 2 +- .../scalarcontainer/scalarchart/Scalarchart.vue | 2 +- .../scalars/scalarcontainer/scalarchart/index.js | 2 +- .../visual/Visual/scalars/subscalar/SubScalars.vue | 2 +- .../views/visual/Visual/scalars/subscalar/index.js | 2 +- .../views/visual/Visual/statistics/Statistics.vue | 2 +- .../visual/Visual/statistics/StatisticsPanel.vue | 2 +- .../Visual/statistics/drawStatistic/HisOrtho.vue | 2 +- .../statistics/drawStatistic/HisOverlook.vue | 2 +- .../Visual/statistics/drawStatistic/HisThreeD.vue | 2 +- .../Visual/statistics/drawStatistic/index.js | 2 +- .../drawStatistic/statisticContainer.vue | 2 +- webapp/src/views/visual/Visual/statistics/index.js | 2 +- .../statistics/substatistic/SubStatistics.vue | 2 +- .../visual/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 KcmV+b0RR6000031 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 @@ */