- 标注:AI 预标注直写 labels_json(去候选确认两阶段);重叠去重(minIoU);全量标注按钮 - 训练:脚本迁移入 server/training/(Go 化 prepare_yolo/analyze_rfdetr,保留 train_server.py);tflite 产物自检并入训练流程(check_tflite) - 数据目录/权重不进 git;.gitignore 迁移至仓库根
136 lines
3.1 KiB
Vue
136 lines
3.1 KiB
Vue
<script setup>
|
||
import { computed } from 'vue'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import {
|
||
List as ListIcon,
|
||
Key as KeyIcon,
|
||
Refresh as RefreshIcon,
|
||
SwitchButton as SwitchIcon,
|
||
Picture as PictureIcon,
|
||
} from '@element-plus/icons-vue'
|
||
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
|
||
// 详情页 /datasets/:id 仍高亮「数据训练」菜单项
|
||
const activeMenu = computed(() =>
|
||
route.path.startsWith('/datasets') ? '/datasets' : route.path,
|
||
)
|
||
|
||
function logout() {
|
||
localStorage.removeItem('adminToken')
|
||
router.push('/login')
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<!-- 登录页独立全屏,不套后台布局 -->
|
||
<router-view v-if="route.path === '/login'" />
|
||
|
||
<el-container v-else class="app-layout">
|
||
<el-aside width="200px" class="app-aside">
|
||
<el-menu :default-active="activeMenu" router>
|
||
<el-menu-item index="/datasets">
|
||
<el-icon><PictureIcon /></el-icon>
|
||
<span>数据训练</span>
|
||
</el-menu-item>
|
||
<el-menu-item index="/orders">
|
||
<el-icon><ListIcon /></el-icon>
|
||
<span>订单管理</span>
|
||
</el-menu-item>
|
||
<el-menu-item index="/licenses">
|
||
<el-icon><KeyIcon /></el-icon>
|
||
<span>授权管理</span>
|
||
</el-menu-item>
|
||
<el-menu-item index="/app-versions">
|
||
<el-icon><RefreshIcon /></el-icon>
|
||
<span>版本管理</span>
|
||
</el-menu-item>
|
||
</el-menu>
|
||
</el-aside>
|
||
<el-container>
|
||
<el-header class="app-header">
|
||
<span class="app-header-title">{{ route.meta.title }}</span>
|
||
<el-button link :icon="SwitchIcon" class="app-header-logout" @click="logout">退出登录</el-button>
|
||
</el-header>
|
||
<el-main class="app-main">
|
||
<router-view />
|
||
</el-main>
|
||
</el-container>
|
||
</el-container>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.app-layout {
|
||
height: 100vh;
|
||
}
|
||
.app-aside {
|
||
background: #001529;
|
||
}
|
||
.app-aside :deep(.el-menu) {
|
||
border-right: none;
|
||
background: #001529;
|
||
}
|
||
.app-aside :deep(.el-menu-item) {
|
||
color: rgba(255, 255, 255, 0.7);
|
||
}
|
||
.app-aside :deep(.el-menu-item.is-active),
|
||
.app-aside :deep(.el-menu-item:hover) {
|
||
color: #fff;
|
||
background: #1890ff;
|
||
}
|
||
.app-header {
|
||
background: #fff;
|
||
border-bottom: 1px solid #e4e7ed;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
.app-header-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
.app-main {
|
||
background: #f0f2f5;
|
||
}
|
||
|
||
/* 手机竖屏:侧栏收为顶部横向菜单,页面自然滚动 */
|
||
@media (max-width: 767px) {
|
||
.app-layout {
|
||
display: block;
|
||
height: auto;
|
||
}
|
||
.app-aside {
|
||
width: 100% !important;
|
||
}
|
||
.app-logo {
|
||
height: 48px;
|
||
line-height: 48px;
|
||
font-size: 15px;
|
||
}
|
||
.app-aside :deep(.el-menu) {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
border-bottom: none;
|
||
}
|
||
.app-aside :deep(.el-menu-item) {
|
||
flex: 1;
|
||
justify-content: center;
|
||
height: 44px;
|
||
line-height: 44px;
|
||
min-width: 96px;
|
||
}
|
||
.app-header {
|
||
height: 48px;
|
||
padding: 0 12px;
|
||
}
|
||
.app-main {
|
||
overflow: visible;
|
||
padding: 10px;
|
||
}
|
||
.app-main :deep(.el-card) {
|
||
overflow-x: auto;
|
||
}
|
||
}
|
||
</style>
|