feat: 系统优化Phase2 - 面包屑导航/侧边栏间距/制度公示阅读签收/模板变量中文化/通知类型补全

- 面包屑导航组件,集成至TopNav header
- 侧边栏菜单分组间距增大,分组间分隔线
- 制度公示员工阅读签收:PolicyReadRecord模型、portal路由、管理端阅读统计
- 修复Policies.tsx民主程序推进bug(字段名/API路径/参数)
- 用工文本模板变量名英文转中文显示
- 通知类型TYPE_LABELS补全(RISK_ALERT/SOCIAL_INS/OVERTIME_ALERT/PAYSLIP_READY)
- 通知示例数据补充
- h2标题统一为text-sm font-medium
- 新增run.md
This commit is contained in:
selfrelease
2026-07-26 20:32:38 +08:00
parent 9cb0d1f63b
commit d79e3baa34
71 changed files with 18561 additions and 3230 deletions
+20 -44
View File
@@ -1,22 +1,12 @@
import { Link, useLocation, useNavigate } from 'react-router-dom'
import { Building2, ChevronDown, Settings as SettingsIcon, Bell } from 'lucide-react'
import { Link, useNavigate } from 'react-router-dom'
import { ChevronDown, Settings as SettingsIcon, Bell, Menu } from 'lucide-react'
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import { useAuthStore } from '../../store/authStore'
import api from '../../lib/api'
import clsx from 'clsx'
import Breadcrumb from './Breadcrumb'
const tabs = [
{ path: '/', label: '总览' },
{ path: '/roster', label: '员工管理' },
{ path: '/money', label: '薪税' },
{ path: '/social', label: '社保公积金' },
{ path: '/termination', label: '解聘补偿' },
{ path: '/ai-assistant', label: 'AI顾问' },
]
export default function TopNav() {
const location = useLocation()
export default function TopNav({ onMenuClick }: { onMenuClick?: () => void }) {
const navigate = useNavigate()
const { user, logout } = useAuthStore()
const [menuOpen, setMenuOpen] = useState(false)
@@ -32,47 +22,33 @@ export default function TopNav() {
const riskCount = dashboardData?.riskSummary?.pending || 0
return (
<header className="sticky top-0 z-50 bg-white border-b border-gray-200">
<div className="max-w-content mx-auto px-4 h-14 flex items-center gap-4">
<Link to="/" className="flex items-center gap-2 font-bold text-gray-900 shrink-0">
<Building2 className="w-5 h-5 text-primary" />
<span className="hidden sm:inline"></span>
</Link>
<nav className="hidden md:flex items-center gap-1 flex-1">
{tabs.map((tab) => (
<Link
key={tab.path}
to={tab.path}
className={clsx(
'px-3 py-1.5 rounded-md text-sm font-medium transition-colors relative',
location.pathname === tab.path
? 'bg-primary/10 text-primary'
: 'text-gray-600 hover:bg-gray-100',
)}
>
{tab.label}
{tab.path === '/' && riskCount > 0 && (
<span className="absolute -top-1 -right-1 min-w-4 h-4 px-1 bg-danger text-white text-xs rounded-full flex items-center justify-center">
{riskCount > 99 ? '99+' : riskCount}
</span>
)}
</Link>
))}
</nav>
<header className="sticky top-0 z-30 bg-white border-b border-gray-200">
<div className="h-14 flex items-center justify-between px-4">
{/* 左侧:hamburger(移动端)+ 面包屑 */}
<div className="flex items-center gap-2 min-w-0">
<button
onClick={onMenuClick}
className="md:hidden p-1.5 rounded-md hover:bg-gray-100"
aria-label="打开菜单"
>
<Menu className="w-5 h-5 text-gray-600" />
</button>
<Breadcrumb />
</div>
{/* 右侧:通知 + 设置 + 用户菜单 */}
<div className="flex items-center gap-2 shrink-0">
<Link to="/settings" className="p-1.5 rounded-md hover:bg-gray-100" aria-label="设置">
<SettingsIcon className="w-4 h-4 text-gray-600" />
</Link>
<button className="relative p-1.5 rounded-md hover:bg-gray-100" aria-label="通知">
<Link to="/notifications" className="relative p-1.5 rounded-md hover:bg-gray-100" aria-label="通知">
<Bell className="w-4 h-4 text-gray-600" />
{riskCount > 0 && (
<span className="absolute -top-0.5 -right-0.5 min-w-4 h-4 px-1 bg-danger text-white text-xs rounded-full flex items-center justify-center">
{riskCount > 99 ? '99+' : riskCount}
</span>
)}
</button>
</Link>
<div className="relative">
<button
onClick={() => setMenuOpen(!menuOpen)}