refactor(data): 收口关系表运行时数据源
Some checks failed
Deploy Production / Build, push, deploy, verify (push) Has been cancelled

- 移除已迁移业务 AppData 运行时 fallback,改走领域 API 和关系表快读
- 补齐需求产品负责人、版本计划任务 JSON 和成员 username 回填迁移
- 统一治理字典入口,并补充 AI provider、数据源契约和领域服务测试

Co-Authored-By: Codex GPT-5 <codex@openai.com>
This commit is contained in:
2026-07-09 14:59:49 +08:00
parent 1e6fb0c7aa
commit 2e595c7e72
98 changed files with 2938 additions and 1441 deletions

View File

@@ -6,7 +6,6 @@ import {
markXiaobaoWarningRead,
type XiaobaoWarningReadState,
} from '@/lib/xiaobao-warning-view';
import { loadServerData, saveServerData, SERVER_DATA_CACHE_MS } from '@/lib/server-data';
interface XiaobaoWarningReadStoreState {
readStates: XiaobaoWarningReadState[];
@@ -16,15 +15,23 @@ interface XiaobaoWarningReadStoreState {
markRiskRead: (userId: string, risk: XiaobaoVersionRisk, readAt?: string) => Promise<void>;
}
let readStateSaveQueue: Promise<void> = Promise.resolve();
const READ_STATE_CACHE_MS = 30_000;
const READ_STATE_STORAGE_KEY = 'ftb_xiaobao_warning_views';
let lastReadStatesFetchAt = 0;
async function loadReadStates(): Promise<XiaobaoWarningReadState[] | null> {
function loadReadStates(): XiaobaoWarningReadState[] {
try {
const rows = await loadServerData<XiaobaoWarningReadState[]>('xiaobao-warning-views');
return normalizeReadStates(rows);
if (typeof window === 'undefined') return [];
return normalizeReadStates(JSON.parse(window.localStorage.getItem(READ_STATE_STORAGE_KEY) || '[]'));
} catch {}
return [];
}
function saveReadStates(rows: XiaobaoWarningReadState[]) {
try {
if (typeof window === 'undefined') return;
window.localStorage.setItem(READ_STATE_STORAGE_KEY, JSON.stringify(rows));
} catch {}
return null;
}
function normalizeReadStates(rows: unknown): XiaobaoWarningReadState[] {
@@ -64,14 +71,14 @@ export const useXiaobaoWarningReadStore = create<XiaobaoWarningReadStoreState>((
error: undefined,
fetchReadStates: async () => {
if (get().readStateLoaded && Date.now() - lastReadStatesFetchAt < SERVER_DATA_CACHE_MS) return;
const rows = await loadReadStates();
if (get().readStateLoaded && Date.now() - lastReadStatesFetchAt < SERVER_DATA_CACHE_MS) return;
if (get().readStateLoaded && Date.now() - lastReadStatesFetchAt < READ_STATE_CACHE_MS) return;
const rows = loadReadStates();
if (get().readStateLoaded && Date.now() - lastReadStatesFetchAt < READ_STATE_CACHE_MS) return;
lastReadStatesFetchAt = Date.now();
set({
readStates: rows ? mergeReadStates(rows, get().readStates) : get().readStates,
readStateLoaded: rows !== null,
error: rows === null ? '小宝预警查看状态加载失败' : undefined,
readStates: mergeReadStates(rows, get().readStates),
readStateLoaded: true,
error: undefined,
});
},
@@ -79,20 +86,6 @@ export const useXiaobaoWarningReadStore = create<XiaobaoWarningReadStoreState>((
if (!userId) return;
const optimistic = markXiaobaoWarningRead(get().readStates, userId, risk, readAt);
set({ readStates: optimistic, error: undefined });
const task = readStateSaveQueue.then(async () => {
const remote = await loadServerData<XiaobaoWarningReadState[]>('xiaobao-warning-views', { force: true });
const merged = mergeReadStates(normalizeReadStates(remote), get().readStates);
set({ readStates: merged, readStateLoaded: true, error: undefined });
await saveServerData('xiaobao-warning-views', merged);
});
readStateSaveQueue = task.catch(() => undefined);
try {
await task;
} catch (error) {
set({ error: '小宝预警查看状态保存失败' });
throw error;
}
saveReadStates(optimistic);
},
}));