Files
Nekosonic-Music/src/stores/migrations/settingsMigrations.ts
T
atdunbg 263e9b31d9 feat: v0.8.0 详情页架构重构、皮肤系统、侧边栏交互升级、底层模块拆分
- 详情页统一 DetailLayout 组件(常驻头部 + 独立滚动 + 紧凑态动画)
- 歌曲/评论 tab 切换(懒加载 + 保活),专辑模糊搜索
- 皮肤系统 skins.ts(19 语义色 + 14 预设 + 自定义皮肤 + 壁纸)
- 设置页皮肤模块(外观/主题色/皮肤编辑器/壁纸选择)
- 可折叠侧边栏 + TopBar + 折叠态歌单浮层(高度不越 PlayerBar)
- 首页扩展至 6 区块 + 通用卡片组件 + 虚拟歌曲列表
- audio.rs 拆为 8 模块,api.ts 拆为 api/ 目录,player store 拆为 4 store
- 修复播放竞态、seek 暂停、评论提前加载、紧凑态卡死等
2026-06-26 21:05:51 +08:00

107 lines
3.5 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.
/**
* 设置数据 Schema 迁移
*
* 每次新增字段或修改结构时,新增一个迁移函数并递增 CURRENT_SCHEMA_VERSION。
* 迁移按版本号顺序执行:v0 → v1 → v2 → ... → CURRENT。
*
* 迁移函数签名:(data: any) => any
* - 输入:旧版数据(可能是任意历史版本)
* - 输出:升级后的数据
* - 必须幂等:对已经是目标版本的数据执行应无副作用
*/
/** 当前 Schema 版本号 */
export const CURRENT_SCHEMA_VERSION = 3;
/** 迁移函数按目标版本号索引(data 升级到此版本后即为 vN) */
const migrations: Record<number, (data: any) => any> = {
/**
* v1: theme + appearance → skin
*
* 旧版用独立的 themeblue/green/...)和 appearancedark/light)字段,
* 合并为统一的 skin 字段(如 "dark-blue")。
*/
1: (data) => {
if (!data.skin && (data.theme || data.appearance)) {
const appearance = data.appearance || 'dark';
const theme = data.theme || 'blue';
const validThemes = ['blue', 'green', 'rose', 'violet', 'orange', 'cyan', 'pink'];
const t = validThemes.includes(theme) ? theme : 'blue';
data.skin = appearance === 'light' ? `light-${t}` : `dark-${t}`;
}
if (!data.skin) data.skin = 'dark-blue';
delete data.theme;
delete data.appearance;
return data;
},
/**
* v2: 全局 wallpaper → 移入自定义皮肤
*
* 旧版有全局 wallpaper/wallpaperBlur/wallpaperOpacity 字段,
* 迁移到每个自定义皮肤的对应字段(仅填充缺失项)。
*/
2: (data) => {
if (data.wallpaper && Array.isArray(data.customSkins) && data.customSkins.length > 0) {
data.customSkins = data.customSkins.map((s: any) => {
if (!s.wallpaper) {
return {
...s,
wallpaper: data.wallpaper,
wallpaperBlur: s.wallpaperBlur ?? data.wallpaperBlur ?? 10,
wallpaperOpacity: s.wallpaperOpacity ?? data.wallpaperOpacity ?? 0.3,
};
}
return s;
});
}
delete data.wallpaper;
delete data.wallpaperBlur;
delete data.wallpaperOpacity;
return data;
},
/**
* v3: localMusicPaths (string[]) → localMusicFolders ({path, enabled}[])
*
* 旧版本地音乐路径是字符串数组,新版改为带 enabled 开关的对象数组。
*/
3: (data) => {
if (!data.localMusicFolders && Array.isArray(data.localMusicPaths) && data.localMusicPaths.length) {
data.localMusicFolders = data.localMusicPaths.map((p: string) => ({ path: p, enabled: true }));
}
if (!Array.isArray(data.localMusicFolders)) {
data.localMusicFolders = [];
}
// 兼容 localMusicFolders 内仍是字符串的情况
data.localMusicFolders = data.localMusicFolders.map((f: any) =>
typeof f === 'string' ? { path: f, enabled: true } : f
);
delete data.localMusicPaths;
return data;
},
};
/**
* 执行迁移:将旧版数据升级到 CURRENT_SCHEMA_VERSION
*
* @param raw 从 localStorage 读取的原始数据(可能无 schemaVersion
* @returns 迁移后的数据,含 schemaVersion = CURRENT_SCHEMA_VERSION
*/
export function migrateSettings(raw: any): any {
let data = { ...raw };
let version = typeof data.schemaVersion === 'number' ? data.schemaVersion : 0;
while (version < CURRENT_SCHEMA_VERSION) {
const next = version + 1;
const migrator = migrations[next];
if (migrator) {
data = migrator(data);
}
version = next;
}
data.schemaVersion = CURRENT_SCHEMA_VERSION;
return data;
}