diff --git a/db/connection.go b/db/connection.go index c9c774c..351183c 100644 --- a/db/connection.go +++ b/db/connection.go @@ -170,8 +170,8 @@ func insertDefaultDataIfEmpty() error { {Name: "weiyun", Key: 6, Icon: "", Remark: "微云"}, {Name: "lanzou", Key: 7, Icon: "", Remark: "蓝奏云"}, {Name: "123", Key: 8, Icon: "", Remark: "123云盘"}, - {Name: "onedrive", Key: 9, Icon: "", Remark: "OneDrive"}, - {Name: "google", Key: 10, Icon: "", Remark: "Google云盘"}, + {Name: "onedrive", Key: 9, Icon: "", Remark: "OneDrive"}, + {Name: "google", Key: 10, Icon: "", Remark: "Google云盘"}, {Name: "ctfile", Key: 11, Icon: "", Remark: "城通网盘"}, {Name: "115", Key: 12, Icon: "", Remark: "115网盘"}, {Name: "magnet", Key: 13, Icon: "", Remark: "磁力链接"}, diff --git a/db/repo/resource_repository.go b/db/repo/resource_repository.go index 1aab4d7..3883924 100644 --- a/db/repo/resource_repository.go +++ b/db/repo/resource_repository.go @@ -55,11 +55,29 @@ func (r *ResourceRepositoryImpl) FindWithRelationsPaginated(page, limit int) ([] var total int64 offset := (page - 1) * limit - db := r.db.Model(&entity.Resource{}).Preload("Category").Preload("Pan").Preload("Tags") - // 获取总数 - if err := db.Count(&total).Error; err != nil { - return nil, 0, err + // 优化查询:只预加载必要的关联,并添加排序 + db := r.db.Model(&entity.Resource{}). + Preload("Category"). + Preload("Pan"). + Order("updated_at DESC") // 按更新时间倒序,显示最新内容 + + // 获取总数(使用缓存键) + cacheKey := fmt.Sprintf("resources_total_%d_%d", page, limit) + if cached, exists := r.cache[cacheKey]; exists { + if totalCached, ok := cached.(int64); ok { + total = totalCached + } + } else { + if err := db.Count(&total).Error; err != nil { + return nil, 0, err + } + // 缓存总数(5分钟) + r.cache[cacheKey] = total + go func() { + time.Sleep(5 * time.Minute) + delete(r.cache, cacheKey) + }() } // 获取分页数据 diff --git a/handlers/resource_handler.go b/handlers/resource_handler.go index 2085070..0ae8d6f 100644 --- a/handlers/resource_handler.go +++ b/handlers/resource_handler.go @@ -22,6 +22,9 @@ func GetResources(c *gin.Context) { var total int64 var err error + // 设置响应头,启用缓存 + c.Header("Cache-Control", "public, max-age=300") // 5分钟缓存 + if search != "" { resources, total, err = repoManager.ResourceRepository.Search(search, nil, page, pageSize) } else if categoryID != "" { diff --git a/handlers/stats_handler.go b/handlers/stats_handler.go index 136b605..13f3a52 100644 --- a/handlers/stats_handler.go +++ b/handlers/stats_handler.go @@ -11,6 +11,9 @@ import ( // GetStats 获取基础统计信息 func GetStats(c *gin.Context) { + // 设置响应头,启用缓存 + c.Header("Cache-Control", "public, max-age=60") // 1分钟缓存 + // 获取数据库统计 var totalResources, totalCategories, totalTags, totalViews int64 db.DB.Model(&entity.Resource{}).Count(&totalResources) diff --git a/web/components/Icon.vue b/web/components/Icon.vue new file mode 100644 index 0000000..2b070e2 --- /dev/null +++ b/web/components/Icon.vue @@ -0,0 +1,99 @@ + + + \ No newline at end of file diff --git a/web/nuxt.config.ts b/web/nuxt.config.ts index d8e0649..dcb3144 100644 --- a/web/nuxt.config.ts +++ b/web/nuxt.config.ts @@ -9,6 +9,7 @@ export default defineNuxtConfig({ '~/assets/css/main.css', 'vfonts/Lato.css', 'vfonts/FiraCode.css', + '@fortawesome/fontawesome-free/css/all.min.css', // 本地Font Awesome ], app: { head: { @@ -19,11 +20,7 @@ export default defineNuxtConfig({ { name: 'description', content: '网盘资源管理系统 - 一个现代化的资源管理系统' } ], link: [ - { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, - { - rel: 'stylesheet', - href: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css' - } + { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } ] } }, diff --git a/web/package.json b/web/package.json index 56520bf..03e7dca 100644 --- a/web/package.json +++ b/web/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "@css-render/vue3-ssr": "^0.15.12", + "@fortawesome/fontawesome-free": "^6.7.2", "@juggle/resize-observer": "^3.3.1", "@nuxtjs/tailwindcss": "^6.8.0", "@pinia/nuxt": "^0.5.0", diff --git a/web/pages/index.vue b/web/pages/index.vue index e6f04de..ae21ecd 100644 --- a/web/pages/index.vue +++ b/web/pages/index.vue @@ -525,45 +525,65 @@ onMounted(async () => { console.log('首页 - isAuthenticated:', userStore.isAuthenticated) console.log('首页 - user:', userStore.userInfo) - // 使用Promise.allSettled来确保即使某个请求失败也不会影响其他请求 - const results = await Promise.allSettled([ - store.fetchResources().then((data: any) => { + // 设置超时时间(5秒) + const timeout = 5000 + const timeoutPromise = new Promise((_, reject) => { + setTimeout(() => reject(new Error('请求超时')), timeout) + }) + + // 使用Promise.race来添加超时机制,并优化请求顺序 + try { + // 首先加载最重要的数据(资源列表) + const resourcesPromise = store.fetchResources().then((data: any) => { localResources.value = data.resources || [] return data }).catch((e: any) => { console.error('获取资源失败:', e) return { resources: [] } - }), - store.fetchCategories().then((data: any) => { - localCategories.value = data.categories || [] - return data - }).catch((e: any) => { - console.error('获取分类失败:', e) - return { categories: [] } - }), - store.fetchStats().then((data: any) => { - localStats.value = data || { total_resources: 0, total_categories: 0, total_tags: 0, total_views: 0 } - return data - }).catch((e: any) => { - console.error('获取统计失败:', e) - return { total_resources: 0, total_categories: 0, total_tags: 0, total_views: 0 } - }), - fetchPlatforms().catch((e: any) => console.error('获取平台失败:', e)), - fetchSystemConfig().catch((e: any) => console.error('获取系统配置失败:', e)), - ]) - - // 检查哪些请求成功了 - results.forEach((result, index) => { - if (result.status === 'rejected') { - console.error(`请求 ${index} 失败:`, result.reason) - } - }) + }) + + // 等待资源数据加载完成或超时 + await Promise.race([resourcesPromise, timeoutPromise]) + + // 然后并行加载其他数据 + const otherDataPromise = Promise.allSettled([ + store.fetchCategories().then((data: any) => { + localCategories.value = data.categories || [] + return data + }).catch((e: any) => { + console.error('获取分类失败:', e) + return { categories: [] } + }), + store.fetchStats().then((data: any) => { + localStats.value = data || { total_resources: 0, total_categories: 0, total_tags: 0, total_views: 0 } + return data + }).catch((e: any) => { + console.error('获取统计失败:', e) + return { total_resources: 0, total_categories: 0, total_tags: 0, total_views: 0 } + }), + fetchPlatforms().catch((e: any) => console.error('获取平台失败:', e)), + fetchSystemConfig().catch((e: any) => console.error('获取系统配置失败:', e)), + ]) + + // 检查哪些请求成功了 + otherDataPromise.then(results => { + results.forEach((result, index) => { + if (result.status === 'rejected') { + console.error(`请求 ${index} 失败:`, result.reason) + } + }) + }) + + } catch (timeoutError) { + console.warn('部分数据加载超时,使用默认数据:', timeoutError) + // 超时后使用默认数据,不阻塞页面显示 + } animateCounters() } catch (error) { console.error('页面数据加载失败:', error) } finally { - // 所有数据加载完成后,关闭加载状态 + // 无论成功还是失败,都要关闭加载状态 pageLoading.value = false console.log('首页 - onMounted 完成') } diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 1a084a0..11589f5 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@css-render/vue3-ssr': specifier: ^0.15.12 version: 0.15.14(vue@3.5.17(typescript@5.8.3)) + '@fortawesome/fontawesome-free': + specifier: ^6.7.2 + version: 6.7.2 '@juggle/resize-observer': specifier: ^3.3.1 version: 3.4.0 @@ -549,6 +552,10 @@ packages: '@fastify/busboy@3.1.1': resolution: {integrity: sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw==} + '@fortawesome/fontawesome-free@6.7.2': + resolution: {integrity: sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==} + engines: {node: '>=6'} + '@ioredis/commands@1.2.0': resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} @@ -4970,6 +4977,8 @@ snapshots: '@fastify/busboy@3.1.1': {} + '@fortawesome/fontawesome-free@6.7.2': {} + '@ioredis/commands@1.2.0': {} '@isaacs/cliui@8.0.2':