diff --git a/platform/frontend/navigation-component.js b/platform/frontend/navigation-component.js index 61ae6ff..bd05d6e 100644 --- a/platform/frontend/navigation-component.js +++ b/platform/frontend/navigation-component.js @@ -1,5 +1,6 @@ -// 公共导航组件定义 +// 公共导航组件定义(使用 render 函数,兼容 prod 版 Vue) const NavigationComponent = { + name: 'NavigationComponent', props: { currentPage: { type: String, @@ -11,206 +12,110 @@ const NavigationComponent = { default: false } }, - template: ` - - ` + const sidebarItems = [ + { icon: '📊', label: '系统概览', page: 'dashboard' }, + { icon: '📋', label: '选题管理', page: 'topics' }, + { icon: '📄', label: '系统日志', page: 'logs' }, + ...(this.isAdmin ? [ + { icon: '👥', label: '用户管理', page: 'users' }, + { icon: '⚙️', label: '系统管理', page: 'admin' } + ] : []) + ]; + + const mobileItems = [ + { icon: '📊', label: '', page: 'dashboard' }, + { icon: '📋', label: '选题', page: 'topics' }, + { icon: '📄', label: '日志', page: 'logs' }, + ...(this.isAdmin ? [ + { icon: '👥', label: '用户', page: 'users' }, + { icon: '⚙️', label: '系统', page: 'admin' } + ] : []) + ]; + + const createSidebarBtn = (item) => { + const isActive = this.currentPage === item.page; + return h('button', { + class: isActive ? 'sidebar-btn active' : 'sidebar-btn', + on: { click: () => navigate(item.page) } + }, [item.icon, ' ', item.label].join('')); + }; + + const createMobileBtn = (item) => { + const isActive = this.currentPage === item.page; + const content = item.label ? [item.icon, item.label].join('') : item.icon; + return h('button', { + class: isActive ? 'mobile-nav-btn active' : 'mobile-nav-btn', + on: { click: () => navigate(item.page) } + }, content); + }; + + return h('div', { class: 'navigation-wrapper' }, [ + h('aside', { class: 'sidebar' }, [ + h('div', { class: 'sidebar-header' }, [h('h3', '宇之然平台')]), + h('nav', { class: 'sidebar-nav' }, sidebarItems.map(createSidebarBtn)) + ]), + h('nav', { class: 'mobile-nav' }, mobileItems.map(createMobileBtn)) + ]); + } }; -// 注入公共样式(如果尚未注入) function injectNavigationStyles() { if (document.getElementById('navigation-styles')) return; - const styles = ` - /* 导航组件样式 */ + .navigation-wrapper { position: relative; } .navigation-wrapper .sidebar { - width: 180px; - background: white; - padding: 12px; - box-shadow: 2px 0 8px rgba(0,0,0,0.05); - position: fixed; - left: 0; - top: 60px; - bottom: 0; - overflow-y: auto; - z-index: 100; - } - .navigation-wrapper .sidebar-header { - padding: 12px 8px 16px; - border-bottom: 1px solid #ebeef5; - margin-bottom: 12px; - } - .navigation-wrapper .sidebar-header h3 { - margin: 0; - font-size: 16px; - font-weight: 600; - color: #303133; + width: 180px; background: white; padding: 12px; box-shadow: 2px 0 8px rgba(0,0,0,0.05); + position: fixed; left: 0; top: 60px; bottom: 0; overflow-y: auto; z-index: 100; } + .navigation-wrapper .sidebar-header { padding: 12px 8px 16px; border-bottom: 1px solid #ebeef5; margin-bottom: 12px; } + .navigation-wrapper .sidebar-header h3 { margin: 0; font-size: 16px; font-weight: 600; color: #303133; } .navigation-wrapper .sidebar-btn { - width: 100%; - text-align: left; - padding: 10px 12px; - border: none; - background: transparent; - border-radius: 8px; - margin-bottom: 6px; - cursor: pointer; - transition: all 0.3s; - color: #606266; - font-size: 14px; - display: flex; - align-items: center; - gap: 6px; - } - .navigation-wrapper .sidebar-btn:hover { - background: #f5f7fa; - color: #409eff; - } - .navigation-wrapper .sidebar-btn.active { - background: #ecf5ff; - color: #409eff; - font-weight: 600; + width: 100%; text-align: left; padding: 10px 12px; border: none; background: transparent; border-radius: 8px; + margin-bottom: 6px; cursor: pointer; transition: all 0.3s; color: #606266; font-size: 14px; display: flex; align-items: center; gap: 6px; } + .navigation-wrapper .sidebar-btn:hover { background: #f5f7fa; color: #409eff; } + .navigation-wrapper .sidebar-btn.active { background: #ecf5ff; color: #409eff; font-weight: 600; } .navigation-wrapper .mobile-nav { - display: none; - position: fixed; - bottom: 0; - left: 0; - right: 0; - background: white; - box-shadow: 0 -2px 8px rgba(0,0,0,0.1); - padding: 8px 0; - z-index: 1000; - justify-content: space-around; + display: none; position: fixed; bottom: 0; left: 0; right: 0; background: white; + box-shadow: 0 -2px 8px rgba(0,0,0,0.1); padding: 8px 0; z-index: 1000; justify-content: space-around; } .navigation-wrapper .mobile-nav-btn { - flex: 1; - border: none; - background: transparent; - padding: 10px 4px; - text-align: center; - font-size: 11px; - color: #606266; - cursor: pointer; - display: flex; - flex-direction: column; - align-items: center; - gap: 2px; - } - .navigation-wrapper .mobile-nav-btn:hover { - color: #409eff; - } - .navigation-wrapper .mobile-nav-btn.active { - color: #409eff; - font-weight: 600; + flex: 1; border: none; background: transparent; padding: 10px 4px; text-align: center; + font-size: 11px; color: #606266; cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 2px; } + .navigation-wrapper .mobile-nav-btn:hover { color: #409eff; } + .navigation-wrapper .mobile-nav-btn.active { color: #409eff; font-weight: 600; } @media (max-width: 768px) { - .navigation-wrapper .sidebar { - display: none !important; - } - .navigation-wrapper .mobile-nav { - display: flex; - } + .navigation-wrapper .sidebar { display: none !important; } + .navigation-wrapper .mobile-nav { display: flex !important; } } - @media (min-width: 769px) { - .navigation-wrapper .mobile-nav { - display: none !important; - } + @media (min-width: 769px) { .navigation-wrapper .mobile-nav { display: none !important; } } + body > #app > .navigation-wrapper + .main-content { margin-left: 180px; } + @media (max-width: 768px) { + body > #app > .navigation-wrapper + .main-content { margin-left: 0 !important; padding-bottom: 60px !important; } } `; - const styleEl = document.createElement('style'); styleEl.id = 'navigation-styles'; styleEl.textContent = styles; document.head.appendChild(styleEl); } -// 安装组件到Vue应用 -function installNavigation(app, options = {}) { +function installNavigation(app) { injectNavigationStyles(); - app.component('navigation-component', NavigationComponent); - - // 添加全局redirectToPage方法(兼容旧代码) - app.config.globalProperties.$redirectToPage = (path) => { - window.location.href = path; - }; - + app.config.globalProperties.$redirectToPage = (path) => { window.location.href = path; }; return app; } -// 导出到全局(兼容直接使用) if (typeof window !== 'undefined') { window.NavigationComponent = NavigationComponent; window.installNavigation = installNavigation; } - if (typeof module !== 'undefined' && module.exports) { module.exports = { NavigationComponent, installNavigation }; }