feat(cost-center): 记住载体/Tab 选择,补配置引导并优化表格列宽
- 新增 usePersistedState:载体工作区与 Tab 存 localStorage(admin-cost-center:carrier / :tab), 刷新后保持;存储值非法或 Tab 不适用于该载体时自动回退 - 成本项目增加配置说明与常用成本项模板(采购成本/打手报酬/人工成本/平台费/通道费/售后损失), 成本项行新增「加版本」并按成本类型预选范围;成本项/版本弹窗补字段说明 - 商品与成本中心 8 张表统一 tableLayout=fixed,名称类列定宽 + 省略 + tooltip, 表格最小宽度按列宽之和设置,避免名称列独占剩余宽度
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
/**
|
||||
* 把 UI 状态(tab、筛选等)持久化到 localStorage,刷新后保持。
|
||||
*
|
||||
* - 读取失败 / 值不合法时回退到 initial
|
||||
* - setter 支持值或函数式更新
|
||||
* - 写入失败(隐私模式、配额满)时静默忽略,不影响页面
|
||||
*/
|
||||
export function usePersistedState<T>(
|
||||
key: string,
|
||||
initial: T,
|
||||
isValid?: (value: unknown) => value is T,
|
||||
) {
|
||||
const [value, setValue] = useState<T>(() => {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(key)
|
||||
if (raw === null) return initial
|
||||
const parsed: unknown = JSON.parse(raw)
|
||||
if (isValid && !isValid(parsed)) return initial
|
||||
return parsed as T
|
||||
} catch {
|
||||
return initial
|
||||
}
|
||||
})
|
||||
|
||||
const setPersistedValue = useCallback(
|
||||
(next: T | ((prev: T) => T)) => {
|
||||
setValue((prev) => {
|
||||
const resolved = typeof next === 'function' ? (next as (previous: T) => T)(prev) : next
|
||||
try {
|
||||
window.localStorage.setItem(key, JSON.stringify(resolved))
|
||||
} catch {
|
||||
// 本地存储不可用时只保留内存状态。
|
||||
}
|
||||
return resolved
|
||||
})
|
||||
},
|
||||
[key],
|
||||
)
|
||||
|
||||
return [value, setPersistedValue] as const
|
||||
}
|
||||
Reference in New Issue
Block a user