feat(cost-center): 记住载体/Tab 选择,补配置引导并优化表格列宽

- 新增 usePersistedState:载体工作区与 Tab 存 localStorage(admin-cost-center:carrier / :tab),
  刷新后保持;存储值非法或 Tab 不适用于该载体时自动回退
- 成本项目增加配置说明与常用成本项模板(采购成本/打手报酬/人工成本/平台费/通道费/售后损失),
  成本项行新增「加版本」并按成本类型预选范围;成本项/版本弹窗补字段说明
- 商品与成本中心 8 张表统一 tableLayout=fixed,名称类列定宽 + 省略 + tooltip,
  表格最小宽度按列宽之和设置,避免名称列独占剩余宽度
This commit is contained in:
yml2213
2026-10-22 14:36:56 +08:00
parent b520a078b0
commit 0f7d9d4fad
2 changed files with 307 additions and 43 deletions
@@ -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
}