Merge branch 'main' of https://github.com/ctwj/urldb into feat_xunlei

This commit is contained in:
Kerwin
2025-09-05 16:28:46 +08:00
69 changed files with 4581 additions and 2225 deletions

View File

@@ -2,11 +2,18 @@ package handlers
import (
"github.com/ctwj/urldb/db/repo"
"github.com/ctwj/urldb/services"
)
var repoManager *repo.RepositoryManager
var meilisearchManager *services.MeilisearchManager
// SetRepositoryManager 设置Repository管理器
func SetRepositoryManager(rm *repo.RepositoryManager) {
repoManager = rm
func SetRepositoryManager(manager *repo.RepositoryManager) {
repoManager = manager
}
// SetMeilisearchManager 设置Meilisearch管理器
func SetMeilisearchManager(manager *services.MeilisearchManager) {
meilisearchManager = manager
}

View File

@@ -0,0 +1,270 @@
package handlers
import (
"net/http"
"strconv"
"github.com/ctwj/urldb/db/converter"
"github.com/ctwj/urldb/services"
"github.com/ctwj/urldb/utils"
"github.com/gin-gonic/gin"
)
// MeilisearchHandler Meilisearch处理器
type MeilisearchHandler struct {
meilisearchManager *services.MeilisearchManager
}
// NewMeilisearchHandler 创建Meilisearch处理器
func NewMeilisearchHandler(meilisearchManager *services.MeilisearchManager) *MeilisearchHandler {
return &MeilisearchHandler{
meilisearchManager: meilisearchManager,
}
}
// TestConnection 测试Meilisearch连接
func (h *MeilisearchHandler) TestConnection(c *gin.Context) {
var req struct {
Host string `json:"host"`
Port interface{} `json:"port"` // 支持字符串或数字
MasterKey string `json:"masterKey"`
IndexName string `json:"indexName"` // 可选字段
}
if err := c.ShouldBindJSON(&req); err != nil {
ErrorResponse(c, "请求参数错误", http.StatusBadRequest)
return
}
// 验证必要字段
if req.Host == "" {
ErrorResponse(c, "主机地址不能为空", http.StatusBadRequest)
return
}
// 转换port为字符串
var portStr string
switch v := req.Port.(type) {
case string:
portStr = v
case float64:
portStr = strconv.Itoa(int(v))
case int:
portStr = strconv.Itoa(v)
default:
portStr = "7700" // 默认端口
}
// 如果没有提供索引名称,使用默认值
indexName := req.IndexName
if indexName == "" {
indexName = "resources"
}
// 创建临时服务进行测试
service := services.NewMeilisearchService(req.Host, portStr, req.MasterKey, indexName, true)
if err := service.HealthCheck(); err != nil {
ErrorResponse(c, "连接测试失败: "+err.Error(), http.StatusBadRequest)
return
}
SuccessResponse(c, gin.H{"message": "连接测试成功"})
}
// GetStatus 获取Meilisearch状态
func (h *MeilisearchHandler) GetStatus(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{
"enabled": false,
"healthy": false,
"message": "Meilisearch未初始化",
})
return
}
status, err := h.meilisearchManager.GetStatusWithHealthCheck()
if err != nil {
ErrorResponse(c, "获取状态失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, status)
}
// GetUnsyncedCount 获取未同步资源数量
func (h *MeilisearchHandler) GetUnsyncedCount(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{"count": 0})
return
}
count, err := h.meilisearchManager.GetUnsyncedCount()
if err != nil {
ErrorResponse(c, "获取未同步数量失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{"count": count})
}
// GetUnsyncedResources 获取未同步的资源
func (h *MeilisearchHandler) GetUnsyncedResources(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{
"resources": []interface{}{},
"total": 0,
})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
resources, total, err := h.meilisearchManager.GetUnsyncedResources(page, pageSize)
if err != nil {
ErrorResponse(c, "获取未同步资源失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"resources": converter.ToResourceResponseList(resources),
"total": total,
"page": page,
"page_size": pageSize,
})
}
// GetSyncedResources 获取已同步的资源
func (h *MeilisearchHandler) GetSyncedResources(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{
"resources": []interface{}{},
"total": 0,
})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
resources, total, err := h.meilisearchManager.GetSyncedResources(page, pageSize)
if err != nil {
ErrorResponse(c, "获取已同步资源失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"resources": converter.ToResourceResponseList(resources),
"total": total,
"page": page,
"page_size": pageSize,
})
}
// GetAllResources 获取所有资源
func (h *MeilisearchHandler) GetAllResources(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{
"resources": []interface{}{},
"total": 0,
})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
resources, total, err := h.meilisearchManager.GetAllResources(page, pageSize)
if err != nil {
ErrorResponse(c, "获取所有资源失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"resources": converter.ToResourceResponseList(resources),
"total": total,
"page": page,
"page_size": pageSize,
})
}
// SyncAllResources 同步所有资源
func (h *MeilisearchHandler) SyncAllResources(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
utils.Info("开始同步所有资源到Meilisearch...")
_, err := h.meilisearchManager.SyncAllResources()
if err != nil {
ErrorResponse(c, "同步失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"message": "同步已开始,请查看进度",
})
}
// GetSyncProgress 获取同步进度
func (h *MeilisearchHandler) GetSyncProgress(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
progress := h.meilisearchManager.GetSyncProgress()
SuccessResponse(c, progress)
}
// StopSync 停止同步
func (h *MeilisearchHandler) StopSync(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
h.meilisearchManager.StopSync()
SuccessResponse(c, gin.H{
"message": "同步已停止",
})
}
// ClearIndex 清空索引
func (h *MeilisearchHandler) ClearIndex(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
if err := h.meilisearchManager.ClearIndex(); err != nil {
ErrorResponse(c, "清空索引失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{"message": "清空索引成功"})
}
// UpdateIndexSettings 更新索引设置
func (h *MeilisearchHandler) UpdateIndexSettings(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
service := h.meilisearchManager.GetService()
if service == nil {
ErrorResponse(c, "Meilisearch服务未初始化", http.StatusInternalServerError)
return
}
if err := service.UpdateIndexSettings(); err != nil {
ErrorResponse(c, "更新索引设置失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{"message": "索引设置更新成功"})
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/ctwj/urldb/db/dto"
"github.com/ctwj/urldb/db/entity"
"github.com/ctwj/urldb/utils"
"github.com/gin-gonic/gin"
)
@@ -182,6 +183,7 @@ func (h *PublicAPIHandler) SearchResources(c *gin.Context) {
keyword := c.Query("keyword")
tag := c.Query("tag")
category := c.Query("category")
panID := c.Query("pan_id")
pageStr := c.DefaultQuery("page", "1")
pageSizeStr := c.DefaultQuery("page_size", "20")
@@ -195,67 +197,129 @@ func (h *PublicAPIHandler) SearchResources(c *gin.Context) {
pageSize = 20
}
// 构建搜索条件
params := map[string]interface{}{
"page": page,
"page_size": pageSize,
var resources []entity.Resource
var total int64
// 如果启用了Meilisearch优先使用Meilisearch搜索
if meilisearchManager != nil && meilisearchManager.IsEnabled() {
// 构建过滤器
filters := make(map[string]interface{})
if category != "" {
filters["category"] = category
}
if tag != "" {
filters["tags"] = tag
}
if panID != "" {
if id, err := strconv.ParseUint(panID, 10, 32); err == nil {
// 根据pan_id获取pan_name
pan, err := repoManager.PanRepository.FindByID(uint(id))
if err == nil && pan != nil {
filters["pan_name"] = pan.Name
}
}
}
// 使用Meilisearch搜索
service := meilisearchManager.GetService()
if service != nil {
docs, docTotal, err := service.Search(keyword, filters, page, pageSize)
if err == nil {
// 将Meilisearch文档转换为Resource实体保持兼容性
for _, doc := range docs {
resource := entity.Resource{
ID: doc.ID,
Title: doc.Title,
Description: doc.Description,
URL: doc.URL,
SaveURL: doc.SaveURL,
FileSize: doc.FileSize,
Key: doc.Key,
PanID: doc.PanID,
CreatedAt: doc.CreatedAt,
UpdatedAt: doc.UpdatedAt,
}
resources = append(resources, resource)
}
total = docTotal
} else {
utils.Error("Meilisearch搜索失败回退到数据库搜索: %v", err)
}
}
}
if keyword != "" {
params["search"] = keyword
// 如果Meilisearch未启用或搜索失败使用数据库搜索
if meilisearchManager == nil || !meilisearchManager.IsEnabled() || err != nil {
// 构建搜索条件
params := map[string]interface{}{
"page": page,
"page_size": pageSize,
}
if keyword != "" {
params["search"] = keyword
}
if tag != "" {
params["tag"] = tag
}
if category != "" {
params["category"] = category
}
if panID != "" {
if id, err := strconv.ParseUint(panID, 10, 32); err == nil {
params["pan_id"] = uint(id)
}
}
// 执行数据库搜索
resources, total, err = repoManager.ResourceRepository.SearchWithFilters(params)
if err != nil {
ErrorResponse(c, "搜索失败: "+err.Error(), 500)
return
}
}
if tag != "" {
params["tag"] = tag
}
if category != "" {
params["category"] = category
}
// 执行搜索
resources, total, err := repoManager.ResourceRepository.SearchWithFilters(params)
// 获取违禁词配置(只获取一次)
cleanWords, err := utils.GetForbiddenWordsFromConfig(func() (string, error) {
return repoManager.SystemConfigRepository.GetConfigValue(entity.ConfigKeyForbiddenWords)
})
if err != nil {
ErrorResponse(c, "搜索失败: "+err.Error(), 500)
return
utils.Error("获取违禁词配置失败: %v", err)
cleanWords = []string{} // 如果获取失败,使用空列表
}
// 过滤违禁词
filteredResources, foundForbiddenWords := h.filterForbiddenWords(resources)
// 计算过滤后的总数
filteredTotal := len(filteredResources)
// 转换为响应格式
// 转换为响应格式并添加违禁词标记
var resourceResponses []gin.H
for _, resource := range filteredResources {
resourceResponses = append(resourceResponses, gin.H{
"id": resource.ID,
"title": resource.Title,
"url": resource.URL,
"description": resource.Description,
"view_count": resource.ViewCount,
"created_at": resource.CreatedAt.Format("2006-01-02 15:04:05"),
"updated_at": resource.UpdatedAt.Format("2006-01-02 15:04:05"),
})
for i, processedResource := range resources {
originalResource := resources[i]
forbiddenInfo := utils.CheckResourceForbiddenWords(originalResource.Title, originalResource.Description, cleanWords)
resourceResponse := gin.H{
"id": processedResource.ID,
"title": forbiddenInfo.ProcessedTitle, // 使用处理后的标题
"url": processedResource.URL,
"description": forbiddenInfo.ProcessedDesc, // 使用处理后的描述
"view_count": processedResource.ViewCount,
"created_at": processedResource.CreatedAt.Format("2006-01-02 15:04:05"),
"updated_at": processedResource.UpdatedAt.Format("2006-01-02 15:04:05"),
}
// 添加违禁词标记
resourceResponse["has_forbidden_words"] = forbiddenInfo.HasForbiddenWords
resourceResponse["forbidden_words"] = forbiddenInfo.ForbiddenWords
resourceResponses = append(resourceResponses, resourceResponse)
}
// 构建响应数据
responseData := gin.H{
"list": resourceResponses,
"total": filteredTotal,
"total": total,
"page": page,
"limit": pageSize,
}
// 如果存在违禁词过滤,添加提醒字段
if len(foundForbiddenWords) > 0 {
responseData["forbidden_words_filtered"] = true
responseData["filtered_forbidden_words"] = foundForbiddenWords
responseData["original_total"] = total
responseData["filtered_count"] = total - int64(filteredTotal)
}
SuccessResponse(c, responseData)
}

View File

@@ -64,19 +64,123 @@ func GetResources(c *gin.Context) {
params["pan_name"] = panName
}
resources, total, err := repoManager.ResourceRepository.SearchWithFilters(params)
// 获取违禁词配置(只获取一次)
cleanWords, err := utils.GetForbiddenWordsFromConfig(func() (string, error) {
return repoManager.SystemConfigRepository.GetConfigValue(entity.ConfigKeyForbiddenWords)
})
if err != nil {
utils.Error("获取违禁词配置失败: %v", err)
cleanWords = []string{} // 如果获取失败,使用空列表
}
var resources []entity.Resource
var total int64
// 如果有搜索关键词且启用了Meilisearch优先使用Meilisearch搜索
if search := c.Query("search"); search != "" && meilisearchManager != nil && meilisearchManager.IsEnabled() {
// 构建Meilisearch过滤器
filters := make(map[string]interface{})
if panID := c.Query("pan_id"); panID != "" {
if id, err := strconv.ParseUint(panID, 10, 32); err == nil {
// 直接使用pan_id进行过滤
filters["pan_id"] = id
}
}
// 使用Meilisearch搜索
service := meilisearchManager.GetService()
if service != nil {
docs, docTotal, err := service.Search(search, filters, page, pageSize)
if err == nil {
// 将Meilisearch文档转换为ResourceResponse包含高亮信息并处理违禁词
var resourceResponses []dto.ResourceResponse
for _, doc := range docs {
resourceResponse := converter.ToResourceResponseFromMeilisearch(doc)
// 处理违禁词Meilisearch场景需要处理高亮标记
if len(cleanWords) > 0 {
forbiddenInfo := utils.CheckResourceForbiddenWords(resourceResponse.Title, resourceResponse.Description, cleanWords)
if forbiddenInfo.HasForbiddenWords {
resourceResponse.Title = forbiddenInfo.ProcessedTitle
resourceResponse.Description = forbiddenInfo.ProcessedDesc
resourceResponse.TitleHighlight = forbiddenInfo.ProcessedTitle
resourceResponse.DescriptionHighlight = forbiddenInfo.ProcessedDesc
}
resourceResponse.HasForbiddenWords = forbiddenInfo.HasForbiddenWords
resourceResponse.ForbiddenWords = forbiddenInfo.ForbiddenWords
}
resourceResponses = append(resourceResponses, resourceResponse)
}
// 返回Meilisearch搜索结果包含高亮信息
SuccessResponse(c, gin.H{
"data": resourceResponses,
"total": docTotal,
"page": page,
"page_size": pageSize,
"source": "meilisearch",
})
return
} else {
utils.Error("Meilisearch搜索失败回退到数据库搜索: %v", err)
}
}
}
// 如果Meilisearch未启用、搜索失败或没有搜索关键词使用数据库搜索
if meilisearchManager == nil || !meilisearchManager.IsEnabled() || len(resources) == 0 {
resources, total, err = repoManager.ResourceRepository.SearchWithFilters(params)
}
if err != nil {
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"data": converter.ToResourceResponseList(resources),
// 处理违禁词替换和标记
var processedResources []entity.Resource
if len(cleanWords) > 0 {
processedResources = utils.ProcessResourcesForbiddenWords(resources, cleanWords)
} else {
processedResources = resources
}
// 转换为响应格式并添加违禁词标记
var resourceResponses []gin.H
for i, processedResource := range processedResources {
// 使用原始资源进行检查违禁词(数据库搜索场景,使用普通处理)
originalResource := resources[i]
forbiddenInfo := utils.CheckResourceForbiddenWords(originalResource.Title, originalResource.Description, cleanWords)
resourceResponse := gin.H{
"id": processedResource.ID,
"title": forbiddenInfo.ProcessedTitle, // 使用处理后的标题
"url": processedResource.URL,
"description": forbiddenInfo.ProcessedDesc, // 使用处理后的描述
"pan_id": processedResource.PanID,
"view_count": processedResource.ViewCount,
"created_at": processedResource.CreatedAt.Format("2006-01-02 15:04:05"),
"updated_at": processedResource.UpdatedAt.Format("2006-01-02 15:04:05"),
}
// 添加违禁词标记
resourceResponse["has_forbidden_words"] = forbiddenInfo.HasForbiddenWords
resourceResponse["forbidden_words"] = forbiddenInfo.ForbiddenWords
resourceResponses = append(resourceResponses, resourceResponse)
}
// 构建响应数据
responseData := gin.H{
"data": resourceResponses,
"total": total,
"page": page,
"page_size": pageSize,
})
}
SuccessResponse(c, responseData)
}
// GetResourceByID 根据ID获取资源
@@ -164,6 +268,15 @@ func CreateResource(c *gin.Context) {
}
}
// 同步到Meilisearch
if meilisearchManager != nil && meilisearchManager.IsEnabled() {
go func() {
if err := meilisearchManager.SyncResourceToMeilisearch(resource); err != nil {
utils.Error("同步资源到Meilisearch失败: %v", err)
}
}()
}
SuccessResponse(c, gin.H{
"message": "资源创建成功",
"resource": converter.ToResourceResponse(resource),
@@ -240,6 +353,15 @@ func UpdateResource(c *gin.Context) {
}
}
// 同步到Meilisearch
if meilisearchManager != nil && meilisearchManager.IsEnabled() {
go func() {
if err := meilisearchManager.SyncResourceToMeilisearch(resource); err != nil {
utils.Error("同步资源到Meilisearch失败: %v", err)
}
}()
}
SuccessResponse(c, gin.H{"message": "资源更新成功"})
}
@@ -271,12 +393,53 @@ func SearchResources(c *gin.Context) {
var total int64
var err error
if query == "" {
// 搜索关键词为空时,返回最新记录(分页)
resources, total, err = repoManager.ResourceRepository.FindWithRelationsPaginated(page, pageSize)
} else {
// 有搜索关键词时,执行搜索
resources, total, err = repoManager.ResourceRepository.Search(query, nil, page, pageSize)
// 如果启用了Meilisearch优先使用Meilisearch搜索
if meilisearchManager != nil && meilisearchManager.IsEnabled() {
// 构建过滤器
filters := make(map[string]interface{})
if categoryID := c.Query("category_id"); categoryID != "" {
if id, err := strconv.ParseUint(categoryID, 10, 32); err == nil {
filters["category"] = uint(id)
}
}
// 使用Meilisearch搜索
service := meilisearchManager.GetService()
if service != nil {
docs, docTotal, err := service.Search(query, filters, page, pageSize)
if err == nil {
// 将Meilisearch文档转换为Resource实体
for _, doc := range docs {
resource := entity.Resource{
ID: doc.ID,
Title: doc.Title,
Description: doc.Description,
URL: doc.URL,
SaveURL: doc.SaveURL,
FileSize: doc.FileSize,
Key: doc.Key,
PanID: doc.PanID,
CreatedAt: doc.CreatedAt,
UpdatedAt: doc.UpdatedAt,
}
resources = append(resources, resource)
}
total = docTotal
} else {
utils.Error("Meilisearch搜索失败回退到数据库搜索: %v", err)
}
}
}
// 如果Meilisearch未启用或搜索失败使用数据库搜索
if meilisearchManager == nil || !meilisearchManager.IsEnabled() || err != nil {
if query == "" {
// 搜索关键词为空时,返回最新记录(分页)
resources, total, err = repoManager.ResourceRepository.FindWithRelationsPaginated(page, pageSize)
} else {
// 有搜索关键词时,执行搜索
resources, total, err = repoManager.ResourceRepository.Search(query, nil, page, pageSize)
}
}
if err != nil {

View File

@@ -195,6 +195,17 @@ func UpdateSystemConfig(c *gin.Context) {
// 刷新系统配置缓存
pan.RefreshSystemConfigCache()
// 重新加载Meilisearch配置如果Meilisearch配置有变更
if req.MeilisearchEnabled != nil || req.MeilisearchHost != nil || req.MeilisearchPort != nil || req.MeilisearchMasterKey != nil || req.MeilisearchIndexName != nil {
if meilisearchManager != nil {
if err := meilisearchManager.ReloadConfig(); err != nil {
utils.Error("重新加载Meilisearch配置失败: %v", err)
} else {
utils.Debug("Meilisearch配置重新加载成功")
}
}
}
// 根据配置更新定时任务状态(错误不影响配置保存)
scheduler := scheduler.GetGlobalScheduler(
repoManager.HotDramaRepository,
@@ -311,6 +322,12 @@ func ToggleAutoProcess(c *gin.Context) {
return
}
// 确保配置缓存已刷新
if err := repoManager.SystemConfigRepository.SafeRefreshConfigCache(); err != nil {
utils.Error("刷新配置缓存失败: %v", err)
// 不返回错误,因为配置已经保存成功
}
// 更新定时任务状态
scheduler := scheduler.GetGlobalScheduler(
repoManager.HotDramaRepository,

View File

@@ -50,7 +50,7 @@ func (h *TaskHandler) CreateBatchTransferTask(c *gin.Context) {
return
}
utils.Info("创建批量转存任务: %s资源数量: %d选择账号数量: %d", req.Title, len(req.Resources), len(req.SelectedAccounts))
utils.Debug("创建批量转存任务: %s资源数量: %d选择账号数量: %d", req.Title, len(req.Resources), len(req.SelectedAccounts))
// 构建任务配置
taskConfig := map[string]interface{}{
@@ -105,7 +105,7 @@ func (h *TaskHandler) CreateBatchTransferTask(c *gin.Context) {
}
}
utils.Info("批量转存任务创建完成: %d, 共 %d 项", newTask.ID, len(req.Resources))
utils.Debug("批量转存任务创建完成: %d, 共 %d 项", newTask.ID, len(req.Resources))
SuccessResponse(c, gin.H{
"task_id": newTask.ID,
@@ -123,8 +123,6 @@ func (h *TaskHandler) StartTask(c *gin.Context) {
return
}
utils.Info("启动任务: %d", taskID)
err = h.taskManager.StartTask(uint(taskID))
if err != nil {
utils.Error("启动任务失败: %v", err)
@@ -132,6 +130,8 @@ func (h *TaskHandler) StartTask(c *gin.Context) {
return
}
utils.Debug("启动任务: %d", taskID)
SuccessResponse(c, gin.H{
"message": "任务启动成功",
})
@@ -146,8 +146,6 @@ func (h *TaskHandler) StopTask(c *gin.Context) {
return
}
utils.Info("停止任务: %d", taskID)
err = h.taskManager.StopTask(uint(taskID))
if err != nil {
utils.Error("停止任务失败: %v", err)
@@ -155,6 +153,8 @@ func (h *TaskHandler) StopTask(c *gin.Context) {
return
}
utils.Debug("停止任务: %d", taskID)
SuccessResponse(c, gin.H{
"message": "任务停止成功",
})
@@ -169,8 +169,6 @@ func (h *TaskHandler) PauseTask(c *gin.Context) {
return
}
utils.Info("暂停任务: %d", taskID)
err = h.taskManager.PauseTask(uint(taskID))
if err != nil {
utils.Error("暂停任务失败: %v", err)
@@ -178,6 +176,8 @@ func (h *TaskHandler) PauseTask(c *gin.Context) {
return
}
utils.Debug("暂停任务: %d", taskID)
SuccessResponse(c, gin.H{
"message": "任务暂停成功",
})
@@ -234,13 +234,25 @@ func (h *TaskHandler) GetTaskStatus(c *gin.Context) {
// GetTasks 获取任务列表
func (h *TaskHandler) GetTasks(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
taskType := c.Query("task_type")
// 获取查询参数
pageStr := c.DefaultQuery("page", "1")
pageSizeStr := c.DefaultQuery("pageSize", "10")
taskType := c.Query("taskType")
status := c.Query("status")
utils.Info("GetTasks: 获取任务列表 page=%d, pageSize=%d, taskType=%s, status=%s", page, pageSize, taskType, status)
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
page = 1
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 || pageSize > 100 {
pageSize = 10
}
utils.Debug("GetTasks: 获取任务列表 page=%d, pageSize=%d, taskType=%s, status=%s", page, pageSize, taskType, status)
// 获取任务列表
tasks, total, err := h.repoMgr.TaskRepository.GetList(page, pageSize, taskType, status)
if err != nil {
utils.Error("获取任务列表失败: %v", err)
@@ -248,19 +260,19 @@ func (h *TaskHandler) GetTasks(c *gin.Context) {
return
}
utils.Info("GetTasks: 从数据库获取到 %d 个任务", len(tasks))
utils.Debug("GetTasks: 从数据库获取到 %d 个任务", len(tasks))
// 为每个任务添加运行状态
var result []gin.H
// 获取任务运行状态
var taskList []gin.H
for _, task := range tasks {
isRunning := h.taskManager.IsTaskRunning(task.ID)
utils.Info("GetTasks: 任务 %d (%s) 数据库状态: %s, TaskManager运行状态: %v", task.ID, task.Title, task.Status, isRunning)
utils.Debug("GetTasks: 任务 %d (%s) 数据库状态: %s, TaskManager运行状态: %v", task.ID, task.Title, task.Status, isRunning)
result = append(result, gin.H{
taskList = append(taskList, gin.H{
"id": task.ID,
"title": task.Title,
"description": task.Description,
"task_type": task.Type,
"type": task.Type,
"status": task.Status,
"total_items": task.TotalItems,
"processed_items": task.ProcessedItems,
@@ -273,10 +285,11 @@ func (h *TaskHandler) GetTasks(c *gin.Context) {
}
SuccessResponse(c, gin.H{
"items": result,
"total": total,
"page": page,
"size": pageSize,
"tasks": taskList,
"total": total,
"page": page,
"page_size": pageSize,
"total_pages": (total + int64(pageSize) - 1) / int64(pageSize),
})
}
@@ -348,7 +361,7 @@ func (h *TaskHandler) DeleteTask(c *gin.Context) {
// 检查任务是否在运行
if h.taskManager.IsTaskRunning(uint(taskID)) {
ErrorResponse(c, "任务正在运行,请先停止任务", http.StatusBadRequest)
ErrorResponse(c, "任务正在运行中,无法删除", http.StatusBadRequest)
return
}
@@ -368,7 +381,8 @@ func (h *TaskHandler) DeleteTask(c *gin.Context) {
return
}
utils.Info("任务删除成功: %d", taskID)
utils.Debug("任务删除成功: %d", taskID)
SuccessResponse(c, gin.H{
"message": "任务删除成功",
})