Files
ele-HeiXiu/src/modules/canvas/hooks/useSidecarSync.ts
YoungestSongMo 337d6c1205 feat: 构建系统重构 + VCHSM 架构迁移 + 右键菜单修复 + 尺寸参数统一
## 构建、打包与分发系统重构 (build/)

- 构建系统收敛至 build/ 目录:build.mjs + electron-builder.js + 6 个脚本

- electron-builder 配置从 package.json 提取为 build/electron-builder.js

- 新增 --edition (personal/enterprise) 和 --channel (stable/beta/alpha) 参数

- OSS 路径按渠道隔离

- 新增 pre-build-check.mjs:Git/CHANGELOG/版本/环境变量校验

- 新增 bump-version.mjs:版本号管理 + CHANGELOG 自动生成

- updater.ts 发送 channel/edition/deviceFingerprint

- 新增 src/shared/utils/rollout.ts 灰度测试工具

- 新增 10 条 NPM 脚本

## VCHSM 五层架构迁移

- 7 个业务模块 + ~500 处导入路径同步

## 修复

- MediaCardContextMenu 改用共享 ContextMenu 组件

- ComboBox 尺寸参数显示统一 (size-format.ts)

## 文档

- UpdateA.md / build/README.md / README.md / .env.example 更新

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-29 18:41:07 +08:00

60 lines
2.4 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.
// ============================================================
// useSidecarSync — Sidecar 元数据防抖同步 Hook
//
// QuickEditPanel 编辑 → 250ms 防抖 → dataSource.writeSidecar() → 保存到 JSON。
// Phase 4 扩展:写入后通过事件总线通知宿主窗口刷新。
// ============================================================
import { useRef, useCallback } from 'react';
import { useCanvasStore, getCanvasStore } from '../stores/useCanvasStore';
import type { SidecarMetadata } from '../utils/ICanvasDataSource';
export function useSidecarSync() {
const updateItemMetadata = useCanvasStore((s) => s.updateItemMetadata);
const getDataSource = useCanvasStore((s) => s.getDataSource);
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const pendingRef = useRef<Map<number, SidecarMetadata>>(new Map());
/**
* 提交元数据更新250ms 防抖)。
* 更新 Store → 延迟写入 sidecar JSON失败时保留 Store 中的副本)。
*/
const commitMetadata = useCallback(
(itemId: number, filePath: string, partial: Partial<SidecarMetadata>) => {
const current =
pendingRef.current.get(itemId) ||
({} as SidecarMetadata);
const merged = { ...current, ...partial };
pendingRef.current.set(itemId, merged);
// 立即更新 Store乐观更新
updateItemMetadata(itemId, partial);
// 防抖写入 sidecar
if (timerRef.current) clearTimeout(timerRef.current);
timerRef.current = setTimeout(async () => {
const batch = new Map(pendingRef.current);
pendingRef.current.clear();
const dataSource = getDataSource();
const store = getCanvasStore();
for (const [id, meta] of batch) {
try {
const item = store.getState().items.find(
(i) => i.id === id,
);
if (item) {
await dataSource.writeSidecar(item.path, meta);
}
} catch {
console.warn(`[useSidecarSync] 写入 sidecar 失败: ${filePath}`);
}
}
}, 250);
},
[updateItemMetadata, getDataSource],
);
return { commitMetadata };
}