update: tgbot 优化

This commit is contained in:
Kerwin
2025-10-10 19:17:03 +08:00
parent 4da07b3ea4
commit 516746f722
7 changed files with 482 additions and 44 deletions

View File

@@ -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

View File

@@ -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"`

View File

@@ -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 指定表名

View File

@@ -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)
}
@@ -282,9 +295,14 @@ func (h *TelegramHandler) RegisterChannelByCommand(chatID int64, chatName, chatT
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(),
ResourceStrategy: "random", // 默认纯随机
TimeLimit: "none", // 默认无限制
}
return h.telegramChannelRepo.Create(&channel)

View File

@@ -29,6 +29,12 @@ CREATE TABLE telegram_channels (
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),
INDEX idx_chat_type (chat_type),

View File

@@ -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,7 +1263,9 @@ 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(),
@@ -1101,6 +1275,8 @@ func (s *TelegramBotServiceImpl) RegisterChannel(chatID int64, chatName, chatTyp
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
}

View File

@@ -293,21 +293,27 @@
</div>
<!-- 推送配置 -->
<div v-if="channel.push_enabled" class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
<div>
<div v-if="channel.push_enabled" class="flex flex-wrap gap-6 mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
<div class="flex-1 min-w-0">
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">推送频率</label>
<p class="text-sm text-gray-600 dark:text-gray-400">{{ channel.push_frequency }} 分钟</p>
</div>
<div>
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">内容分类</label>
<div class="flex-1 min-w-0">
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">资源策略</label>
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ channel.content_categories || '全部' }}
{{ getResourceStrategyLabel(channel.resource_strategy) }}
</p>
</div>
<div>
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">标签</label>
<div class="flex-1 min-w-0">
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">时间限制</label>
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ channel.content_tags || '全部' }}
{{ getTimeLimitLabel(channel.time_limit) }}
</p>
</div>
<div class="flex-1 min-w-0">
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">推送时间段</label>
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ channel.push_start_time && channel.push_end_time ? `${channel.push_start_time}-${channel.push_end_time}` : '全天' }}
</p>
</div>
</div>
@@ -469,8 +475,6 @@
<n-select
v-model:value="editingChannel.push_frequency"
:options="[
{ label: '每5分钟', value: 5 },
{ label: '每10分钟', value: 10 },
{ label: '每15分钟', value: 15 },
{ label: '每30分钟', value: 30 },
{ label: '每45分钟', value: 45 },
@@ -487,6 +491,40 @@
/>
</div>
<!-- 资源策略 -->
<div v-if="editingChannel.push_enabled">
<label class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 block">资源策略</label>
<n-select
v-model:value="editingChannel.resource_strategy"
:options="[
{ label: '纯随机', value: 'random' },
{ label: '最新优先', value: 'latest' },
{ label: '已转存优先', value: 'transferred' }
]"
placeholder="选择资源策略"
/>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
纯随机完全随机推送资源最新优先优先推送最新资源已转存优先优先推送已转存的资源
</p>
</div>
<!-- 时间限制 -->
<div v-if="editingChannel.push_enabled">
<label class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 block">时间限制</label>
<n-select
v-model:value="editingChannel.time_limit"
:options="[
{ label: '无限制', value: 'none' },
{ label: '一周内', value: 'week' },
{ label: '一月内', value: 'month' }
]"
placeholder="选择时间限制"
/>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
无限制推送所有时间段的资源一周内仅推送最近一周的资源一月内仅推送最近一个月的资源
</p>
</div>
<!-- 推送时间段 -->
<div v-if="editingChannel.push_enabled">
<label class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 block">推送时间段</label>
@@ -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
}