2025-04-02 14:29:44 +08:00

232 lines
6.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"context"
"encoding/json"
"strconv"
"time"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
"gitee.ltd/lxh/wechat-robot/internal/docker"
"gitee.ltd/lxh/wechat-robot/internal/model"
)
// ListContacts 列出机器人的联系人
func ListContacts(c *fiber.Ctx) error {
robotID, err := strconv.Atoi(c.Params("id"))
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "无效的机器人ID")
}
var robot model.Robot
db := model.GetDB()
if err := db.First(&robot, robotID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return fiber.NewError(fiber.StatusNotFound, "机器人不存在")
}
return fiber.NewError(fiber.StatusInternalServerError, "查询数据库失败")
}
// 获取联系人列表
var contacts []model.Contact
if err := db.Where("robot_id = ?", robotID).Find(&contacts).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "获取联系人列表失败")
}
// 如果机器人在线并且没有联系人,则从机器人获取最新联系人
if robot.Status == model.RobotStatusOnline && len(contacts) == 0 {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// 调用Docker API获取联系人传递容器访问地址
contactsData, err := docker.GetWechatContacts(ctx, robot.ContainerID, robot.ContainerHost)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "从机器人获取联系人失败: "+err.Error())
}
// 解析联系人数据
var response docker.APIResponse
if err := json.Unmarshal([]byte(contactsData), &response); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "解析联系人数据失败: "+err.Error())
}
// 保存联系人到数据库
if response.Success {
contactList, ok := response.Data.([]interface{})
if ok {
for _, c := range contactList {
contactMap, ok := c.(map[string]interface{})
if !ok {
continue
}
contact := model.Contact{
RobotID: uint(robotID),
WechatID: contactMap["id"].(string),
Nickname: contactMap["name"].(string),
Avatar: contactMap["avatar"].(string),
Type: model.ContactTypeFriend,
}
if contactMap["type"].(string) == "group" {
contact.Type = model.ContactTypeGroup
}
db.Create(&contact)
contacts = append(contacts, contact)
}
}
}
}
return c.Render("contact/index", fiber.Map{
"Title": "联系人列表",
"Robot": robot,
"Contacts": contacts,
})
}
// ShowContact 显示联系人详情与聊天记录
func ShowContact(c *fiber.Ctx) error {
robotID, err := strconv.Atoi(c.Params("id"))
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "无效的机器人ID")
}
contactID, err := strconv.Atoi(c.Params("contactId"))
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "无效的联系人ID")
}
db := model.GetDB()
// 获取机器人信息
var robot model.Robot
if err := db.First(&robot, robotID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return fiber.NewError(fiber.StatusNotFound, "机器人不存在")
}
return fiber.NewError(fiber.StatusInternalServerError, "查询机器人失败")
}
// 获取联系人信息
var contact model.Contact
if err := db.First(&contact, contactID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return fiber.NewError(fiber.StatusNotFound, "联系人不存在")
}
return fiber.NewError(fiber.StatusInternalServerError, "查询联系人失败")
}
// 获取聊天记录
var messages []model.Message
if err := db.Where("robot_id = ? AND contact_id = ?", robotID, contactID).
Order("send_time DESC").Limit(50).Find(&messages).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "获取聊天记录失败")
}
return c.Render("contact/show", fiber.Map{
"Title": contact.Nickname,
"Robot": robot,
"Contact": contact,
"Messages": messages,
})
}
// ListGroupMembers 列出群成员
func ListGroupMembers(c *fiber.Ctx) error {
robotID, err := strconv.Atoi(c.Params("id"))
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "无效的机器人ID")
}
contactID, err := strconv.Atoi(c.Params("contactId"))
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "无效的联系人ID")
}
db := model.GetDB()
// 获取机器人信息
var robot model.Robot
if err := db.First(&robot, robotID).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "查询机器人失败")
}
// 获取联系人信息(群)
var contact model.Contact
if err := db.First(&contact, contactID).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "查询群信息失败")
}
// 确保联系人是群组
if contact.Type != model.ContactTypeGroup {
return fiber.NewError(fiber.StatusBadRequest, "指定的联系人不是群组")
}
// 获取群成员
var members []model.GroupMember
if err := db.Where("group_id = ?", contactID).Find(&members).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "获取群成员失败")
}
// 如果机器人在线并且没有群成员,则从机器人获取
if robot.Status == model.RobotStatusOnline && len(members) == 0 {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// 调用Docker API获取群成员传递容器访问地址
membersData, err := docker.GetWechatGroupMembers(ctx, robot.ContainerID, contact.WechatID, robot.ContainerHost)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "从机器人获取群成员失败: "+err.Error())
}
// 解析群成员数据
var response docker.APIResponse
if err := json.Unmarshal([]byte(membersData), &response); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "解析群成员数据失败: "+err.Error())
}
// 保存群成员到数据库
if response.Success {
memberList, ok := response.Data.([]interface{})
if ok {
for _, m := range memberList {
memberMap, ok := m.(map[string]interface{})
if !ok {
continue
}
role := model.MemberRoleMember
if memberMap["role"].(string) == "owner" {
role = model.MemberRoleOwner
} else if memberMap["role"].(string) == "admin" {
role = model.MemberRoleAdmin
}
member := model.GroupMember{
GroupID: contact.ID,
WechatID: memberMap["id"].(string),
Nickname: memberMap["name"].(string),
Avatar: memberMap["avatar"].(string),
Role: role,
}
db.Create(&member)
members = append(members, member)
}
}
}
}
return c.Render("contact/members", fiber.Map{
"Title": contact.Nickname + " 群成员",
"Robot": robot,
"Contact": contact,
"Members": members,
})
}