新增:Markdown编辑器/数据库优化/安全修复
- Markdown 编辑器:实时预览、PDF 导出、独立查看器 - 数据库优化:动态连接池、查询缓存、Redis Pipeline - 窗口置顶功能 - 文件系统增强:右键菜单、编辑器集成、收藏夹重构 - 安全修复:XSS 防护、路径穿越、HTML 注入 - 代码质量:正则预编译、缓存锁优化、死代码清理
This commit is contained in:
@@ -66,8 +66,8 @@ export function useFavoriteFiles(storageKey, options = {}) {
|
||||
return
|
||||
}
|
||||
favoriteFiles.value.sort((a, b) => {
|
||||
const timeA = a.created_at || 0
|
||||
const timeB = b.created_at || 0
|
||||
const timeA = a.addedAt || 0
|
||||
const timeB = b.addedAt || 0
|
||||
return timeB - timeA // 倒序:最新的在上面
|
||||
})
|
||||
}
|
||||
@@ -106,8 +106,8 @@ export function useFavoriteFiles(storageKey, options = {}) {
|
||||
favoriteFiles.value.push({
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
is_dir: item.is_dir || false,
|
||||
created_at: Date.now(), // 添加时间戳(用于 getSortedFavorites)
|
||||
isDir: item.isDir || false,
|
||||
addedAt: Date.now(),
|
||||
})
|
||||
|
||||
save(favoriteFiles.value) // 直接保存,不重新排序(新项目添加到末尾)
|
||||
@@ -201,8 +201,8 @@ export function useFavoriteFiles(storageKey, options = {}) {
|
||||
const getSortedFavorites = (order = 'desc') => {
|
||||
const sorted = [...favoriteFiles.value]
|
||||
sorted.sort((a, b) => {
|
||||
const timeA = a.created_at || 0
|
||||
const timeB = b.created_at || 0
|
||||
const timeA = a.addedAt || 0
|
||||
const timeB = b.addedAt || 0
|
||||
return order === 'desc' ? timeB - timeA : timeA - timeB
|
||||
})
|
||||
return sorted
|
||||
@@ -255,9 +255,27 @@ export function useFavoriteFiles(storageKey, options = {}) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 组件挂载时加载数据(不自动排序,保持用户拖拽的顺序)
|
||||
// 旧字段名 → 新字段名迁移(一次性,迁移后自动回写)
|
||||
const migrateFieldNames = (list) => {
|
||||
if (!Array.isArray(list)) return
|
||||
const map = { is_dir: 'isDir', created_at: 'addedAt' }
|
||||
let changed = false
|
||||
list.forEach(item => {
|
||||
for (const [old, newKey] of Object.entries(map)) {
|
||||
if (old in item) {
|
||||
if (!(newKey in item)) item[newKey] = item[old]
|
||||
delete item[old]
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
})
|
||||
if (changed) save(list)
|
||||
}
|
||||
|
||||
// 组件挂载时加载数据并迁移旧字段
|
||||
onMounted(() => {
|
||||
load()
|
||||
migrateFieldNames(favoriteFiles.value)
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* LocalStorage composable
|
||||
* 通用的 localStorage 操作
|
||||
*/
|
||||
|
||||
import { watch, type Ref } from 'vue'
|
||||
|
||||
export function useLocalStorage<T>(
|
||||
key: string,
|
||||
defaultValue: T,
|
||||
storage: Storage = localStorage
|
||||
): [Ref<T>, (value: T) => void, () => void] {
|
||||
const stored = storage.getItem(key)
|
||||
const value = ref<T>(stored ? JSON.parse(stored) : defaultValue)
|
||||
|
||||
const setValue = (newValue: T) => {
|
||||
value.value = newValue
|
||||
}
|
||||
|
||||
const clearValue = () => {
|
||||
value.value = defaultValue
|
||||
storage.removeItem(key)
|
||||
}
|
||||
|
||||
watch(value, (newValue) => {
|
||||
try {
|
||||
storage.setItem(key, JSON.stringify(newValue))
|
||||
} catch (e) {
|
||||
console.warn(`Failed to save ${key} to localStorage:`, e)
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
return [value, setValue, clearValue]
|
||||
}
|
||||
Reference in New Issue
Block a user