fix(console): 纯色恢复初始回到原背景色(#0a0d13, hsl -140/31/6);修复上传后缩略图挂图(不再撤销共享对象URL);photoStore 迁移改惰性、升级事务不再删旧store

This commit is contained in:
Aisland
2026-09-01 13:31:02 +08:00
parent a924174632
commit 2f6acb7fc6
4 changed files with 107 additions and 110 deletions
+1 -1
View File
@@ -1394,7 +1394,7 @@ function WorktableSection(props: any) {
return { id, url: URL.createObjectURL(blob) }
},
setPhotoId: (id: string) => persistView({ consoleBgPhotoId: id }),
getPlainHsl: () => viewRef.current.consoleBgPlainHsl ?? { h: 0, s: 31, l: 6 },
getPlainHsl: () => viewRef.current.consoleBgPlainHsl ?? { h: -140, s: 31, l: 6 },
setPlainHsl: (v: { h: number; s: number; l: number }) => persistView({ consoleBgPlainHsl: { ...v } }),
getGlowHsl: () => viewRef.current.consoleBgGlowHsl ?? { h: 0, s: 100, l: 100 },
setGlowHsl: (v: { h: number; s: number; l: number }) => persistView({ consoleBgGlowHsl: { ...v } }),
+48 -36
View File
@@ -1,5 +1,6 @@
/** dsh-worktable 控制室背景照片库:IndexedDB 存原始图片(Blob 记录,零压缩)。
* v2:多张照片记录(id/createdAt/blob),v1 单图自动迁移为一条 'legacy' 记录。 */
* v2:多张照片记录(id/createdAt/blob);v1 单图在首次 list() 时惰性迁移为 'legacy' 记录。
* (不在 onupgradeneeded 里动旧 store —— 升级事务内异步读写易出竞态,迁移放到读路径最稳。) */
const DB_NAME = 'dsh-worktable'
const STORE = 'photoRecords'
const LEGACY_STORE = 'consoleBgPhoto'
@@ -13,53 +14,64 @@ function openDb(): Promise<IDBDatabase> {
req.onupgradeneeded = () => {
const db = req.result
if (!db.objectStoreNames.contains(STORE)) db.createObjectStore(STORE)
// v1→v2 迁移:旧单图(consoleBgPhoto/original)转为一条 'legacy' 记录
if (db.objectStoreNames.contains(LEGACY_STORE)) {
try {
const tx = req.transaction as IDBTransaction
const getReq = tx.objectStore(LEGACY_STORE).get(LEGACY_KEY)
getReq.onsuccess = () => {
try {
const blob = getReq.result
if (blob instanceof Blob) {
const rec: PhotoRecord = { id: 'legacy', createdAt: Date.now(), blob }
tx.objectStore(STORE).put(rec, rec.id)
}
tx.objectStore(LEGACY_STORE).delete(LEGACY_KEY)
} catch {}
}
} catch {}
try { db.deleteObjectStore(LEGACY_STORE) } catch {}
}
}
req.onsuccess = () => resolve(req.result)
req.onerror = () => reject(req.error)
})
}
function getAll(db: IDBDatabase): Promise<PhotoRecord[]> {
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE, 'readonly')
const req = tx.objectStore(STORE).getAll()
req.onsuccess = () => {
const arr: PhotoRecord[] = []
for (const v of req.result as unknown[]) {
const r = v as PhotoRecord | null
if (r && typeof r === 'object' && typeof (r as any).id === 'string' && (r as any).blob instanceof Blob) {
arr.push(r)
}
}
arr.sort((a, b) => b.createdAt - a.createdAt)
db.close()
resolve(arr)
}
req.onerror = () => { db.close(); reject(req.error) }
})
}
export const photoStore = {
/** 全部照片记录(最新在前) */
/** 全部照片记录(最新在前);无记录时惰性迁移 v1 单图 */
async list(): Promise<PhotoRecord[]> {
const db = await openDb()
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE, 'readonly')
const req = tx.objectStore(STORE).getAll()
req.onsuccess = () => {
const arr: PhotoRecord[] = []
for (const v of req.result as unknown[]) {
const r = v as PhotoRecord | null
if (r && typeof r === 'object' && typeof (r as any).id === 'string' && (r as any).blob instanceof Blob) {
arr.push(r)
}
const main = await getAll(db)
if (main.length > 0) return main
// 迁移旧单图(若有):读取 → 转为 'legacy' 记录
try {
if (db.objectStoreNames.contains(LEGACY_STORE)) {
const blob = await new Promise<Blob | null>((resolve, reject) => {
const tx = db.transaction(LEGACY_STORE, 'readonly')
const req = tx.objectStore(LEGACY_STORE).get(LEGACY_KEY)
req.onsuccess = () => resolve(req.result instanceof Blob ? req.result : null)
req.onerror = () => reject(req.error)
})
if (blob) {
const rec: PhotoRecord = { id: 'legacy', createdAt: Date.now(), blob }
await new Promise<void>((resolve, reject) => {
const tx = db.transaction(STORE, 'readwrite')
tx.objectStore(STORE).put(rec, rec.id)
tx.oncomplete = () => resolve()
tx.onerror = () => reject(tx.error)
})
db.close()
return [rec]
}
arr.sort((a, b) => b.createdAt - a.createdAt)
db.close()
resolve(arr)
}
req.onerror = () => { db.close(); reject(req.error) }
})
} catch {}
db.close()
return []
},
/** 新增一张原始照片,返回其 id(自动置为最新) */
/** 新增一张原始照片,返回其 id(自动成为最新) */
async add(blob: Blob): Promise<string> {
const db = await openDb()
const id = Date.now().toString(36) + Math.random().toString(36).slice(2, 7)
+4 -7
View File
@@ -1090,7 +1090,7 @@ function ConsolePane() {
const photoUrlRef = useRef<string>('')
const [openMenu, setOpenMenu] = useState<string | null>(null)
const [bgEdit, setBgEdit] = useState<'plain' | 'glow' | 'photo' | null>(null)
const [plainHsl, setPlainHslState] = useState<{ h: number; s: number; l: number }>(() => splitEnv?.console?.getPlainHsl?.() ?? { h: 220, s: 31, l: 6 })
const [plainHsl, setPlainHslState] = useState<{ h: number; s: number; l: number }>(() => splitEnv?.console?.getPlainHsl?.() ?? { h: -140, s: 31, l: 6 })
const [glowHsl, setGlowHslState] = useState<{ h: number; s: number; l: number }>(() => splitEnv?.console?.getGlowHsl?.() ?? { h: 0, s: 100, l: 100 })
const [photoHsl, setPhotoHslState] = useState<{ h: number; s: number; l: number }>({ h: 0, s: 100, l: 100 })
const gridRef = useRef<HTMLDivElement | null>(null)
@@ -1129,11 +1129,10 @@ function ConsolePane() {
const onFilePhoto = async (file: Blob) => {
let id = ''
let url = ''
const rec = await splitEnv?.console?.addPhoto?.(file).catch(() => null)
const rec = await (splitEnv?.console?.addPhoto?.(file) ?? Promise.resolve(null)).catch(() => null)
if (rec) { id = rec.id; url = rec.url } else {
url = URL.createObjectURL(file)
}
if (photoUrlRef.current) { try { URL.revokeObjectURL(photoUrlRef.current) } catch {} }
photoUrlRef.current = url
setPhotoIdLocal(id)
if (id) setPhotoList((prev) => [{ id, url }, ...prev])
@@ -1145,7 +1144,6 @@ function ConsolePane() {
const selectPhoto = (p: { id: string; url: string }) => {
setPhotoIdLocal(p.id)
splitEnv?.console?.setPhotoId?.(p.id)
if (photoUrlRef.current) { try { URL.revokeObjectURL(photoUrlRef.current) } catch {} }
photoUrlRef.current = p.url
setBgPhoto(p.url)
setBgState('photo')
@@ -1177,8 +1175,8 @@ function ConsolePane() {
}
const resetHsl = (kind: 'plain' | 'glow' | 'photo') => {
if (kind === 'plain') {
setPlainHslState({ h: 0, s: 31, l: 6 })
splitEnv?.console?.setPlainHsl?.({ h: 0, s: 31, l: 6 })
setPlainHslState({ h: -140, s: 31, l: 6 })
splitEnv?.console?.setPlainHsl?.({ h: -140, s: 31, l: 6 })
} else if (kind === 'glow') {
setGlowHslState({ h: 0, s: 100, l: 100 })
splitEnv?.console?.setGlowHsl?.({ h: 0, s: 100, l: 100 })
@@ -1239,7 +1237,6 @@ function ConsolePane() {
const active = lib.list.find((p) => p.id === lib.activeId) ?? lib.list[0] ?? null
if (active) {
setPhotoIdLocal(active.id)
if (photoUrlRef.current) { try { URL.revokeObjectURL(photoUrlRef.current) } catch {} }
photoUrlRef.current = active.url
setBgPhoto(active.url)
}