mirror of
https://github.com/ctwj/urldb.git
synced 2025-11-25 03:15:04 +08:00
update: tgbot 优化
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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 指定表名
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user