From 0d12ce5201cef6281a3ddf3f663ed660c49a046c Mon Sep 17 00:00:00 2001 From: root Date: Tue, 10 Mar 2026 17:02:58 +0800 Subject: [PATCH] feat(watermark): nested menu and 3 table list pages (#7 #8) --- src/api/watermark.js | 24 ++ src/layouts/MainLayout.vue | 88 +++++-- src/router/index.js | 25 +- src/views/watermark/layout.vue | 3 + .../watermark/video-download-failures.vue | 171 +++++++++++++ src/views/watermark/video-parse-logs.vue | 227 ++++++++++++++++++ src/views/watermark/video-parse-unlocks.vue | 186 ++++++++++++++ 7 files changed, 698 insertions(+), 26 deletions(-) create mode 100644 src/views/watermark/layout.vue create mode 100644 src/views/watermark/video-download-failures.vue create mode 100644 src/views/watermark/video-parse-logs.vue create mode 100644 src/views/watermark/video-parse-unlocks.vue diff --git a/src/api/watermark.js b/src/api/watermark.js index 3a64ee3..0d4b40e 100644 --- a/src/api/watermark.js +++ b/src/api/watermark.js @@ -28,3 +28,27 @@ export function deleteWatermarkTask(id) { method: 'delete' }) } + +export function getVideoParseLogs(params) { + return request({ + url: '/api/admin/watermark/video-parse-logs', + method: 'get', + params + }) +} + +export function getVideoParseUnlocks(params) { + return request({ + url: '/api/admin/watermark/video-parse-unlocks', + method: 'get', + params + }) +} + +export function getVideoDownloadFailures(params) { + return request({ + url: '/api/admin/watermark/video-download-failures', + method: 'get', + params + }) +} diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 703ead9..54e26aa 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -6,7 +6,6 @@ @click="closeMobileMenu" > -
管理后台 @@ -20,20 +19,36 @@ router @select="handleMenuSelect" > - - - - + - -
@@ -59,7 +74,6 @@
- @@ -122,26 +136,51 @@ watch( } ) -// 获取菜单路由(过滤掉隐藏的路由) const menuRoutes = computed(() => { - const routes = router.getRoutes() - const mainRoute = routes.find(r => r.path === '/') - if (!mainRoute || !mainRoute.children) return [] - - return mainRoute.children.filter(r => !r.meta?.hidden) + const rootRoute = router.options.routes.find((item) => item.path === '/') + if (!rootRoute || !rootRoute.children) return [] + return rootRoute.children.filter((item) => !item.meta?.hidden) }) -// 当前激活的菜单 +const visibleChildren = (routeItem) => { + return (routeItem.children || []).filter((child) => !child.meta?.hidden) +} + +const hasChildren = (routeItem) => { + return visibleChildren(routeItem).length > 0 +} + +const routeKey = (routeItem) => { + return `${routeItem.path || ''}-${routeItem.name || ''}` +} + +const resolvePath = (parentPath = '', childPath = '') => { + const normalize = (value) => { + if (!value) return '/' + return value.startsWith('/') ? value : `/${value}` + } + + const parent = normalize(parentPath) + if (!childPath) { + return parent + } + if (childPath.startsWith('/')) { + return childPath + } + return `${parent.replace(/\/$/, '')}/${childPath}`.replace(/\/{2,}/g, '/') +} + const activeMenu = computed(() => { const { path } = route - // 如果是子路由,返回父路由路径 + if (path === '/watermark') { + return '/watermark/video-parse-logs' + } if (path.includes('/create') || path.includes('/edit') || /\/\d+$/.test(path)) { return '/' + path.split('/')[1] } return path }) -// 切换侧边栏折叠状态 const toggleCollapse = () => { if (isMobile.value) { mobileMenuVisible.value = !mobileMenuVisible.value @@ -167,7 +206,6 @@ const handleResize = () => { } } -// 处理下拉菜单命令 const handleCommand = async (command) => { if (command === 'logout') { try { @@ -222,11 +260,13 @@ const handleCommand = async (command) => { background: #304156; } -:deep(.el-menu-item) { +:deep(.el-menu-item), +:deep(.el-sub-menu__title) { color: #bfcbd9; } -:deep(.el-menu-item:hover) { +:deep(.el-menu-item:hover), +:deep(.el-sub-menu__title:hover) { background: #263445 !important; color: #fff; } diff --git a/src/router/index.js b/src/router/index.js index 4b1d107..a288ebd 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -72,8 +72,29 @@ const routes = [ { path: 'watermark', name: 'Watermark', - component: () => import('../views/watermark/index.vue'), - meta: { title: '去水印管理', icon: 'Brush' } + component: () => import('../views/watermark/layout.vue'), + redirect: '/watermark/video-parse-logs', + meta: { title: '去水印小程序', icon: 'Brush' }, + children: [ + { + path: 'video-parse-logs', + name: 'VideoParseLogs', + component: () => import('../views/watermark/video-parse-logs.vue'), + meta: { title: '解析日志' } + }, + { + path: 'video-parse-unlocks', + name: 'VideoParseUnlocks', + component: () => import('../views/watermark/video-parse-unlocks.vue'), + meta: { title: '广告解锁' } + }, + { + path: 'video-download-failures', + name: 'VideoDownloadFailures', + component: () => import('../views/watermark/video-download-failures.vue'), + meta: { title: '下载失败上报' } + } + ] }, { path: 'settings', diff --git a/src/views/watermark/layout.vue b/src/views/watermark/layout.vue new file mode 100644 index 0000000..98240ae --- /dev/null +++ b/src/views/watermark/layout.vue @@ -0,0 +1,3 @@ + diff --git a/src/views/watermark/video-download-failures.vue b/src/views/watermark/video-download-failures.vue new file mode 100644 index 0000000..543d93f --- /dev/null +++ b/src/views/watermark/video-download-failures.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/src/views/watermark/video-parse-logs.vue b/src/views/watermark/video-parse-logs.vue new file mode 100644 index 0000000..7aa0817 --- /dev/null +++ b/src/views/watermark/video-parse-logs.vue @@ -0,0 +1,227 @@ + + + + + diff --git a/src/views/watermark/video-parse-unlocks.vue b/src/views/watermark/video-parse-unlocks.vue new file mode 100644 index 0000000..3bc5d0a --- /dev/null +++ b/src/views/watermark/video-parse-unlocks.vue @@ -0,0 +1,186 @@ + + + + +