feat: 三栏比例缩放 + SeedanceContent视频上传 + 本地存储基建 (0.0.22)
三栏布局 - ResizeObserver 等比例分配替代固定默认值恢复 - 修复拖拽+窗口调整竞态卡死(needsRecalcRef 延迟补算) - containerRef.current 动态读取 DOM 替代闭包 el Seedance2Content - 从占位文本重构为内容编排控件(文本+图片/视频/音频上传) - 根据 spec.image_files/video_files/audio_files 动态渲染上传区域 - 值 JSON 序列化 → 提交时转 ContentItem[](text/image_url/video_url/audio_url) 图片上传兼容视频文件 - buildAccept 根据 file_filter 区分 image/video 前缀 - createMediaBeforeUpload 动态放行 video/* MIME - 公共模块 media-upload-utils.ts 本地存储基建 - sql.js (WASM SQLite) + safeStorage 加密持久化 - 8个IPC文件操作通道 + resolveSafe 路径穿越防护 - <userData>/heixiu-data/ 沙箱 + JWT用户隔离 - 7表DDL + 游标分页 + LRU媒体淘汰 其他 - 修复 errorMessageRef 渲染期写入警告 - 媒体预览回退直接URL(<img>无CORS限制)+ output_type类型补充 - CSP wasm-unsafe-eval + https: CDN媒体源
This commit is contained in:
80
src/infrastructure/storage/param-store.ts
Normal file
80
src/infrastructure/storage/param-store.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
// ============================================================
|
||||
// infrastructure/storage/param-store.ts — 参数历史本地存储
|
||||
//
|
||||
// 职责:
|
||||
// - 任务提交后保存输入参数快照(task_id 主键)
|
||||
// - 任务完成后回填输出数据
|
||||
// - 按模型查询历史参数列表(回填菜单数据源)
|
||||
// ============================================================
|
||||
|
||||
import { execute, queryAll, queryOne } from './db-core';
|
||||
import { getCurrentUserId } from './user-scope';
|
||||
import type { ParamHistoryEntry } from './types';
|
||||
|
||||
const MAX_PER_MODEL = 20;
|
||||
|
||||
// ---------- API ----------
|
||||
|
||||
export function saveParamSnapshot(
|
||||
taskId: string,
|
||||
modelId: string,
|
||||
modelName: string,
|
||||
inputParams: Record<string, unknown>,
|
||||
tag?: string,
|
||||
): void {
|
||||
const uid = getCurrentUserId();
|
||||
execute(
|
||||
`INSERT OR REPLACE INTO param_history (task_id, user_id, model_id, model_name, input_params_json, tag, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||
[taskId, uid, modelId, modelName, JSON.stringify(inputParams), tag || null, Date.now()],
|
||||
);
|
||||
// 裁剪旧记录
|
||||
prune(modelId, uid);
|
||||
}
|
||||
|
||||
export function fillOutputData(taskId: string, outputData: Record<string, unknown>): void {
|
||||
execute(
|
||||
`UPDATE param_history SET output_data_json = ? WHERE task_id = ?`,
|
||||
[JSON.stringify(outputData), taskId],
|
||||
);
|
||||
}
|
||||
|
||||
export function getParamByTaskId(taskId: string): ParamHistoryEntry | null {
|
||||
return queryOne<ParamHistoryEntry>(`SELECT * FROM param_history WHERE task_id = ?`, [taskId]);
|
||||
}
|
||||
|
||||
export function getParamHistory(modelId: string, limit = 10): ParamHistoryEntry[] {
|
||||
const uid = getCurrentUserId();
|
||||
return queryAll<ParamHistoryEntry>(
|
||||
`SELECT * FROM param_history WHERE user_id = ? AND model_id = ? ORDER BY created_at DESC LIMIT ?`,
|
||||
[uid, modelId, limit],
|
||||
);
|
||||
}
|
||||
|
||||
export function parseParams(entry: ParamHistoryEntry): Record<string, unknown> {
|
||||
try { return JSON.parse(entry.input_params_json) as Record<string, unknown>; } catch { return {}; }
|
||||
}
|
||||
|
||||
export function deleteParamHistory(id: number): void {
|
||||
execute(`DELETE FROM param_history WHERE id = ?`, [id]);
|
||||
}
|
||||
|
||||
export function clearUserParams(): void {
|
||||
execute(`DELETE FROM param_history WHERE user_id = ?`, [getCurrentUserId()]);
|
||||
}
|
||||
|
||||
// ---------- 内部 ----------
|
||||
|
||||
function prune(modelId: string, userId: string): void {
|
||||
try {
|
||||
const rows = queryAll<ParamHistoryEntry>(
|
||||
`SELECT id FROM param_history WHERE user_id = ? AND model_id = ? ORDER BY created_at DESC`,
|
||||
[userId, modelId],
|
||||
);
|
||||
if (rows.length <= MAX_PER_MODEL) return;
|
||||
const toDelete = rows.slice(MAX_PER_MODEL);
|
||||
for (const r of toDelete) {
|
||||
if (r.id) execute(`DELETE FROM param_history WHERE id = ?`, [r.id]);
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
Reference in New Issue
Block a user