feat: 构建系统重构 + VCHSM 架构迁移 + 右键菜单修复 + 尺寸参数统一
## 构建、打包与分发系统重构 (build/) - 构建系统收敛至 build/ 目录:build.mjs + electron-builder.js + 6 个脚本 - electron-builder 配置从 package.json 提取为 build/electron-builder.js - 新增 --edition (personal/enterprise) 和 --channel (stable/beta/alpha) 参数 - OSS 路径按渠道隔离 - 新增 pre-build-check.mjs:Git/CHANGELOG/版本/环境变量校验 - 新增 bump-version.mjs:版本号管理 + CHANGELOG 自动生成 - updater.ts 发送 channel/edition/deviceFingerprint - 新增 src/shared/utils/rollout.ts 灰度测试工具 - 新增 10 条 NPM 脚本 ## VCHSM 五层架构迁移 - 7 个业务模块 + ~500 处导入路径同步 ## 修复 - MediaCardContextMenu 改用共享 ContextMenu 组件 - ComboBox 尺寸参数显示统一 (size-format.ts) ## 文档 - UpdateA.md / build/README.md / README.md / .env.example 更新 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
167
src/modules/navbar/views/NavBar.tsx
Normal file
167
src/modules/navbar/views/NavBar.tsx
Normal file
@@ -0,0 +1,167 @@
|
||||
// ============================================================
|
||||
// NavBar — 自定义顶部导航栏(替代系统菜单)
|
||||
//
|
||||
// 逻辑:
|
||||
// - 所有导航项默认全部显示(不再按登录状态隐藏)
|
||||
// - 未登录时点击需登录的项 → 弹出提示"请先登录"并触发登录 Modal
|
||||
// - 登录/注册 与 退出登录 仍按登录状态互斥显示
|
||||
// ============================================================
|
||||
|
||||
import {useState, useCallback, useMemo} from 'react';
|
||||
import {App} from 'antd';
|
||||
|
||||
import {useAppContext} from '@/app/providers/AppProvider';
|
||||
import {useTheme} from '@/app/providers/ThemeProvider';
|
||||
import {emit, EVENTS, safeIpcSend} from '@/shared/utils/bus';
|
||||
import {RENDERER_TO_MAIN} from '@shared/constants/ipc-channels';
|
||||
import {useAnnouncements} from '@/shared/hooks/use-announcements';
|
||||
import {NavItem} from './NavItem';
|
||||
import {AnnouncementDrawer} from '@/modules/announcement/views/AnnouncementDrawer';
|
||||
import {personalLeft, personalRight, enterpriseLeft, enterpriseRight} from '../settings/nav-config';
|
||||
import type {NavItemConfig} from '../model/types';
|
||||
|
||||
const NAVBAR_HEIGHT = 56;
|
||||
|
||||
export function NavBar() {
|
||||
const {platform, edition, isLoggedIn, logout} = useAppContext();
|
||||
const {isDark} = useTheme();
|
||||
const {message} = App.useApp();
|
||||
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
|
||||
// 公告轮询 + 未读缓存
|
||||
const { announcements, unreadCount, loading: announcementsLoading, markAsRead } = useAnnouncements();
|
||||
|
||||
// 根据版本选择导航项
|
||||
const {leftItems, rightItems} = useMemo(() => {
|
||||
const isEnterprise = edition === 'enterprise';
|
||||
return {
|
||||
leftItems: isEnterprise ? enterpriseLeft : personalLeft,
|
||||
rightItems: isEnterprise ? enterpriseRight : personalRight,
|
||||
};
|
||||
}, [edition]);
|
||||
|
||||
// 过滤规则:
|
||||
// requireGuest → 仅未登录时可见(登录/注册)
|
||||
// "退出登录" → 仅已登录时可见
|
||||
// 其他所有项 → 始终可见,未登录点击时弹"请先登录"
|
||||
const visibleLeft = useMemo(
|
||||
() =>
|
||||
leftItems.filter((item) => {
|
||||
if (item.requireGuest && isLoggedIn) return false;
|
||||
return !(item.key === 'logout' && !isLoggedIn);
|
||||
}),
|
||||
[leftItems, isLoggedIn],
|
||||
);
|
||||
const visibleRight: NavItemConfig[] = useMemo(
|
||||
() =>
|
||||
rightItems.filter((item) => {
|
||||
if (item.requireGuest && isLoggedIn) return false;
|
||||
return !(item.key === 'logout' && !isLoggedIn);
|
||||
}),
|
||||
[rightItems, isLoggedIn],
|
||||
);
|
||||
|
||||
// 点击导航项
|
||||
const handleNavClick = useCallback(
|
||||
(item: NavItemConfig) => {
|
||||
// 需要登录但未登录 → 提示并弹出登录 Modal
|
||||
if (item.requireLogin && !isLoggedIn) {
|
||||
message.warning('请先登录');
|
||||
emit(EVENTS.SHOW_LOGIN);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (item.action) {
|
||||
case 'drawer':
|
||||
if (item.key === 'announcements') {
|
||||
setDrawerOpen(true);
|
||||
markAsRead();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'button':
|
||||
if (item.key === 'logout') {
|
||||
logout();
|
||||
} else if (item.key === 'settings') {
|
||||
emit(EVENTS.OPEN_SETTINGS);
|
||||
} else if (item.key === 'auth') {
|
||||
emit(EVENTS.SHOW_LOGIN);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'external':
|
||||
if (item.target) {
|
||||
window.open(item.target, '_blank');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'page':
|
||||
// 项目管理 → 打开独立画布窗口(新 BrowserWindow,非主窗口内叠加层)
|
||||
if (item.key === 'project-management') {
|
||||
console.log('[NavBar] 🖼️ 点击"项目管理" → 发送 OPEN_CANVAS_WINDOW IPC');
|
||||
safeIpcSend(RENDERER_TO_MAIN.OPEN_CANVAS_WINDOW);
|
||||
return;
|
||||
}
|
||||
if (item.target) {
|
||||
emit(EVENTS.OPEN_PAGE, {
|
||||
target: item.target,
|
||||
modalType: item.modalType ?? 'floating',
|
||||
label: item.label,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
[isLoggedIn, logout, message, markAsRead],
|
||||
);
|
||||
|
||||
const macPaddingLeft = platform === 'darwin' ? 80 : 12;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="navbar-drag-region flex items-center justify-between select-none"
|
||||
style={{
|
||||
height: NAVBAR_HEIGHT,
|
||||
paddingLeft: macPaddingLeft,
|
||||
paddingRight: 12,
|
||||
background: isDark
|
||||
? 'linear-gradient(180deg, #1E1B4B 0%, #1A1730 100%)'
|
||||
: 'linear-gradient(180deg, #FFFFFF 0%, #F5F3FF 100%)',
|
||||
borderBottom: `1px solid ${isDark ? '#2E2A4A' : '#E5E7EB'}`,
|
||||
boxShadow: isDark ? '0 1px 4px rgba(0,0,0,0.3)' : '0 1px 4px rgba(99,102,241,0.06)',
|
||||
}}
|
||||
>
|
||||
<div className="navbar-no-drag flex items-center gap-0.5">
|
||||
{visibleLeft.map((item) => (
|
||||
<NavItem
|
||||
key={item.key}
|
||||
item={item}
|
||||
onClick={handleNavClick}
|
||||
badgeCount={item.key === 'announcements' ? unreadCount : undefined}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="navbar-no-drag flex items-center gap-0.5">
|
||||
{visibleRight.map((item) => (
|
||||
<NavItem
|
||||
key={item.key}
|
||||
item={item}
|
||||
onClick={handleNavClick}
|
||||
badgeCount={item.key === 'announcements' ? unreadCount : undefined}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AnnouncementDrawer
|
||||
open={drawerOpen}
|
||||
onClose={() => setDrawerOpen(false)}
|
||||
announcements={announcements}
|
||||
loading={announcementsLoading}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user