task-122(记录与版本中心): 实现历史记录筛选条件

新增 records/history-filter.ts:筛选草稿/已应用快照与变更回首页。

TDD: task-122.test.ts 8 用例 RED→GREEN。
This commit is contained in:
2026-09-05 17:30:35 +08:00
parent 467c72efb4
commit 103cb28a1f
2 changed files with 120 additions and 0 deletions
@@ -0,0 +1,57 @@
/** 历史记录筛选栏状态(任务 122):筛选草稿/已应用快照与“变更回首页”,纯逻辑。 */
export interface HistoryFilterDraft {
userId: number | null
timeStart: string
timeEnd: string
}
export interface HistoryFilterBarState {
applied: HistoryFilterDraft | null
returnFirstPage: boolean
}
export function createHistoryFilterBarState(): HistoryFilterBarState {
return { applied: null, returnFirstPage: false }
}
function positiveIdOrNull(value: unknown): number | null {
if (typeof value === 'number') return Number.isFinite(value) && value >= 1 ? Math.floor(value) : null
if (typeof value === 'string' && /^\d+$/.test(value.trim())) {
const parsed = Number(value.trim())
return parsed >= 1 ? Math.floor(parsed) : null
}
return null
}
function textOf(value: unknown): string {
return typeof value === 'string' ? value.trim() : ''
}
/** 由界面输入(userId/起止时间)生成筛选草稿。 */
export function historyDraftFromInput(input: { userId?: string | number | null; timeStart?: string; timeEnd?: string }): HistoryFilterDraft {
return {
userId: positiveIdOrNull(input.userId),
timeStart: textOf(input.timeStart),
timeEnd: textOf(input.timeEnd),
}
}
function clone(draft: HistoryFilterDraft): HistoryFilterDraft {
return { userId: draft.userId, timeStart: textOf(draft.timeStart), timeEnd: textOf(draft.timeEnd) }
}
export function commitHistoryFilter(_state: HistoryFilterBarState, draft: HistoryFilterDraft): HistoryFilterBarState {
return { applied: clone(draft), returnFirstPage: true }
}
export function clearHistoryFilter(_state: HistoryFilterBarState): HistoryFilterBarState {
return { applied: null, returnFirstPage: true }
}
/** 草稿是否与已应用一致(无差异则无需重新加载)。 */
export function isHistoryFilterApplied(draft: HistoryFilterDraft, applied: HistoryFilterDraft | null): boolean {
if (!applied) return false
const a = clone(draft)
return a.userId === applied.userId && a.timeStart === applied.timeStart && a.timeEnd === applied.timeEnd
}