Sprint 4-5: 员工自助+考勤+合规+AI+搜索

This commit is contained in:
selfrelease
2026-08-01 06:45:59 +08:00
parent 9946197d20
commit a88c96299c
16 changed files with 1919 additions and 35 deletions
+88
View File
@@ -0,0 +1,88 @@
/**
* useSavedViews — 保存/加载筛选视图到 localStorage
* 支持多页面、多视图持久化
*/
import { useState, useCallback, useEffect } from 'react'
interface SavedView {
id: string
name: string
filters: Record<string, any>
createdAt: string
}
/**
* 保存视图 Hook — 将筛选条件持久化到 localStorage
* @param pageKey 页面唯一标识(如 'roster', 'money'
*/
export function useSavedViews(pageKey: string) {
const storageKey = `saved-views:${pageKey}`
const [views, setViews] = useState<SavedView[]>([])
const [activeViewId, setActiveViewId] = useState<string | null>(null)
/** 初始化加载 */
useEffect(() => {
try {
const stored = localStorage.getItem(storageKey)
if (stored) {
setViews(JSON.parse(stored))
}
} catch {
// 忽略解析错误
}
}, [storageKey])
/** 持久化保存 */
const persist = useCallback((newViews: SavedView[]) => {
setViews(newViews)
try {
localStorage.setItem(storageKey, JSON.stringify(newViews))
} catch {
// 存储满或不可用
}
}, [storageKey])
/** 保存当前筛选为视图 */
const saveView = useCallback((name: string, filters: Record<string, any>) => {
const id = `${Date.now()}`
const newView: SavedView = {
id,
name,
filters,
createdAt: new Date().toISOString(),
}
persist([...views, newView])
setActiveViewId(id)
return newView
}, [views, persist])
/** 删除视图 */
const deleteView = useCallback((id: string) => {
persist(views.filter(v => v.id !== id))
if (activeViewId === id) setActiveViewId(null)
}, [views, persist, activeViewId])
/** 应用视图 */
const applyView = useCallback((id: string) => {
const view = views.find(v => v.id === id)
if (view) {
setActiveViewId(id)
return view.filters
}
return null
}, [views])
/** 重命名视图 */
const renameView = useCallback((id: string, name: string) => {
persist(views.map(v => v.id === id ? { ...v, name } : v))
}, [views, persist])
return {
views,
activeViewId,
saveView,
deleteView,
applyView,
renameView,
}
}