refactor: 前端本地偏好统一为公共存储层
- 新增 frontend/src/utils/storageKeys.ts 集中维护存储键常量并登记旧键迁移 - 新增 frontend/src/utils/storage.ts 统一 localStorage/sessionStorage 读写与异常容错 - 新增 frontend/src/composables/usePreference.ts 提供 useStringPreference 响应式字符串偏好 - 新增 frontend/src/utils/transactionFilterPrefs.ts 抽出收支筛选偏好字段定义与共享读写 - 存储键统一以 finance. 前缀命名,locale、emailBill.tab、logs.tab 迁移到新键并自动迁移旧值 - 各页面与组件改用公共层,移除重复的 try/catch 与跨组件重复的序列化逻辑 - 认证凭据 token 属登录状态,保持原键名不纳入 finance. 前缀
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { ref, watch, onBeforeUnmount, nextTick } from 'vue'
|
||||
import { NButton, NIcon } from 'naive-ui'
|
||||
import { CloseOutline } from '@vicons/ionicons5'
|
||||
import { readJson, writeJson } from '../utils/storage'
|
||||
|
||||
/** 浮窗位置与尺寸 */
|
||||
interface PanelRect {
|
||||
@@ -67,25 +68,20 @@ function clampRect() {
|
||||
/** 读取持久化的位置与尺寸,非法值回退默认并居中 */
|
||||
function loadRect() {
|
||||
if (props.storageKey) {
|
||||
try {
|
||||
const raw = localStorage.getItem(props.storageKey)
|
||||
const parsed = raw ? JSON.parse(raw) : null
|
||||
const x = Number(parsed?.x)
|
||||
const y = Number(parsed?.y)
|
||||
const width = Number(parsed?.width)
|
||||
const height = Number(parsed?.height)
|
||||
if ([x, y, width, height].every((n) => Number.isFinite(n))) {
|
||||
rect.value = {
|
||||
x,
|
||||
y,
|
||||
width: Math.max(props.minWidth, width),
|
||||
height: Math.max(props.minHeight, height),
|
||||
}
|
||||
clampRect()
|
||||
return
|
||||
const parsed = readJson<Partial<PanelRect> | null>(props.storageKey, null)
|
||||
const x = Number(parsed?.x)
|
||||
const y = Number(parsed?.y)
|
||||
const width = Number(parsed?.width)
|
||||
const height = Number(parsed?.height)
|
||||
if ([x, y, width, height].every((n) => Number.isFinite(n))) {
|
||||
rect.value = {
|
||||
x,
|
||||
y,
|
||||
width: Math.max(props.minWidth, width),
|
||||
height: Math.max(props.minHeight, height),
|
||||
}
|
||||
} catch {
|
||||
// 忽略读取失败
|
||||
clampRect()
|
||||
return
|
||||
}
|
||||
}
|
||||
rect.value = defaultRect()
|
||||
@@ -94,11 +90,7 @@ function loadRect() {
|
||||
/** 持久化位置与尺寸,忽略存储异常 */
|
||||
function saveRect() {
|
||||
if (!props.storageKey) return
|
||||
try {
|
||||
localStorage.setItem(props.storageKey, JSON.stringify(rect.value))
|
||||
} catch {
|
||||
// 忽略写入失败
|
||||
}
|
||||
writeJson(props.storageKey, rect.value)
|
||||
}
|
||||
|
||||
// 拖拽状态
|
||||
|
||||
@@ -9,9 +9,11 @@ import type { TransactionGroup, TransactionRelationType, TransactionGroupPayload
|
||||
import { getTransactionPage } from '../api/transaction'
|
||||
import { getAiConfig, parseRelationByAi } from '../api/ai'
|
||||
import { getChannelLabel } from '../utils/channel'
|
||||
import { readString, writeString } from '../utils/storage'
|
||||
import { STORAGE_KEYS } from '../utils/storageKeys'
|
||||
|
||||
/** 关系类型偏好存储键(界面偏好统一以 finance. 前缀命名) */
|
||||
const RELATION_TYPE_KEY = 'finance.transaction.relationType'
|
||||
const RELATION_TYPE_KEY = STORAGE_KEYS.transactionRelationType
|
||||
|
||||
const props = defineProps<{
|
||||
/** 弹窗显示状态 */
|
||||
@@ -79,21 +81,13 @@ onMounted(loadAiConfig)
|
||||
|
||||
/** 读取上次使用的关系类型偏好,非法值或异常回退 PARENT_CHILD */
|
||||
function loadPreferredRelationType(): TransactionRelationType {
|
||||
try {
|
||||
const saved = localStorage.getItem(RELATION_TYPE_KEY)
|
||||
return saved === 'PARENT_CHILD' || saved === 'SIBLING' ? saved : 'PARENT_CHILD'
|
||||
} catch (e) {
|
||||
return 'PARENT_CHILD'
|
||||
}
|
||||
const saved = readString(RELATION_TYPE_KEY)
|
||||
return saved === 'PARENT_CHILD' || saved === 'SIBLING' ? saved : 'PARENT_CHILD'
|
||||
}
|
||||
|
||||
/** 保存关系类型偏好,忽略存储异常 */
|
||||
function savePreferredRelationType(type: TransactionRelationType) {
|
||||
try {
|
||||
localStorage.setItem(RELATION_TYPE_KEY, type)
|
||||
} catch (e) {
|
||||
// 忽略存储异常
|
||||
}
|
||||
writeString(RELATION_TYPE_KEY, type)
|
||||
}
|
||||
|
||||
/** 加载关系名称历史(按当前关系类型过滤) */
|
||||
|
||||
Reference in New Issue
Block a user