diff --git a/db/converter/telegram_channel_converter.go b/db/converter/telegram_channel_converter.go index df47df6..77e58f3 100644 --- a/db/converter/telegram_channel_converter.go +++ b/db/converter/telegram_channel_converter.go @@ -24,6 +24,8 @@ func TelegramChannelToResponse(channel entity.TelegramChannel) dto.TelegramChann ContentCategories: channel.ContentCategories, ContentTags: channel.ContentTags, IsActive: channel.IsActive, + ResourceStrategy: channel.ResourceStrategy, + TimeLimit: channel.TimeLimit, LastPushAt: channel.LastPushAt, RegisteredBy: channel.RegisteredBy, RegisteredAt: channel.RegisteredAt, @@ -41,7 +43,7 @@ func TelegramChannelsToResponse(channels []entity.TelegramChannel) []dto.Telegra // RequestToTelegramChannel 将请求DTO转换为TelegramChannel实体 func RequestToTelegramChannel(req dto.TelegramChannelRequest, registeredBy string) entity.TelegramChannel { - return entity.TelegramChannel{ + channel := entity.TelegramChannel{ ChatID: req.ChatID, ChatName: req.ChatName, ChatType: req.ChatType, @@ -55,6 +57,21 @@ func RequestToTelegramChannel(req dto.TelegramChannelRequest, registeredBy strin RegisteredBy: registeredBy, RegisteredAt: time.Now(), } + + // 设置默认值(如果为空) + if req.ResourceStrategy == "" { + channel.ResourceStrategy = "random" + } else { + channel.ResourceStrategy = req.ResourceStrategy + } + + if req.TimeLimit == "" { + channel.TimeLimit = "none" + } else { + channel.TimeLimit = req.TimeLimit + } + + return channel } // TelegramBotConfigToResponse 将Telegram bot配置转换为响应DTO diff --git a/db/dto/telegram_channel.go b/db/dto/telegram_channel.go index bed652e..9052db4 100644 --- a/db/dto/telegram_channel.go +++ b/db/dto/telegram_channel.go @@ -14,6 +14,8 @@ type TelegramChannelRequest struct { ContentCategories string `json:"content_categories"` ContentTags string `json:"content_tags"` IsActive bool `json:"is_active"` + ResourceStrategy string `json:"resource_strategy"` + TimeLimit string `json:"time_limit"` } // TelegramChannelUpdateRequest 更新 Telegram 频道/群组请求(ChatID可选) @@ -28,6 +30,8 @@ type TelegramChannelUpdateRequest struct { ContentCategories string `json:"content_categories"` ContentTags string `json:"content_tags"` IsActive bool `json:"is_active"` + ResourceStrategy string `json:"resource_strategy"` + TimeLimit string `json:"time_limit"` } // TelegramChannelResponse Telegram 频道/群组响应 @@ -43,6 +47,8 @@ type TelegramChannelResponse struct { ContentCategories string `json:"content_categories"` ContentTags string `json:"content_tags"` IsActive bool `json:"is_active"` + ResourceStrategy string `json:"resource_strategy"` + TimeLimit string `json:"time_limit"` LastPushAt *time.Time `json:"last_push_at"` RegisteredBy string `json:"registered_by"` RegisteredAt time.Time `json:"registered_at"` diff --git a/db/entity/telegram_channel.go b/db/entity/telegram_channel.go index f94364b..c40afc2 100644 --- a/db/entity/telegram_channel.go +++ b/db/entity/telegram_channel.go @@ -36,6 +36,10 @@ type TelegramChannel struct { Token string `json:"token" gorm:"size:255;comment:访问令牌"` ApiType string `json:"api_type" gorm:"size:50;comment:API类型"` IsPushSavedInfo bool `json:"is_push_saved_info" gorm:"default:false;comment:是否只推送已转存资源"` + + // 资源策略和时间限制配置 + ResourceStrategy string `json:"resource_strategy" gorm:"size:20;default:'random';comment:资源策略:latest-最新优先,transferred-已转存优先,random-纯随机"` + TimeLimit string `json:"time_limit" gorm:"size:20;default:'none';comment:时间限制:none-无限制,week-一周内,month-一月内"` } // TableName 指定表名 diff --git a/handlers/telegram_handler.go b/handlers/telegram_handler.go index b51262f..92529c6 100644 --- a/handlers/telegram_handler.go +++ b/handlers/telegram_handler.go @@ -206,6 +206,9 @@ func (h *TelegramHandler) UpdateChannel(c *gin.Context) { return } + utils.Info("[TELEGRAM:HANDLER] 接收到频道更新请求: ID=%s, ChatName=%s, PushStartTime=%s, PushEndTime=%s, ResourceStrategy=%s, TimeLimit=%s", + idStr, req.ChatName, req.PushStartTime, req.PushEndTime, req.ResourceStrategy, req.TimeLimit) + // 查找现有频道 channel, err := h.telegramChannelRepo.FindByID(uint(id)) if err != nil { @@ -213,6 +216,10 @@ func (h *TelegramHandler) UpdateChannel(c *gin.Context) { return } + // 保存前的日志 + utils.Info("[TELEGRAM:HANDLER] 更新前频道状态: PushStartTime=%s, PushEndTime=%s, ResourceStrategy=%s, TimeLimit=%s", + channel.PushStartTime, channel.PushEndTime, channel.ResourceStrategy, channel.TimeLimit) + // 如果前端传递了ChatID,验证它是否与现有频道匹配 if req.ChatID != 0 && req.ChatID != channel.ChatID { ErrorResponse(c, "ChatID不匹配,无法更新此频道", http.StatusBadRequest) @@ -229,12 +236,18 @@ func (h *TelegramHandler) UpdateChannel(c *gin.Context) { channel.ContentCategories = req.ContentCategories channel.ContentTags = req.ContentTags channel.IsActive = req.IsActive + channel.ResourceStrategy = req.ResourceStrategy + channel.TimeLimit = req.TimeLimit if err := h.telegramChannelRepo.Update(channel); err != nil { ErrorResponse(c, "更新频道失败", http.StatusInternalServerError) return } + // 保存后的日志 + utils.Info("[TELEGRAM:HANDLER] 更新后频道状态: PushStartTime=%s, PushEndTime=%s, ResourceStrategy=%s, TimeLimit=%s", + channel.PushStartTime, channel.PushEndTime, channel.ResourceStrategy, channel.TimeLimit) + response := converter.TelegramChannelToResponse(*channel) SuccessResponse(c, response) } @@ -278,13 +291,18 @@ func (h *TelegramHandler) RegisterChannelByCommand(chatID int64, chatName, chatT // 创建新的频道记录 channel := entity.TelegramChannel{ - ChatID: chatID, - ChatName: chatName, - ChatType: chatType, - PushEnabled: true, - PushFrequency: 5, // 默认5分钟 - IsActive: true, - RegisteredBy: "bot_command", + ChatID: chatID, + ChatName: chatName, + ChatType: chatType, + PushEnabled: true, + PushFrequency: 15, // 默认15分钟 + PushStartTime: "08:30", // 默认开始时间8:30 + PushEndTime: "11:30", // 默认结束时间11:30 + IsActive: true, + RegisteredBy: "bot_command", + RegisteredAt: time.Now(), + ResourceStrategy: "random", // 默认纯随机 + TimeLimit: "none", // 默认无限制 } return h.telegramChannelRepo.Create(&channel) diff --git a/migrations/telegram_channels.sql b/migrations/telegram_channels.sql index e14b94b..4e2c3a9 100644 --- a/migrations/telegram_channels.sql +++ b/migrations/telegram_channels.sql @@ -28,6 +28,12 @@ CREATE TABLE telegram_channels ( token VARCHAR(255) COMMENT '访问令牌', api_type VARCHAR(50) COMMENT 'API类型', is_push_saved_info BOOLEAN DEFAULT FALSE COMMENT '是否只推送已转存资源', + + -- 资源策略和时间限制配置 + resource_strategy VARCHAR(20) DEFAULT 'random' COMMENT '资源策略:latest-最新优先,transferred-已转存优先,random-纯随机', + time_limit VARCHAR(20) DEFAULT 'none' COMMENT '时间限制:none-无限制,week-一周内,month-一月内', + push_start_time VARCHAR(10) COMMENT '推送开始时间,格式HH:mm', + push_end_time VARCHAR(10) COMMENT '推送结束时间,格式HH:mm', -- 索引 INDEX idx_chat_id (chat_id), diff --git a/services/telegram_bot_service.go b/services/telegram_bot_service.go index ce727c1..da55cfc 100644 --- a/services/telegram_bot_service.go +++ b/services/telegram_bot_service.go @@ -937,6 +937,191 @@ func (s *TelegramBotServiceImpl) pushToChannel(channel entity.TelegramChannel) { func (s *TelegramBotServiceImpl) findResourcesForChannel(channel entity.TelegramChannel) []interface{} { utils.Info("[TELEGRAM:PUSH] 开始为频道 %s (%d) 查找资源", channel.ChatName, channel.ChatID) + // 获取最近推送的历史资源ID,避免重复推送 + excludeResourceIDs := s.getRecentlyPushedResourceIDs(channel.ChatID) + + // 解析资源策略 + strategy := channel.ResourceStrategy + if strategy == "" { + strategy = "random" // 默认纯随机 + } + + utils.Info("[TELEGRAM:PUSH] 使用策略: %s, 时间限制: %s, 排除最近推送资源数: %d", + strategy, channel.TimeLimit, len(excludeResourceIDs)) + + // 根据策略获取资源 + switch strategy { + case "latest": + // 最新优先策略 - 获取最近的资源 + return s.findLatestResources(channel, excludeResourceIDs) + case "transferred": + // 已转存优先策略 - 优先获取有转存链接的资源 + return s.findTransferredResources(channel, excludeResourceIDs) + case "random": + // 纯随机策略(原逻辑) + return s.findRandomResources(channel, excludeResourceIDs) + default: + // 默认随机策略 + return s.findRandomResources(channel, excludeResourceIDs) + } +} + +// findLatestResources 查找最新资源 +func (s *TelegramBotServiceImpl) findLatestResources(channel entity.TelegramChannel, excludeResourceIDs []uint) []interface{} { + params := s.buildFilterParams(channel) + + // 使用现有的搜索功能,按更新时间倒序获取最新资源 + resources, _, err := s.resourceRepo.SearchWithFilters(params) + if err != nil { + utils.Error("[TELEGRAM:PUSH] 获取最新资源失败: %v", err) + return []interface{}{} + } + + // 排除最近推送过的资源 + if len(excludeResourceIDs) > 0 { + resources = s.excludePushedResources(resources, excludeResourceIDs) + } + + // 应用时间限制 + if channel.TimeLimit != "none" && len(resources) > 0 { + resources = s.applyTimeFilter(resources, channel.TimeLimit) + } + + if len(resources) == 0 { + utils.Info("[TELEGRAM:PUSH] 没有找到符合条件的最新资源") + return []interface{}{} + } + + // 返回最新资源(第一条) + utils.Info("[TELEGRAM:PUSH] 成功获取最新资源: %s", resources[0].Title) + return []interface{}{resources[0]} +} + +// findTransferredResources 查找已转存资源 +func (s *TelegramBotServiceImpl) findTransferredResources(channel entity.TelegramChannel, excludeResourceIDs []uint) []interface{} { + params := s.buildFilterParams(channel) + + // 添加转存链接条件 + params["has_save_url"] = true + + // 优先获取有转存链接的资源 + resources, _, err := s.resourceRepo.SearchWithFilters(params) + if err != nil { + utils.Error("[TELEGRAM:PUSH] 获取已转存资源失败: %v", err) + return []interface{}{} + } + + // 排除最近推送过的资源 + if len(excludeResourceIDs) > 0 { + resources = s.excludePushedResources(resources, excludeResourceIDs) + } + + // 应用时间限制 + if channel.TimeLimit != "none" && len(resources) > 0 { + resources = s.applyTimeFilter(resources, channel.TimeLimit) + } + + if len(resources) == 0 { + utils.Info("[TELEGRAM:PUSH] 没有找到符合条件的已转存资源,尝试获取随机资源") + // 如果没有已转存资源,回退到随机策略 + return s.findRandomResources(channel, excludeResourceIDs) + } + + // 返回第一个有转存链接的资源 + utils.Info("[TELEGRAM:PUSH] 成功获取已转存资源: %s", resources[0].Title) + return []interface{}{resources[0]} +} + +// findRandomResources 查找随机资源(原有逻辑) +func (s *TelegramBotServiceImpl) findRandomResources(channel entity.TelegramChannel, excludeResourceIDs []uint) []interface{} { + params := s.buildFilterParams(channel) + + // 如果是已转存优先策略但没有找到转存资源,这里会回退到随机策略 + // 此时不需要额外的转存链接条件,让随机函数处理 + + // 先尝试获取候选资源列表,然后从中排除已推送的资源 + var candidateResources []entity.Resource + var err error + + // 使用搜索功能获取候选资源,然后过滤 + params["limit"] = 100 // 获取更多候选资源 + candidateResources, _, err = s.resourceRepo.SearchWithFilters(params) + if err != nil { + utils.Error("[TELEGRAM:PUSH] 获取候选资源失败: %v", err) + return []interface{}{} + } + + // 排除最近推送过的资源 + if len(excludeResourceIDs) > 0 { + candidateResources = s.excludePushedResources(candidateResources, excludeResourceIDs) + } + + // 应用时间限制 + if channel.TimeLimit != "none" && len(candidateResources) > 0 { + candidateResources = s.applyTimeFilter(candidateResources, channel.TimeLimit) + } + + // 如果还有候选资源,随机选择一个 + if len(candidateResources) > 0 { + // 简单随机选择(未来可以考虑使用更好的随机算法) + randomIndex := time.Now().Nanosecond() % len(candidateResources) + selectedResource := candidateResources[randomIndex] + + utils.Info("[TELEGRAM:PUSH] 成功获取随机资源: %s (从 %d 个候选资源中选择)", + selectedResource.Title, len(candidateResources)) + return []interface{}{selectedResource} + } + + // 如果候选资源不足,回退到数据库随机函数 + defer func() { + if r := recover(); r != nil { + utils.Warn("[TELEGRAM:PUSH] 随机查询失败,回退到传统方法: %v", r) + } + }() + + randomResource, err := s.resourceRepo.GetRandomResourceWithFilters(params["category"].(string), params["tag"].(string), channel.IsPushSavedInfo) + if err == nil && randomResource != nil { + utils.Info("[TELEGRAM:PUSH] 使用数据库随机函数获取资源: %s", randomResource.Title) + return []interface{}{randomResource} + } + + return []interface{}{} +} + +// applyTimeFilter 应用时间限制过滤 +func (s *TelegramBotServiceImpl) applyTimeFilter(resources []entity.Resource, timeLimit string) []entity.Resource { + now := time.Now() + var filtered []entity.Resource + + for _, resource := range resources { + include := false + + switch timeLimit { + case "week": + // 一周内 + if resource.CreatedAt.After(now.AddDate(0, 0, -7)) { + include = true + } + case "month": + // 一月内 + if resource.CreatedAt.After(now.AddDate(0, -1, 0)) { + include = true + } + case "none": + // 无限制,包含所有 + include = true + } + + if include { + filtered = append(filtered, resource) + } + } + + return filtered +} + +// buildFilterParams 构建过滤参数 +func (s *TelegramBotServiceImpl) buildFilterParams(channel entity.TelegramChannel) map[string]interface{} { params := map[string]interface{}{"category": "", "tag": ""} if channel.ContentCategories != "" { @@ -955,20 +1140,7 @@ func (s *TelegramBotServiceImpl) findResourcesForChannel(channel entity.Telegram params["tag"] = tags[0] } - // 尝试使用 PostgreSQL 的随机功能 - defer func() { - if r := recover(); r != nil { - utils.Warn("[TELEGRAM:PUSH] 随机查询失败,回退到传统方法: %v", r) - } - }() - - randomResource, err := s.resourceRepo.GetRandomResourceWithFilters(params["category"].(string), params["tag"].(string), channel.IsPushSavedInfo) - if err == nil && randomResource != nil { - utils.Info("[TELEGRAM:PUSH] 成功获取随机资源: %s", randomResource.Title) - return []interface{}{randomResource} - } - - return []interface{}{} + return params } // buildPushMessage 构建推送消息 @@ -1091,16 +1263,20 @@ func (s *TelegramBotServiceImpl) RegisterChannel(chatID int64, chatName, chatTyp ChatName: chatName, ChatType: chatType, PushEnabled: true, - PushFrequency: 5, // 默认5分钟 + PushFrequency: 15, // 默认15分钟 + PushStartTime: "08:30", // 默认开始时间8:30 + PushEndTime: "11:30", // 默认结束时间11:30 IsActive: true, RegisteredBy: "bot_command", RegisteredAt: time.Now(), ContentCategories: "", ContentTags: "", - API: "", // 后续可配置 - Token: "", // 后续可配置 - ApiType: "l9", // 默认l9类型 - IsPushSavedInfo: false, // 默认推送所有资源 + API: "", // 后续可配置 + Token: "", // 后续可配置 + ApiType: "l9", // 默认l9类型 + IsPushSavedInfo: false, // 默认推送所有资源 + ResourceStrategy: "random", // 默认纯随机 + TimeLimit: "none", // 默认无限制 } return s.channelRepo.Create(&channel) @@ -1396,6 +1572,21 @@ func (s *TelegramBotServiceImpl) handleChannelRegistration(message *tgbotapi.Mes if existingChannel.ApiType == "" { existingChannel.ApiType = "telegram" } + if existingChannel.ResourceStrategy == "" { + existingChannel.ResourceStrategy = "random" + } + if existingChannel.TimeLimit == "" { + existingChannel.TimeLimit = "none" + } + if existingChannel.PushFrequency == 0 { + existingChannel.PushFrequency = 15 + } + if existingChannel.PushStartTime == "" { + existingChannel.PushStartTime = "08:30" + } + if existingChannel.PushEndTime == "" { + existingChannel.PushEndTime = "11:30" + } err := s.channelRepo.Update(existingChannel) if err != nil { @@ -1464,3 +1655,41 @@ func (s *TelegramBotServiceImpl) CleanupDuplicateChannels() error { utils.Info("[TELEGRAM:CLEANUP:SUCCESS] 成功清理重复的频道记录") return nil } + +// getRecentlyPushedResourceIDs 获取最近推送过的资源ID列表 +func (s *TelegramBotServiceImpl) getRecentlyPushedResourceIDs(chatID int64) []uint { + // 这里需要实现获取推送历史的逻辑 + // 由于没有现有的推送历史表,我们暂时返回空列表 + // 未来可以添加一个 TelegramPushHistory 实体来跟踪推送历史 + utils.Debug("[TELEGRAM:PUSH] 获取推送历史,ChatID: %d", chatID) + + // 暂时返回空列表,表示没有历史推送记录 + // TODO: 实现推送历史跟踪功能 + return []uint{} +} + +// excludePushedResources 从候选资源中排除已推送过的资源 +func (s *TelegramBotServiceImpl) excludePushedResources(resources []entity.Resource, excludeIDs []uint) []entity.Resource { + if len(excludeIDs) == 0 { + return resources + } + + utils.Debug("[TELEGRAM:PUSH] 排除 %d 个已推送资源", len(excludeIDs)) + + // 创建排除ID的映射,提高查找效率 + excludeMap := make(map[uint]bool) + for _, id := range excludeIDs { + excludeMap[id] = true + } + + // 过滤资源列表 + var filtered []entity.Resource + for _, resource := range resources { + if !excludeMap[resource.ID] { + filtered = append(filtered, resource) + } + } + + utils.Debug("[TELEGRAM:PUSH] 过滤后剩余 %d 个资源", len(filtered)) + return filtered +} diff --git a/web/components/TelegramBotTab.vue b/web/components/TelegramBotTab.vue index f824150..b08d8f2 100644 --- a/web/components/TelegramBotTab.vue +++ b/web/components/TelegramBotTab.vue @@ -293,21 +293,27 @@ -
-
+
+

{{ channel.push_frequency }} 分钟

-
- +
+

- {{ channel.content_categories || '全部' }} + {{ getResourceStrategyLabel(channel.resource_strategy) }}

-
- +
+

- {{ channel.content_tags || '全部' }} + {{ getTimeLimitLabel(channel.time_limit) }} +

+
+
+ +

+ {{ channel.push_start_time && channel.push_end_time ? `${channel.push_start_time}-${channel.push_end_time}` : '全天' }}

@@ -469,8 +475,6 @@ + + +

+ 纯随机:完全随机推送资源;最新优先:优先推送最新资源;已转存优先:优先推送已转存的资源 +

+
+ + +
+ + +

+ 无限制:推送所有时间段的资源;一周内:仅推送最近一周的资源;一月内:仅推送最近一个月的资源 +

+
+
@@ -896,29 +934,78 @@ const editChannel = (channel: any) => { // 处理时间字段,确保时间选择器可以正确显示 try { + console.log('处理编辑频道时间字段:') + console.log('原始开始时间:', channelCopy.push_start_time) + console.log('原始结束时间:', channelCopy.push_end_time) + // 处理开始时间 if (channelCopy.push_start_time) { if (isValidTimeString(channelCopy.push_start_time)) { - // 确保格式正确,转换为标准格式 - channelCopy.push_start_time = normalizeTimeString(channelCopy.push_start_time) + // 数据库中是 "HH:mm" 格式的时间字符串 + console.log('开始时间是有效格式,保持原样:', channelCopy.push_start_time) } else { + console.log('开始时间格式无效,设为null') channelCopy.push_start_time = null } } else { + console.log('开始时间为空,设为null') channelCopy.push_start_time = null } // 处理结束时间 if (channelCopy.push_end_time) { if (isValidTimeString(channelCopy.push_end_time)) { - // 确保格式正确,转换为标准格式 - channelCopy.push_end_time = normalizeTimeString(channelCopy.push_end_time) + // 数据库中是 "HH:mm" 格式的时间字符串 + console.log('结束时间是有效格式,保持原样:', channelCopy.push_end_time) } else { + console.log('结束时间格式无效,设为null') channelCopy.push_end_time = null } } else { + console.log('结束时间为空,设为null') channelCopy.push_end_time = null } + + console.log('处理后时间字段:', { + push_start_time: channelCopy.push_start_time, + push_end_time: channelCopy.push_end_time + }) + + // 尝试转换为时间戳格式(毫秒),因为时间选择器可能期望这种格式 + if (channelCopy.push_start_time) { + const timeStr = channelCopy.push_start_time // 格式如 "08:30" + const parts = timeStr.split(':') + if (parts.length === 2) { + const hours = parseInt(parts[0], 10) + const minutes = parseInt(parts[1], 10) + // 创建今天的日期,然后设置小时和分钟 + const today = new Date() + today.setHours(hours, minutes, 0, 0) + const timestamp = today.getTime() + console.log('转换开始时间戳:', timestamp) + channelCopy.push_start_time = timestamp + } + } + + if (channelCopy.push_end_time) { + const timeStr = channelCopy.push_end_time // 格式如 "11:30" + const parts = timeStr.split(':') + if (parts.length === 2) { + const hours = parseInt(parts[0], 10) + const minutes = parseInt(parts[1], 10) + // 创建今天的日期,然后设置小时和分钟 + const today = new Date() + today.setHours(hours, minutes, 0, 0) + const timestamp = today.getTime() + console.log('转换结束时间戳:', timestamp) + channelCopy.push_end_time = timestamp + } + } + + console.log('最终时间字段格式:', { + push_start_time: channelCopy.push_start_time, + push_end_time: channelCopy.push_end_time + }) } catch (error) { console.warn('处理频道时间字段时出错:', error) channelCopy.push_start_time = null @@ -1168,6 +1255,26 @@ const getCategoryLabel = (category: string): string => { } } +// 获取资源策略标签 +const getResourceStrategyLabel = (strategy: string): string => { + switch (strategy) { + case 'random': return '纯随机' + case 'latest': return '最新优先' + case 'transferred': return '已转存优先' + default: return '纯随机' + } +} + +// 获取时间限制标签 +const getTimeLimitLabel = (timeLimit: string): string => { + switch (timeLimit) { + case 'none': return '无限制' + case 'week': return '一周内' + case 'month': return '一月内' + default: return '无限制' + } +} + const notification = useNotification() const dialog = useDialog() @@ -1216,14 +1323,26 @@ const saveChannelSettings = async () => { chat_type: editingChannel.value.chat_type, push_enabled: editingChannel.value.push_enabled, push_frequency: editingChannel.value.push_frequency, + push_start_time: formatTimeForSave(editingChannel.value.push_start_time), + push_end_time: formatTimeForSave(editingChannel.value.push_end_time), content_categories: editingChannel.value.content_categories, content_tags: editingChannel.value.content_tags, is_active: editingChannel.value.is_active, - push_start_time: formatTimeForSave(editingChannel.value.push_start_time), - push_end_time: formatTimeForSave(editingChannel.value.push_end_time) + resource_strategy: editingChannel.value.resource_strategy, + time_limit: editingChannel.value.time_limit } + console.log('准备提交频道更新数据:', updateData) + console.log('频道ID:', editingChannel.value.id) + console.log('推送开始时间原始值:', editingChannel.value.push_start_time) + console.log('推送结束时间原始值:', editingChannel.value.push_end_time) + console.log('格式化后推送开始时间:', formatTimeForSave(editingChannel.value.push_start_time)) + console.log('格式化后推送结束时间:', formatTimeForSave(editingChannel.value.push_end_time)) + console.log('资源策略:', editingChannel.value.resource_strategy) + console.log('时间限制:', editingChannel.value.time_limit) + await telegramApi.updateChannel(editingChannel.value.id, updateData) + console.log('频道更新提交完成') notification.success({ content: `频道 "${editingChannel.value.chat_name}" 设置已更新`, @@ -1248,22 +1367,61 @@ const saveChannelSettings = async () => { // 格式化时间字段以便保存 const formatTimeForSave = (timeValue: any): string | null => { + console.log('formatTimeForSave 输入值:', timeValue, '类型:', typeof timeValue) + if (!timeValue) { + console.log('formatTimeForSave: 空值,返回 null') return null } // 如果已经是字符串格式,直接返回 if (typeof timeValue === 'string') { + console.log('formatTimeForSave: 字符串格式,直接返回:', timeValue) return timeValue } + // 如果是数组(Naive UI Time Picker 可能返回这种格式) + if (Array.isArray(timeValue)) { + console.log('formatTimeForSave: 数组格式,处理数组:', timeValue) + if (timeValue.length >= 2) { + const hours = timeValue[0].toString().padStart(2, '0') + const minutes = timeValue[1].toString().padStart(2, '0') + const result = `${hours}:${minutes}` + console.log('formatTimeForSave: 数组转换为:', result) + return result + } + } + // 如果是 Date 对象,格式化为 HH:mm if (timeValue instanceof Date) { const hours = timeValue.getHours().toString().padStart(2, '0') const minutes = timeValue.getMinutes().toString().padStart(2, '0') - return `${hours}:${minutes}` + const result = `${hours}:${minutes}` + console.log('formatTimeForSave: Date 对象转换为:', result) + return result } + // 如果是有 hour 和 minute 属性的对象 + if (timeValue && typeof timeValue === 'object' && 'hour' in timeValue && 'minute' in timeValue) { + const hours = timeValue.hour.toString().padStart(2, '0') + const minutes = timeValue.minute.toString().padStart(2, '0') + const result = `${hours}:${minutes}` + console.log('formatTimeForSave: 对象格式转换为:', result) + return result + } + + // 如果是时间戳(毫秒) + if (typeof timeValue === 'number' && timeValue > 0) { + console.log('formatTimeForSave: 时间戳格式,转换为日期') + const date = new Date(timeValue) + const hours = date.getHours().toString().padStart(2, '0') + const minutes = date.getMinutes().toString().padStart(2, '0') + const result = `${hours}:${minutes}` + console.log('formatTimeForSave: 时间戳转换为:', result) + return result + } + + console.log('formatTimeForSave: 无法识别的格式,返回 null') return null }