refactor: improve codebase structure and Univer integration
- Add AGENTS.md knowledge base with project documentation - Move UserPreferences model to separate models.py file - Extract API_KEY to environment variable for security - Enhance Univer Editor with PPTX support and improved UI - Improve file system handling with binary file detection - Add HF_ENDPOINT mirror for better China connectivity - Clean up unused imports and code structure
This commit is contained in:
@@ -35,15 +35,20 @@ async function withStore(mode, handler) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction(STORE_NAME, mode)
|
||||
const store = transaction.objectStore(STORE_NAME)
|
||||
let result
|
||||
let request
|
||||
try {
|
||||
result = handler(store)
|
||||
request = handler(store)
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
return
|
||||
}
|
||||
transaction.oncomplete = () => resolve(result)
|
||||
transaction.onerror = () => reject(transaction.error || new Error('本地数据库写入失败'))
|
||||
if (request && typeof request.onsuccess === 'function') {
|
||||
request.onsuccess = () => resolve(request.result)
|
||||
request.onerror = () => reject(request.error || new Error('本地数据库操作失败'))
|
||||
} else {
|
||||
transaction.oncomplete = () => resolve(request)
|
||||
transaction.onerror = () => reject(transaction.error || new Error('本地数据库操作失败'))
|
||||
}
|
||||
transaction.onabort = () => reject(transaction.error || new Error('本地数据库操作已取消'))
|
||||
})
|
||||
}
|
||||
@@ -62,43 +67,32 @@ function getExtension(name = '') {
|
||||
}
|
||||
|
||||
function isTextExtension(ext) {
|
||||
return [
|
||||
'md',
|
||||
'markdown',
|
||||
'txt',
|
||||
'json',
|
||||
'js',
|
||||
'jsx',
|
||||
'ts',
|
||||
'tsx',
|
||||
'css',
|
||||
'scss',
|
||||
'less',
|
||||
'html',
|
||||
'htm',
|
||||
'py',
|
||||
'vue',
|
||||
'xml',
|
||||
'yaml',
|
||||
'yml',
|
||||
'csv',
|
||||
'log',
|
||||
'sql',
|
||||
'toml',
|
||||
'ini',
|
||||
'cfg',
|
||||
'conf',
|
||||
'sh',
|
||||
'bat',
|
||||
'ps1',
|
||||
'java',
|
||||
'c',
|
||||
'cpp',
|
||||
'h',
|
||||
'hpp',
|
||||
'go',
|
||||
'rs'
|
||||
].includes(ext)
|
||||
const textExtensions = [
|
||||
'md', 'markdown', 'txt', 'json', 'js', 'jsx', 'ts', 'tsx',
|
||||
'css', 'scss', 'less', 'html', 'htm', 'py', 'vue', 'xml',
|
||||
'yaml', 'yml', 'csv', 'log', 'sql', 'toml', 'ini', 'cfg',
|
||||
'conf', 'sh', 'bat', 'ps1', 'java', 'c', 'cpp', 'h', 'hpp',
|
||||
'go', 'rs', 'swift', 'kt', 'rb', 'php', 'pl', 'r', 'scala',
|
||||
'gradle', 'properties', 'env', 'gitignore', 'dockerfile'
|
||||
]
|
||||
return textExtensions.includes(ext)
|
||||
}
|
||||
|
||||
function isBinaryExtension(ext) {
|
||||
const binaryExtensions = [
|
||||
'exe', 'dll', 'so', 'dylib', 'bin', 'dat', 'obj', 'o', 'a',
|
||||
'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp',
|
||||
'pdf', 'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz',
|
||||
'png', 'jpg', 'jpeg', 'gif', 'bmp', 'ico', 'webp', 'svg',
|
||||
'mp3', 'mp4', 'wav', 'avi', 'mov', 'mkv', 'flv', 'wmv',
|
||||
'ttf', 'otf', 'woff', 'woff2', 'eot',
|
||||
'class', 'pyc', 'pyo', 'jar', 'war', 'ear',
|
||||
'db', 'sqlite', 'mdb', 'accdb',
|
||||
'pem', 'key', 'crt', 'cer', 'p12', 'pfx', 'jks',
|
||||
'msg', 'eml', 'pst', 'ost',
|
||||
'dwg', 'dxf', 'step', 'stl', 'obj', 'fbx', '3ds', 'blend'
|
||||
]
|
||||
return binaryExtensions.includes(ext.toLowerCase())
|
||||
}
|
||||
|
||||
function inferMimeType(name, fallback = '') {
|
||||
@@ -143,6 +137,8 @@ function inferMimeType(name, fallback = '') {
|
||||
|
||||
function isTextFile(record) {
|
||||
const ext = getExtension(record?.name)
|
||||
// 二进制文件不提供预览
|
||||
if (isBinaryExtension(ext)) return false
|
||||
const mime = String(record?.mimeType || '')
|
||||
return isTextExtension(ext) || mime.startsWith('text/') || mime.includes('json') || mime.includes('xml')
|
||||
}
|
||||
@@ -218,6 +214,7 @@ async function readFilePayload(file) {
|
||||
const mimeType = inferMimeType(file.name, file.type)
|
||||
const ext = getExtension(file.name)
|
||||
const textFile = isTextExtension(ext) || mimeType.startsWith('text/') || mimeType.includes('json') || mimeType.includes('xml')
|
||||
|
||||
if (!textFile) {
|
||||
return {
|
||||
mimeType,
|
||||
@@ -226,6 +223,17 @@ async function readFilePayload(file) {
|
||||
blob: file
|
||||
}
|
||||
}
|
||||
|
||||
// 二进制扩展名文件不尝试读取内容,避免长时间等待
|
||||
if (isBinaryExtension(ext)) {
|
||||
return {
|
||||
mimeType,
|
||||
size: file.size,
|
||||
storageKind: 'blob',
|
||||
blob: file
|
||||
}
|
||||
}
|
||||
|
||||
if (file.size <= MAX_TEXT_SIZE) {
|
||||
const content = await file.text()
|
||||
return {
|
||||
@@ -314,13 +322,8 @@ export function useFileSystem() {
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
const stored = await withStore('readonly', (store) => store.getAll())
|
||||
const request = stored
|
||||
const nextRecords = await new Promise((resolve, reject) => {
|
||||
request.onsuccess = () => resolve(Array.isArray(request.result) ? request.result : [])
|
||||
request.onerror = () => reject(request.error || new Error('读取本地文件失败'))
|
||||
})
|
||||
if (nextRecords.length === 0) {
|
||||
const nextRecords = await withStore('readonly', (store) => store.getAll())
|
||||
if (!Array.isArray(nextRecords) || nextRecords.length === 0) {
|
||||
const seed = createWelcomeRecords()
|
||||
await Promise.all(seed.map((record) => persistRecord(record)))
|
||||
records.value = seed
|
||||
|
||||
Reference in New Issue
Block a user