Files
DevFlow/src/composables/useStoreAction.ts
T
lxy 3d8b755229 重构: 前端DRY收口+后端测试类型对齐
- 新增 useToast composable: 消除 AiChat/Settings/Projects 4处 toast 重复
  统一默认3000ms(Projects原4000ms为操作类提示保留参数覆盖)
- 新增 utils/json.ts parseJsonArray: 消除 parseStack/parseTags/ModuleNode
  3处JSON字符串数组解析重复
- 新增 utils/html.ts escapeHtml: 消除 useMarkdown/FilePreview 2处重复
- ProjectDetail score-bar 内联三元改用 scoreTier(消除最后一处阈值硬编码)
- ConversationSidebar 删除 formatTime 透传包装(直接用 formatRelative)
- 清理死代码: parseTs/stringifyError/ErrorSink/_Unused 改私有或删除
  wrapNakedDiff 改私有(无外部 import)
- ModuleNode shortPath 改名 truncatedPath(与 useToolCard.shortPath 语义不同)
2026-07-03 00:18:21 +08:00

81 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Store action 统一错误处理工具(任务 #7 DRY 抽离)。
*
* 之前 4 个 storeknowledge/ideas/projects/tasks)共 38 处重复:
* try { ... } catch (e: any) { state.error = e?.toString() ?? t('xxx') }
*
* 本工具:
* - 用 `catch (e: unknown)` 替代 `any`(类型安全)
* - 失败时写 state.error,返回 undefined(调用方判断)
* - 成功时返回 fn 结果
*
* 注:带 seq 竞态守卫的场景调用方需在 fn 内部判断,不在本工具职责范围。
*/
// (Ref import 已移除,_Unused 类型已删除)
/** 带 error 字段的 store state 形状(仅约束 error,其他字段任意)。仅本模块内部使用。 */
interface ErrorSink {
error: string | null
}
/**
* 执行异步 action,失败时写 state.error + 返回 undefined。
*
* @param state 带 error 字段的响应式 state
* @param i18nKey 失败时的 i18n 文案 key(兜底)
* @param fn 异步 action
* @returns 成功返 fn 结果;失败返 undefined
*/
export async function runWithCatch<T>(
state: ErrorSink,
i18nKey: string,
fn: () => Promise<T>,
): Promise<T | undefined> {
try {
return await fn()
} catch (e: unknown) {
state.error = stringifyError(e) ?? i18nKey
return undefined
}
}
// stringifyError 仅本模块内部使用(runWithCatch/runWithCatchGuarded 调用),不导出。
function stringifyError(e: unknown): string | undefined {
if (typeof e === 'string') return e
if (e instanceof Error) return e.message || e.toString()
if (e && typeof e === 'object' && 'toString' in e) {
try {
return String((e as { toString(): string }).toString())
} catch {
return undefined
}
}
return undefined
}
/**
* Variant:带前置守卫的错误捕获。
*
* 用于「旧请求的失败不污染当前视图」场景(如 seq 守卫)。
*
* @param guard 返回 true 时才写 state.errorfalse 时静默(旧响应丢弃)
*/
export async function runWithCatchGuarded<T>(
state: ErrorSink,
i18nKey: string,
guard: () => boolean,
fn: () => Promise<T>,
): Promise<T | undefined> {
try {
return await fn()
} catch (e: unknown) {
if (guard()) {
state.error = stringifyError(e) ?? i18nKey
}
return undefined
}
}
// _Unused 类型从未被外部 import,已删除(同时移除上方 Ref import)。