refactor: 重构ViewedRowPersistOptions处理扁平化问题

改成按 type 字段区分的联合类型
This commit is contained in:
layhuts
2026-05-09 11:02:16 +08:00
parent 8ce773f264
commit 88d5661e0c
2 changed files with 43 additions and 54 deletions

View File

@@ -55,34 +55,50 @@ export interface ViewedRowStorageAdapter {
} }
/** /**
* 已读行持久化配置 * 已读行持久化 — 公共基础字段
*/ */
export interface ViewedRowPersistOptions { interface ViewedRowPersistBase {
/**
* 存储类型,默认 'localStorage'
* - memory: 仅内存,不持久化
* - localStorage: 使用 localStorage 整体存储
* - sessionStorage: 使用 sessionStorage 整体存储
* - indexedDB: 使用 IndexedDB 单条存储(支持单条 TTL)
* - custom: 用户自定义存储适配器
*/
type?: 'custom' | 'indexedDB' | 'localStorage' | 'memory' | 'sessionStorage';
/** 存储 key / prefix(type 为 localStorage/sessionStorage/indexedDB 时必传) */
key?: string;
/** 持久化数据的存活时间(毫秒) */ /** 持久化数据的存活时间(毫秒) */
ttl?: number; ttl?: number;
/** 最大缓存数量,超出时淘汰最早标记的 key(FIFO),默认 100 */ /** 最大缓存数量,超出时淘汰最早标记的 key(FIFO),默认 100 */
maxSize?: number; maxSize?: number;
/** IndexedDB 数据库名称(仅 type='indexedDB' 时生效,默认 'viewed-table-db') */
dbName?: string;
/** IndexedDB 数据库版本(仅 type='indexedDB' 时生效,默认 1) */
dbVersion?: number;
/** IndexedDB 对象存储名称(仅 type='indexedDB' 时生效,默认 'viewed-table-row') */
storeName?: string;
/** 自定义存储适配器(仅 type='custom' 时生效,不传则降级为 memory) */
storage?: ViewedRowStorageAdapter;
} }
/**
* 已读行持久化配置(按 type 区分的联合类型)
*
* - 'memory' → 仅内存,不持久化
* - 'localStorage' → 使用 localStorage 整体存储,key 必传
* - 'sessionStorage' → 使用 sessionStorage 整体存储,key 必传
* - 'indexedDB' → 使用 IndexedDB 单条存储,key 必传
* - 'custom' → 用户自定义存储适配器,storage 必传
*/
export type ViewedRowPersistOptions =
({
/** IndexedDB 数据库名称,默认 'viewed-table-db' */
dbName?: string;
/** IndexedDB 数据库版本,默认 1 */
dbVersion?: number;
/** 存储 key / prefix(必传) */
key: string;
/** IndexedDB 对象存储名称,默认 'viewed-table-row' */
storeName?: string;
type: 'indexedDB';
} & ViewedRowPersistBase)
| ({
/** 存储 key(必传) */
key: string;
type: 'localStorage' | 'sessionStorage';
} & ViewedRowPersistBase)
| ({
/** 自定义存储适配器(必传) */
storage: ViewedRowStorageAdapter;
type: 'custom';
} & ViewedRowPersistBase)
| (ViewedRowPersistBase & {
type: 'memory';
});
/** /**
* 已查看row设置 * 已查看row设置
*/ */

View File

@@ -54,9 +54,9 @@ function createWebStorageAdapter(
* 单条存储:prefix:1 → { expiry, value: 1 } * 单条存储:prefix:1 → { expiry, value: 1 }
*/ */
function createIndexedDBAdapter( function createIndexedDBAdapter(
opts: ViewedRowPersistOptions, opts: Extract<ViewedRowPersistOptions, { type: 'indexedDB' }>,
): ViewedRowStorageAdapter { ): ViewedRowStorageAdapter {
const prefix = opts.key || 'viewed'; const prefix = opts.key;
const manager = new StorageManager({ const manager = new StorageManager({
driver: new IndexedDBDriver({ driver: new IndexedDBDriver({
dbName: opts.dbName || 'viewed-table-db', dbName: opts.dbName || 'viewed-table-db',
@@ -69,16 +69,11 @@ function createIndexedDBAdapter(
return { return {
async getKeys() { async getKeys() {
try { try {
// 通过 StorageManager 的 driver 获取所有 key,再逐条读取(自动过滤过期) // 通过 StorageManager 获取当前前缀下所有 key,再逐条读取(自动过滤过期)
const allKeys = (await (manager as any).driver.keys()) as string[]; const shortKeys = await manager.keys();
const fullPrefix = prefix ? `${prefix}-` : '';
const prefixedKeys = allKeys.filter((k: string) =>
k.startsWith(fullPrefix),
);
const results: Array<number | string> = []; const results: Array<number | string> = [];
for (const fullKey of prefixedKeys) { for (const shortKey of shortKeys) {
const shortKey = fullKey.replace(fullPrefix, '');
const value = await manager.getItem<number | string>(shortKey); const value = await manager.getItem<number | string>(shortKey);
if (value !== null) { if (value !== null) {
results.push(value); results.push(value);
@@ -124,43 +119,21 @@ function createStorageAdapter(
return createWebStorageAdapter('localStorage', persist); return createWebStorageAdapter('localStorage', persist);
} }
const {type = 'localStorage'} = persist; switch (persist.type) {
switch (type) {
case 'custom': { case 'custom': {
if (!persist.storage) {
// 没有提供 storage 适配器,降级为 memory
return null;
}
// 用户自定义适配器,解除 Vue 响应式代理 // 用户自定义适配器,解除 Vue 响应式代理
return toRaw(persist.storage); return toRaw(persist.storage);
} }
case 'indexedDB': { case 'indexedDB': {
if (!persist.key) {
console.warn('[viewedRow] persist.key is required for indexedDB type');
return null;
}
return createIndexedDBAdapter(persist); return createIndexedDBAdapter(persist);
} }
case 'localStorage': { case 'localStorage': {
if (!persist.key) {
console.warn(
'[viewedRow] persist.key is required for localStorage type',
);
return null;
}
return createWebStorageAdapter('localStorage', persist.key, persist.ttl); return createWebStorageAdapter('localStorage', persist.key, persist.ttl);
} }
case 'memory': { case 'memory': {
return null; return null;
} }
case 'sessionStorage': { case 'sessionStorage': {
if (!persist.key) {
console.warn(
'[viewedRow] persist.key is required for sessionStorage type',
);
return null;
}
return createWebStorageAdapter( return createWebStorageAdapter(
'sessionStorage', 'sessionStorage',
persist.key, persist.key,