ai_scheduler/internal/biz/advice_client.go

245 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 biz
import (
"ai_scheduler/internal/data/mongo_model"
"ai_scheduler/internal/entitys"
"ai_scheduler/internal/pkg"
"errors"
"fmt"
"time"
"context"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)
type AdviceClientBiz struct {
AdvicerClientMongo *mongo_model.AdvicerClientMongo
mongo *pkg.Mongo
}
func NewAdviceClientBiz(
advicerClientMongo *mongo_model.AdvicerClientMongo,
mongo *pkg.Mongo,
) *AdviceClientBiz {
return &AdviceClientBiz{
AdvicerClientMongo: advicerClientMongo,
mongo: mongo,
}
}
func (a *AdviceClientBiz) Add(ctx context.Context, param *entitys.AdvicerClientAddReq) (id interface{}, err error) {
// AI 参与开关:默认开启
aiEnabled := true
if param.AiEnabled != nil {
aiEnabled = *param.AiEnabled
}
res, err := a.mongo.Co(a.AdvicerClientMongo).InsertOne(ctx, &mongo_model.AdvicerClientMongo{
ProjectId: param.ProjectId,
AdvicerId: param.AdvicerId,
Wxid: param.Wxid,
AiEnabled: aiEnabled,
PersonalInfo: param.PersonalInfo,
PurchasePurpose: param.PurchasePurpose,
CoreDemands: param.CoreDemands,
Concerns: param.Concerns,
DecisionProfile: param.DecisionProfile,
LastUpdateTime: time.Now(),
})
if err != nil {
return nil, err
}
return res.InsertedID, err
}
func (a *AdviceClientBiz) Update(ctx context.Context, param *entitys.AdvicerrClientUpdateReq) (err error) {
filter := bson.M{}
if len(param.Id) == 0 {
return errors.New("ID不能为空")
}
objectID, err := primitive.ObjectIDFromHex(param.Id)
if err != nil {
return fmt.Errorf("ID转换失败: %w", err)
}
filter["_id"] = objectID
// 读取旧记录,保留回调/等级评估自动维护的字段,避免人工编辑资料时被覆盖
var old mongo_model.AdvicerClientMongo
if err = a.mongo.Co(a.AdvicerClientMongo).FindOne(ctx, filter).Decode(&old); err != nil {
return fmt.Errorf("客户不存在: %w", err)
}
// AI 参与开关:未传保持原值
aiEnabled := old.AiEnabled
if param.AiEnabled != nil {
aiEnabled = *param.AiEnabled
}
update := bson.M{
"$set": &mongo_model.AdvicerClientMongo{
ProjectId: param.ProjectId,
AdvicerId: param.AdvicerId,
Wxid: old.Wxid,
AppId: old.AppId,
ClientLevel: old.ClientLevel,
LevelReason: old.LevelReason,
LevelUpdateAt: old.LevelUpdateAt,
LastContactAt: old.LastContactAt,
LastClientMsgAt: old.LastClientMsgAt,
LastReplyAt: old.LastReplyAt,
MsgCount: old.MsgCount,
AiEnabled: aiEnabled,
LastIterateAt: old.LastIterateAt,
PersonalInfo: param.PersonalInfo,
PurchasePurpose: param.PurchasePurpose,
CoreDemands: param.CoreDemands,
Concerns: param.Concerns,
DecisionProfile: param.DecisionProfile,
LastUpdateTime: time.Now(),
},
}
res := a.mongo.Co(a.AdvicerClientMongo).FindOneAndUpdate(ctx, filter, update)
return res.Err()
}
func (a *AdviceClientBiz) List(ctx context.Context, param *entitys.AdvicerClientListReq) (list []mongo_model.AdvicerClientItem, err error) {
filter := bson.M{}
// 1. advicer_id 条件
if param.AdvicerId != 0 {
filter["advicerId"] = param.AdvicerId
}
if param.ProjectId != 0 {
filter["projectId"] = param.ProjectId
}
// 2. _id 条件
if len(param.Id) != 0 {
objectID, err := primitive.ObjectIDFromHex(param.Id)
if err != nil {
return nil, fmt.Errorf("ID转换失败: %w", err)
}
filter["_id"] = objectID
}
cursor, err := a.mongo.Co(a.AdvicerClientMongo).Find(ctx, filter)
if err != nil {
return nil, err
}
// 遍历结果
for cursor.Next(ctx) {
var advicerVersion mongo_model.AdvicerClientItem
if err := cursor.Decode(&advicerVersion); err != nil {
return nil, err
}
list = append(list, advicerVersion)
}
if err := cursor.Err(); err != nil {
return nil, err
}
return list, err
}
func (a *AdviceClientBiz) Del(ctx context.Context, param *entitys.AdvicerClientDelReq) (err error) {
filter := bson.M{}
if len(param.Id) != 0 {
objectID, err := primitive.ObjectIDFromHex(param.Id)
if err != nil {
return fmt.Errorf("ID转换失败: %w", err)
}
filter["_id"] = objectID
}
_, err = a.mongo.Co(a.AdvicerClientMongo).DeleteOne(ctx, filter)
return err
}
func (a *AdviceClientBiz) Info(ctx context.Context, param *entitys.AdvicerClientInfoReq) (info mongo_model.AdvicerClientMongo, err error) {
filter := bson.M{}
if len(param.Id) != 0 {
objectID, err := primitive.ObjectIDFromHex(param.Id)
if err != nil {
return info, fmt.Errorf("ID转换失败: %w", err)
}
filter["_id"] = objectID
}
res := a.mongo.Co(a.AdvicerClientMongo).FindOne(ctx, filter)
if res.Err() != nil {
return info, res.Err()
}
if err = res.Decode(&info); err != nil {
return info, err
}
return
}
// Bind 客户绑定微信(wxid 用于回调消息关联到该客户)
func (a *AdviceClientBiz) Bind(ctx context.Context, param *entitys.AdvicerClientBindReq) (err error) {
if len(param.Id) == 0 {
return errors.New("ID不能为空")
}
if len(param.Wxid) == 0 {
return errors.New("wxid不能为空")
}
objectID, err := primitive.ObjectIDFromHex(param.Id)
if err != nil {
return fmt.Errorf("ID转换失败: %w", err)
}
set := bson.M{"wxid": param.Wxid, "lastUpdateTime": time.Now()}
if len(param.AppId) != 0 {
set["appId"] = param.AppId
}
_, err = a.mongo.Co(a.AdvicerClientMongo).UpdateOne(ctx, bson.M{"_id": objectID}, bson.M{"$set": set})
return err
}
// FindByWxid 按客户微信 wxid 查询客户(回调链按消息来源定位客户)
func (a *AdviceClientBiz) FindByWxid(ctx context.Context, wxid string) (info mongo_model.AdvicerClientItem, found bool, err error) {
if len(wxid) == 0 {
return info, false, errors.New("wxid不能为空")
}
res := a.mongo.Co(a.AdvicerClientMongo).FindOne(ctx, bson.M{"wxid": wxid})
if res.Err() != nil {
if errors.Is(res.Err(), mongo.ErrNoDocuments) {
return info, false, nil
}
return info, false, res.Err()
}
if err = res.Decode(&info); err != nil {
return info, false, err
}
return info, true, nil
}
// TouchInteraction 更新客户互动时间与消息数(回调链针对已绑定客户调用)
// direction: customer 客户发来(更新 lastClientMsgAt);self/ai 我方回复(更新 lastReplyAt)
func (a *AdviceClientBiz) TouchInteraction(ctx context.Context, wxid string, direction string) (err error) {
if len(wxid) == 0 {
return nil
}
now := time.Now()
set := bson.M{
"lastContactAt": now,
}
if direction == mongo_model.WxMsgDirectionCustomer {
set["lastClientMsgAt"] = now
} else {
set["lastReplyAt"] = now
}
update := bson.M{
"$set": set,
"$inc": bson.M{"msgCount": 1},
}
_, err = a.mongo.Co(a.AdvicerClientMongo).UpdateOne(ctx, bson.M{"wxid": wxid}, update)
return err
}