225 lines
6.6 KiB
Go
225 lines
6.6 KiB
Go
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)
|
||
}
|