重构: 清理技术债 + 数据健壮性增强(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:
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user