package telegram import ( "fmt" "html" "strconv" "strings" tele "gopkg.in/telebot.v3" ) const ( cbPrefixDelEntry = "del:" cbPrefixDelWithMsg = "delwithmsg:" cbPrefixDelOnlyToc = "delonlytoc:" ) func (b *Bot) handleEntryDel(c tele.Context) error { id := strings.TrimSpace(c.Message().Payload) if id == "" { return c.Reply("用法: /del ") } entry, err := b.storage.GetEntry(id) if err != nil { return c.Reply(fmt.Sprintf("❌ %v", err)) } menu := &tele.ReplyMarkup{} delWithMsgBtn := menu.Data("🗑 删除条目+频道消息", cbPrefixDelWithMsg+id) delOnlyTocBtn := menu.Data("📝 仅删除目录条目", cbPrefixDelOnlyToc+id) cancelBtn := menu.Data("❌ 取消", cbCancel) menu.Inline( menu.Row(delWithMsgBtn), menu.Row(delOnlyTocBtn), menu.Row(cancelBtn), ) text := fmt.Sprintf("🗑 确认删除?\n\n分类: %s\n标题: %s\n\n请选择删除方式:", entry.Category, entry.Title) return c.Reply(text, menu) } func (b *Bot) handleEntryEdit(c tele.Context) error { args := strings.SplitN(c.Message().Payload, " ", 2) if len(args) < 2 { return c.Reply("用法: /edit <新标题>") } id := args[0] newTitle := strings.TrimSpace(args[1]) if err := b.storage.UpdateEntryTitle(id, newTitle); err != nil { return c.Reply(fmt.Sprintf("❌ %v", err)) } b.toc.TriggerUpdate() return c.Reply(fmt.Sprintf("✅ 标题已更新为: %s", newTitle)) } func (b *Bot) handleEntryMove(c tele.Context) error { args := strings.Fields(c.Message().Payload) if len(args) < 2 { return c.Reply("用法: /move <新分类>") } id := args[0] newCategory := args[1] if !b.storage.CategoryExists(newCategory) { return c.Reply(fmt.Sprintf("❌ 分类 [%s] 不存在", newCategory)) } if err := b.storage.UpdateEntryCategory(id, newCategory); err != nil { return c.Reply(fmt.Sprintf("❌ %v", err)) } b.toc.TriggerUpdate() return c.Reply(fmt.Sprintf("✅ 已移动到分类: %s", newCategory)) } func (b *Bot) handleEntryList(c tele.Context) error { category := strings.TrimSpace(c.Message().Payload) entries, err := b.storage.ListEntries(category) if err != nil { return c.Reply(fmt.Sprintf("❌ %v", err)) } if len(entries) == 0 { if category != "" { return c.Reply(fmt.Sprintf("📭 分类 [%s] 暂无条目", category)) } return c.Reply("📭 暂无条目") } var sb strings.Builder if category != "" { sb.WriteString(fmt.Sprintf("📋 分类 [%s] 的条目:\n\n", html.EscapeString(category))) } else { sb.WriteString("📋 所有条目:\n\n") } currentCat := "" for _, e := range entries { if category == "" && e.Category != currentCat { currentCat = e.Category sb.WriteString(fmt.Sprintf("\n【%s】\n", html.EscapeString(currentCat))) } sb.WriteString(fmt.Sprintf("• %s %s\n", e.ID, html.EscapeString(e.Title))) } return c.Reply(sb.String(), tele.ModeHTML) } func (b *Bot) handleRefresh(c tele.Context) error { b.toc.TriggerUpdate() return c.Reply("🔄 目录刷新已触发") } // handleDeleteEntryCallback 处理删除条目的回调 func (b *Bot) handleDeleteEntryCallback(c tele.Context, entryID string, deleteChannelMsg bool) error { entry, err := b.storage.GetEntry(entryID) if err != nil { c.Edit(fmt.Sprintf("❌ %v", err)) return c.Respond(&tele.CallbackResponse{Text: "条目不存在"}) } // 根据用户选择决定是否删除频道消息 msgDeleted := false if deleteChannelMsg { if msgID := parseMessageIDFromLink(entry.Link); msgID != 0 { channel := &tele.Chat{ID: b.cfg.Channel.ID} msg := &tele.Message{ID: msgID, Chat: channel} if err := b.bot.Delete(msg); err == nil { msgDeleted = true } } } if err := b.storage.DeleteEntry(entryID); err != nil { c.Edit(fmt.Sprintf("❌ 删除失败: %v", err)) return c.Respond(&tele.CallbackResponse{Text: "删除失败"}) } b.toc.TriggerUpdate() var text string if deleteChannelMsg && msgDeleted { text = fmt.Sprintf("✅ 已删除: [%s] %s\n📨 频道消息已同步删除", entry.Category, entry.Title) } else if deleteChannelMsg && !msgDeleted { text = fmt.Sprintf("✅ 已删除: [%s] %s\n⚠️ 频道消息删除失败(可能已被删除)", entry.Category, entry.Title) } else { text = fmt.Sprintf("✅ 已删除: [%s] %s\n📝 频道消息已保留", entry.Category, entry.Title) } c.Edit(text) return c.Respond(&tele.CallbackResponse{Text: "删除成功"}) } // parseMessageIDFromLink 从链接中解析消息ID // 支持格式: https://t.me/c/123456/789 或 https://t.me/username/789 func parseMessageIDFromLink(link string) int { parts := strings.Split(link, "/") if len(parts) < 1 { return 0 } msgID, err := strconv.Atoi(parts[len(parts)-1]) if err != nil { return 0 } return msgID }