重构: 清理技术债 + 数据健壮性增强(P0+P1)

- 删除 inline.ts(方案A遗留死代码,已被 richtext.ts 替代)
- 删除 ElementStyle.rich 字段(segments 方案后无用)
- 删除 PropsPanel 未使用的 CHART_TYPE_MAP
- 删除 editor.css 旧 class 兼容样式(.el-card-title 等)
- 生成整套/重置时自动备份当前 deck 到 .bak(防误覆盖)
- 新增 recoverBackup() 方法(可恢复上一次被覆盖的 deck)
- 旧版本数据不再直接丢弃,改为 migrateDeck() 补字段升级
- chart 元素自动补 chartType:'bar' 默认值
This commit is contained in:
2026-07-12 13:28:04 +08:00
parent e45df2f269
commit 9933a1711a
5 changed files with 49 additions and 67 deletions

View File

@@ -189,17 +189,41 @@ function touchHistory(key: string) {
touchTimer = setTimeout(() => { touchKey = null }, 900)
}
/* ---------- 数据版本迁移(旧版数据补字段升级,不丢弃) ---------- */
function migrateDeck(d: any): Deck {
// v2→v3: 给元素补默认 chartType / 新元素类型无需处理
if (!d.v || d.v < 3) {
// 确保每个元素有 style 对象
(d.slides || []).forEach((s: any) => {
(s.elements || []).forEach((e: any) => {
if (!e.style) e.style = {};
if (e.type === 'chart' && !e.style.chartType) e.style.chartType = 'bar';
});
});
}
d.v = DECK_VERSION;
return d as Deck;
}
/* ---------- 初始化 ---------- */
function init() {
let loaded: Deck | null = null
try { loaded = JSON.parse(localStorage.getItem(LS_KEY) || 'null') } catch (e) { /* ignore */ }
const curV = SAMPLE_DECK.v
const valid = loaded && loaded.slides && loaded.slides.length && loaded.v === curV
if (!valid && loaded && loaded.slides) {
try { localStorage.setItem(LS_KEY + '.bak', JSON.stringify(loaded)) } catch (e) {} // 旧版备份
let deck: Deck
if (loaded && loaded.slides && loaded.slides.length) {
if (loaded.v !== curV) {
// 版本不匹配 → 尝试迁移
try { localStorage.setItem(LS_KEY + '.bak', JSON.stringify(loaded)) } catch (e) {}
deck = migrateDeck(loaded)
} else {
deck = loaded
}
} else {
deck = clone(SAMPLE_DECK)
}
Object.assign(state, {
deck: valid ? loaded! : clone(SAMPLE_DECK),
deck,
currentIndex: 0,
selectedId: null,
activeLibId: null
@@ -377,6 +401,10 @@ function redo(): boolean {
/* ---------- 整体替换AI 生成 / 导入 / 重置用) ---------- */
function replaceDeck(newDeck: Deck | Record<string, unknown>, opts?: { keepHistory?: boolean; newChat?: boolean }) {
if (!opts?.keepHistory) pushHistory()
// 自动备份newChat=true 时说明是生成整套/重置等“覆盖性操作”,把当前 deck 存入 .bak
if (opts?.newChat && state.deck?.slides?.length) {
try { localStorage.setItem(LS_KEY + '.bak', JSON.stringify(state.deck)) } catch (e) {}
}
suppressHistory = true
let d = newDeck as Deck
if (!d || typeof d !== 'object') d = {} as Deck
@@ -663,6 +691,19 @@ function clearChat(chatId: string) {
try { localStorage.removeItem(CHAT_PREFIX + chatId) } catch (e) {}
}
/** 恢复上一次被覆盖的 deck生成整套/重置前的自动备份) */
function recoverBackup(): boolean {
try {
const bak = localStorage.getItem(LS_KEY + '.bak')
if (!bak) return false
const d = JSON.parse(bak)
if (!d || !d.slides || !d.slides.length) return false
replaceDeck(d)
localStorage.removeItem(LS_KEY + '.bak')
return true
} catch (e) { return false }
}
/* ---------- 导出 ---------- */
export const store = {
// 状态(响应式)
@@ -699,4 +740,6 @@ export const store = {
getTemplates, getUserTemplates, saveCurrentAsTemplate, addSlideFromTemplate, deleteTemplate,
// 会话管理
getChatId, getChat, setChat, clearChat, newChatId,
// 备份恢复
recoverBackup,
}