From cf3376eb31fc936adf44bf3af9741e55a10fb404 Mon Sep 17 00:00:00 2001 From: ctwj <908504609@qq.com> Date: Sun, 27 Jul 2025 01:45:04 +0800 Subject: [PATCH] =?UTF-8?q?update:=20=E6=9B=B4=E6=96=B0=E9=A1=B5=E9=9D=A2,?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B7=BB=E5=8A=A0=E8=B5=84=E6=BA=90=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/repo/resource_repository.go | 2 +- utils/scheduler.go | 97 +++++++++++++++++++++++++--- web/components/SingleAddResource.vue | 24 +++---- web/composables/useApi.ts | 9 ++- web/pages/admin/categories.vue | 28 +++++++- web/pages/admin/tags.vue | 67 +++++++++++++++++-- web/pages/login.vue | 8 +-- 7 files changed, 196 insertions(+), 39 deletions(-) diff --git a/db/repo/resource_repository.go b/db/repo/resource_repository.go index 7145476..507fcc3 100644 --- a/db/repo/resource_repository.go +++ b/db/repo/resource_repository.go @@ -334,7 +334,7 @@ func (r *ResourceRepositoryImpl) InvalidateCache() error { // FindExists 检查是否存在相同URL的资源 func (r *ResourceRepositoryImpl) FindExists(url string, excludeID ...uint) (bool, error) { var count int64 - query := r.db.Model(&entity.Resource{}).Where("url = ? or save_url ", url, url) + query := r.db.Model(&entity.Resource{}).Where("url = ? OR save_url = ?", url, url) // 如果有排除ID,则排除该记录(用于更新时排除自己) if len(excludeID) > 0 { diff --git a/utils/scheduler.go b/utils/scheduler.go index 14766e4..2c3bcda 100644 --- a/utils/scheduler.go +++ b/utils/scheduler.go @@ -428,6 +428,34 @@ func (s *Scheduler) convertReadyResourceToResource(readyResource entity.ReadyRes return nil } else { + // 获取夸克网盘账号的 cookie + accounts, err := s.cksRepo.FindByPanID(*s.getPanIDByServiceType(serviceType)) + if err != nil { + Error("获取夸克网盘账号失败: %v", err) + return err + } + + if len(accounts) == 0 { + Error("没有可用的夸克网盘账号") + return fmt.Errorf("没有可用的夸克网盘账号") + } + + // 选择第一个有效的账号 + var selectedAccount *entity.Cks + for _, account := range accounts { + if account.IsValid { + selectedAccount = &account + break + } + } + + if selectedAccount == nil { + Error("没有有效的夸克网盘账号") + return fmt.Errorf("没有有效的夸克网盘账号") + } + + Debug("使用夸克网盘账号: %d, Cookie: %s", selectedAccount.ID, selectedAccount.Ck[:20]+"...") + // 准备配置 config := &panutils.PanConfig{ URL: readyResource.URL, @@ -436,6 +464,7 @@ func (s *Scheduler) convertReadyResourceToResource(readyResource entity.ReadyRes ExpiredType: 1, // 永久分享 AdFid: "", Stoken: "", + Cookie: selectedAccount.Ck, // 添加 cookie } // 通过工厂获取对应的网盘服务单例 @@ -457,14 +486,22 @@ func (s *Scheduler) convertReadyResourceToResource(readyResource entity.ReadyRes return nil } + // 如果获取到了标题,更新资源标题 + if result.Title != "" { + resource.Title = result.Title + } } // 处理标签 tagIDs, err := s.handleTags(readyResource.Tags) - if err != nil || tagIDs == nil { + if err != nil { Error("处理标签失败: %v", err) return err } + // 如果没有标签,tagIDs 可能为 nil,这是正常的 + if tagIDs == nil { + tagIDs = []uint{} // 初始化为空数组 + } // 处理分类 categoryID, err := s.resolveCategory(readyResource.Category, tagIDs) if err != nil { @@ -481,11 +518,15 @@ func (s *Scheduler) convertReadyResourceToResource(readyResource entity.ReadyRes return err } // 插入 resource_tags 关联 - for _, tagID := range tagIDs { - err := s.resourceRepo.CreateResourceTag(resource.ID, tagID) - if err != nil { - Error("插入资源标签关联失败: %v", err) + if len(tagIDs) > 0 { + for _, tagID := range tagIDs { + err := s.resourceRepo.CreateResourceTag(resource.ID, tagID) + if err != nil { + Error("插入资源标签关联失败: %v", err) + } } + } else { + Debug("没有标签,跳过插入资源标签关联") } return nil } @@ -889,44 +930,80 @@ func splitTags(tagStr string) []string { // 处理标签,返回所有标签ID func (s *Scheduler) handleTags(tagStr string) ([]uint, error) { if tagStr == "" { - return nil, nil + Debug("标签字符串为空,返回空数组") + return []uint{}, nil // 返回空数组而不是 nil } + + Debug("开始处理标签字符串: %s", tagStr) tagNames := splitTags(tagStr) + Debug("分割后的标签名称: %v", tagNames) + var tagIDs []uint for _, name := range tagNames { name = strings.TrimSpace(name) if name == "" { + Debug("跳过空标签名称") continue } + + Debug("查找标签: %s", name) tag, err := s.tagRepo.FindByName(name) - if err != nil || tag == nil { + if err != nil { + Debug("标签 %s 不存在,创建新标签", name) // 不存在则新建 tag = &entity.Tag{Name: name} err = s.tagRepo.Create(tag) if err != nil { - return nil, err + Error("创建标签 %s 失败: %v", name, err) + return nil, fmt.Errorf("创建标签 %s 失败: %v", name, err) } + Debug("成功创建标签: %s (ID: %d)", name, tag.ID) + } else { + Debug("找到已存在的标签: %s (ID: %d)", name, tag.ID) } tagIDs = append(tagIDs, tag.ID) } + + Debug("处理完成,标签ID列表: %v", tagIDs) return tagIDs, nil } // 分类处理逻辑 func (s *Scheduler) resolveCategory(categoryName string, tagIDs []uint) (*uint, error) { + Debug("开始处理分类,分类名称: %s, 标签ID列表: %v", categoryName, tagIDs) + if categoryName != "" { + Debug("查找分类: %s", categoryName) cat, err := s.categoryRepo.FindByName(categoryName) - if err == nil && cat != nil { + if err != nil { + Debug("分类 %s 不存在: %v", categoryName, err) + } else if cat != nil { + Debug("找到分类: %s (ID: %d)", categoryName, cat.ID) return &cat.ID, nil } } + // 没有分类,尝试用标签反查 + if len(tagIDs) == 0 { + Debug("没有标签,无法通过标签反查分类") + return nil, nil + } + + Debug("尝试通过标签反查分类") for _, tagID := range tagIDs { + Debug("查找标签ID: %d", tagID) tag, err := s.tagRepo.GetByID(tagID) - if err == nil && tag != nil && tag.CategoryID != nil { + if err != nil { + Debug("查找标签ID %d 失败: %v", tagID, err) + continue + } + if tag != nil && tag.CategoryID != nil { + Debug("通过标签 %s (ID: %d) 找到分类ID: %d", tag.Name, tagID, *tag.CategoryID) return tag.CategoryID, nil } } + + Debug("未找到分类,返回nil") return nil, nil } diff --git a/web/components/SingleAddResource.vue b/web/components/SingleAddResource.vue index fd893ed..4dec13f 100644 --- a/web/components/SingleAddResource.vue +++ b/web/components/SingleAddResource.vue @@ -39,7 +39,7 @@ required >

- 支持百度网盘、阿里云盘、夸克网盘等链接 + 支持百度网盘、阿里云盘、夸克网盘等链接,每行一个链接

@@ -205,7 +205,7 @@ const clearForm = () => { newTag.value = '' } -// 单个添加提交 +// 单个添加提交 - 更新为使用批量添加方法 const handleSubmit = async () => { loading.value = true try { @@ -214,23 +214,23 @@ const handleSubmit = async () => { // 多行链接处理 const urls = form.value.url.split(/\r?\n/).map(l => l.trim()).filter(Boolean) - // 为每个URL创建一个资源 - for (const url of urls) { - const resourceData = { - title: form.value.title, // 标题必填 - description: form.value.description || undefined, // 添加描述 - url: url, + // 使用批量添加方法,将多个URL作为一个资源的多个链接 + const resourceData = { + resources: [{ + title: form.value.title || undefined, // 后端期望 *string 类型 + description: form.value.description || '', + url: urls, // 现在 url 是一个数组 category: form.value.category || '', tags: form.value.tags.join(','), // 转换为逗号分隔的字符串 img: form.value.img || '', source: form.value.source || '手动添加', extra: form.value.extra || '', - } - - await readyResourceApi.createReadyResource(resourceData) + }] } - emit('success', `成功添加 ${urls.length} 个资源到待处理列表`) + const response = await readyResourceApi.batchCreateReadyResources(resourceData) + + emit('success', `成功添加资源,包含 ${urls.length} 个链接`) clearForm() } catch (e: any) { emit('error', e.message || '添加失败') diff --git a/web/composables/useApi.ts b/web/composables/useApi.ts index 67e1c7d..7ea8675 100644 --- a/web/composables/useApi.ts +++ b/web/composables/useApi.ts @@ -18,6 +18,11 @@ export const parseApiResponse = (response: any): T => { } } + // 检查是否是包含items字段的响应格式(如分类接口) + if (response && typeof response === 'object' && 'items' in response) { + return response + } + // 检查是否是包含success字段的响应格式(如登录接口) if (response && typeof response === 'object' && 'success' in response && 'data' in response) { if (response.success) { @@ -66,7 +71,7 @@ export const useAuthApi = () => { } export const useCategoryApi = () => { - const getCategories = () => useApiFetch('/categories').then(parseApiResponse) + const getCategories = (params?: any) => useApiFetch('/categories', { params }).then(parseApiResponse) const createCategory = (data: any) => useApiFetch('/categories', { method: 'POST', body: data }).then(parseApiResponse) const updateCategory = (id: number, data: any) => useApiFetch(`/categories/${id}`, { method: 'PUT', body: data }).then(parseApiResponse) const deleteCategory = (id: number) => useApiFetch(`/categories/${id}`, { method: 'DELETE' }).then(parseApiResponse) @@ -93,7 +98,7 @@ export const useCksApi = () => { } export const useTagApi = () => { - const getTags = () => useApiFetch('/tags').then(parseApiResponse) + const getTags = (params?: any) => useApiFetch('/tags', { params }).then(parseApiResponse) const getTagsByCategory = (categoryId: number, params?: any) => useApiFetch(`/categories/${categoryId}/tags`, { params }).then(parseApiResponse) const getTag = (id: number) => useApiFetch(`/tags/${id}`).then(parseApiResponse) const createTag = (data: any) => useApiFetch('/tags', { method: 'POST', body: data }).then(parseApiResponse) diff --git a/web/pages/admin/categories.vue b/web/pages/admin/categories.vue index 7071db1..0ab2757 100644 --- a/web/pages/admin/categories.vue +++ b/web/pages/admin/categories.vue @@ -260,12 +260,34 @@ const fetchCategories = async () => { page_size: pageSize.value, search: searchQuery.value } + console.log('获取分类列表参数:', params) const response = await categoryApi.getCategories(params) - categories.value = Array.isArray(response) ? response : [] - totalCount.value = response.total || 0 - totalPages.value = Math.ceil(totalCount.value / pageSize.value) + console.log('分类接口响应:', response) + + // 适配后端API响应格式 + if (response && response.items) { + console.log('使用 items 格式:', response.items) + categories.value = response.items + totalCount.value = response.total || 0 + totalPages.value = Math.ceil(totalCount.value / pageSize.value) + } else if (Array.isArray(response)) { + console.log('使用数组格式:', response) + // 兼容旧格式 + categories.value = response + totalCount.value = response.length + totalPages.value = 1 + } else { + console.log('使用默认格式:', response) + categories.value = [] + totalCount.value = 0 + totalPages.value = 1 + } + console.log('最终分类数据:', categories.value) } catch (error) { console.error('获取分类列表失败:', error) + categories.value = [] + totalCount.value = 0 + totalPages.value = 1 } finally { loading.value = false } diff --git a/web/pages/admin/tags.vue b/web/pages/admin/tags.vue index 35e0948..20890aa 100644 --- a/web/pages/admin/tags.vue +++ b/web/pages/admin/tags.vue @@ -267,6 +267,9 @@