package advice import ( "ai_scheduler/internal/biz" "ai_scheduler/internal/entitys" "ai_scheduler/internal/pkg" "ai_scheduler/internal/pkg/wx" "fmt" "strconv" "strings" "github.com/gofiber/fiber/v2" ) // CustomerService 微信好友数据服务 type CustomerService struct { customerBiz *biz.AdviceCustomerBiz labelBiz *biz.AdviceLabelBiz projectBiz *biz.AdviceProjectBiz advicerBiz *biz.AdviceAdvicerBiz } func NewCustomerService(customerBiz *biz.AdviceCustomerBiz, labelBiz *biz.AdviceLabelBiz, projectBiz *biz.AdviceProjectBiz, advicerBiz *biz.AdviceAdvicerBiz) *CustomerService { return &CustomerService{customerBiz: customerBiz, labelBiz: labelBiz, projectBiz: projectBiz, advicerBiz: advicerBiz} } // Add 新增单条好友 func (s *CustomerService) Add(c *fiber.Ctx) error { req := &entitys.AdvicerCustomerAddReq{} if err := c.BodyParser(req); err != nil { return err } err := s.customerBiz.Add(c.UserContext(), req) return pkg.HandleResponse(c, nil, err) } // List 好友列表查询 func (s *CustomerService) List(c *fiber.Ctx) error { req := &entitys.AdvicerCustomerListReq{} if err := c.BodyParser(req); err != nil { return err } list, err := s.customerBiz.List(c.UserContext(), req) return pkg.HandleResponse(c, list, err) } // Del 删除好友 func (s *CustomerService) Del(c *fiber.Ctx) error { req := &entitys.AdvicerCustomerDelReq{} if err := c.BodyParser(req); err != nil { return err } err := s.customerBiz.Del(c.UserContext(), req) return pkg.HandleResponse(c, nil, err) } // Diff 好友差集查询(同时返回标签列表) func (s *CustomerService) Diff(c *fiber.Ctx) error { req := &entitys.AdvicerCustomerDiffReq{} if err := c.BodyParser(req); err != nil { return err } diff, err := s.customerBiz.Diff(c.UserContext(), req) if err != nil { return pkg.HandleResponse(c, nil, err) } // 顺便查询标签列表 if req.SelfWxid != "" { labels, _ := s.labelBiz.List(c.UserContext(), &entitys.AdvicerLabelListReq{SelfWxid: req.SelfWxid}) if labels != nil { diff.Labels = labels } } return pkg.HandleResponse(c, diff, nil) } // BatchAdd 批量新增好友 func (s *CustomerService) BatchAdd(c *fiber.Ctx) error { req := &entitys.AdvicerCustomerBatchAddReq{} if err := c.BodyParser(req); err != nil { return err } err := s.customerBiz.BatchAdd(c.UserContext(), req) return pkg.HandleResponse(c, nil, err) } // BatchUpdate 批量更新已有好友信息 func (s *CustomerService) BatchUpdate(c *fiber.Ctx) error { req := &entitys.AdvicerCustomerBatchAddReq{} if err := c.BodyParser(req); err != nil { return err } err := s.customerBiz.BatchUpdate(c.UserContext(), req) return pkg.HandleResponse(c, nil, err) } // UpdateLabels 更新好友标签列表(wx API + DB 一次完成) func (s *CustomerService) UpdateLabels(c *fiber.Ctx) error { req := &entitys.AdvicerCustomerUpdateLabelsReq{} if err := c.BodyParser(req); err != nil { return err } // 1. 查询项目的 wx_token project, err := s.projectBiz.BaseInfo(req.ProjectId) if err != nil { return pkg.HandleResponse(c, nil, err) } if project.WxToken == "" { return pkg.HandleResponse(c, nil, fiber.NewError(fiber.StatusBadRequest, "项目未配置微信接入 Token")) } // 2. 调用微信 API 修改好友标签(全量替换) var wxIds []string if req.UserName != "" { wxIds = strings.Split(req.UserName, ",") } wxReq := wx.ModifyMemberListReq{ AppId: req.AppId, LabelIds: req.LabelList, WxIds: wxIds, } var wxRes wx.ModifyMemberListResData if err := wx.Request(c.UserContext(), project.WxToken, wx.ModifyMemberList, wxReq, &wxRes); err != nil { return pkg.HandleResponse(c, nil, fmt.Errorf("微信标签修改失败: %w", err)) } // 3. 更新 DB if err := s.customerBiz.UpdateLabels(c.UserContext(), &entitys.AdvicerCustomerUpdateLabelsReq{ SelfWxid: req.SelfWxid, UserName: req.UserName, LabelList: req.LabelList, }); err != nil { return pkg.HandleResponse(c, nil, fmt.Errorf("数据库更新失败: %w", err)) } return pkg.HandleResponse(c, nil, nil) } // HostedList 查询项目下所有托管客户(在托管标签分组内的客户) func (s *CustomerService) HostedList(c *fiber.Ctx) error { req := &entitys.AdvicerCustomerHostedListReq{} if err := c.BodyParser(req); err != nil { return err } ctx := c.UserContext() // 1. 查项目下所有销售 advicers, err := s.advicerBiz.List(ctx, &entitys.AdvicerListReq{ProjectId: req.ProjectId}) if err != nil { return pkg.HandleResponse(c, nil, err) } // 构建 selfWxid -> advicerName 映射,收集所有 selfWxid // 关联逻辑:advicer.wx_id = ai_advice_customer.self_wxid advicerMap := make(map[string]string) var selfWxids []string for _, adv := range advicers { wxId, _ := adv["wx_id"].(string) name, _ := adv["name"].(string) if wxId != "" { advicerMap[wxId] = name selfWxids = append(selfWxids, wxId) } } if len(selfWxids) == 0 { return pkg.HandleResponse(c, []entitys.HostedCustomerItem{}, nil) } // 2. 获取每个销售的托管标签 ID,构建 selfWxid -> hostingLabelIds 和 labelId -> labelName 映射 hostingLabelsMap := make(map[string]map[int]bool) labelNameMap := make(map[int]string) for _, selfWxid := range selfWxids { hostIds, _ := s.labelBiz.GetHostingLabelIds(ctx, selfWxid) if len(hostIds) == 0 { continue } hostingLabelsMap[selfWxid] = make(map[int]bool) for _, id := range hostIds { hostingLabelsMap[selfWxid][id] = true } labels, _ := s.labelBiz.List(ctx, &entitys.AdvicerLabelListReq{SelfWxid: selfWxid}) for _, l := range labels { labelNameMap[int(l.LabelId)] = l.LabelName } } if len(hostingLabelsMap) == 0 { return pkg.HandleResponse(c, []entitys.HostedCustomerItem{}, nil) } // 3. 查询这些 selfWxid 下的所有客户,筛选出在托管标签下的 allCustomers, err := s.customerBiz.FindBySelfWxids(ctx, selfWxids) if err != nil { return pkg.HandleResponse(c, nil, err) } var result []entitys.HostedCustomerItem for _, cust := range allCustomers { hostLabels, ok := hostingLabelsMap[cust.SelfWxid] if !ok { continue } // 判断客户的 label_list 与托管标签是否有交集 var matchedNames []string for _, ls := range strings.Split(cust.LabelList, ",") { id, e := strconv.Atoi(strings.TrimSpace(ls)) if e == nil && hostLabels[id] { if name, exists := labelNameMap[id]; exists { matchedNames = append(matchedNames, name) } } } if len(matchedNames) == 0 { continue } result = append(result, entitys.HostedCustomerItem{ AiAdviceCustomer: cust, LabelNames: strings.Join(matchedNames, ","), AdvicerName: advicerMap[cust.SelfWxid], }) } return pkg.HandleResponse(c, result, nil) }