239 lines
6.5 KiB
Go
239 lines
6.5 KiB
Go
package biz
|
||
|
||
import (
|
||
"ai_scheduler/internal/data/mongo_model"
|
||
"ai_scheduler/internal/entitys"
|
||
"ai_scheduler/internal/pkg"
|
||
"context"
|
||
"errors"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"go.mongodb.org/mongo-driver/bson"
|
||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||
"go.mongodb.org/mongo-driver/mongo/options"
|
||
)
|
||
|
||
// AdviceActivityBiz 产品活动管理(后台发布,用于 AI 主动对话与活动推送素材)
|
||
type AdviceActivityBiz struct {
|
||
mongo *pkg.Mongo
|
||
activityMongo *mongo_model.AdvicerActivityMongo
|
||
}
|
||
|
||
func NewAdviceActivityBiz(
|
||
mongo *pkg.Mongo,
|
||
activityMongo *mongo_model.AdvicerActivityMongo,
|
||
) *AdviceActivityBiz {
|
||
return &AdviceActivityBiz{
|
||
mongo: mongo,
|
||
activityMongo: activityMongo,
|
||
}
|
||
}
|
||
|
||
// Add 新增产品活动
|
||
func (a *AdviceActivityBiz) Add(ctx context.Context, param *entitys.AdvicerActivityAddReq) (id interface{}, err error) {
|
||
name := strings.TrimSpace(param.Name)
|
||
if len(name) == 0 {
|
||
return nil, errors.New("活动名称不能为空")
|
||
}
|
||
var startAt, endAt time.Time
|
||
if len(strings.TrimSpace(param.StartAt)) != 0 {
|
||
if startAt, err = parseTimeStr(param.StartAt); err != nil {
|
||
return nil, fmt.Errorf("开始时间格式错误: %w", err)
|
||
}
|
||
}
|
||
if len(strings.TrimSpace(param.EndAt)) != 0 {
|
||
if endAt, err = parseTimeStr(param.EndAt); err != nil {
|
||
return nil, fmt.Errorf("结束时间格式错误: %w", err)
|
||
}
|
||
}
|
||
now := time.Now()
|
||
res, err := a.mongo.Co(a.activityMongo).InsertOne(ctx, &mongo_model.AdvicerActivityMongo{
|
||
ProjectId: param.ProjectId,
|
||
AdvicerId: param.AdvicerId,
|
||
Name: name,
|
||
Content: param.Content,
|
||
StartAt: startAt,
|
||
EndAt: endAt,
|
||
TargetLevels: param.TargetLevels,
|
||
Status: param.Status,
|
||
CreateAt: now,
|
||
UpdateAt: now,
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return res.InsertedID, nil
|
||
}
|
||
|
||
// Update 更新产品活动(未传字段保持原值)
|
||
func (a *AdviceActivityBiz) Update(ctx context.Context, param *entitys.AdvicerActivityUpdateReq) (err error) {
|
||
if len(param.Id) == 0 {
|
||
return errors.New("ID不能为空")
|
||
}
|
||
objectID, err := primitive.ObjectIDFromHex(param.Id)
|
||
if err != nil {
|
||
return fmt.Errorf("ID转换失败: %w", err)
|
||
}
|
||
|
||
set := bson.M{"updateAt": time.Now()}
|
||
if name := strings.TrimSpace(param.Name); len(name) != 0 {
|
||
set["name"] = name
|
||
}
|
||
if param.Content != "" {
|
||
set["content"] = param.Content
|
||
}
|
||
if len(strings.TrimSpace(param.StartAt)) != 0 {
|
||
t, e := parseTimeStr(param.StartAt)
|
||
if e != nil {
|
||
return fmt.Errorf("开始时间格式错误: %w", e)
|
||
}
|
||
set["startAt"] = t
|
||
}
|
||
if len(strings.TrimSpace(param.EndAt)) != 0 {
|
||
t, e := parseTimeStr(param.EndAt)
|
||
if e != nil {
|
||
return fmt.Errorf("结束时间格式错误: %w", e)
|
||
}
|
||
set["endAt"] = t
|
||
}
|
||
if param.TargetLevels != nil {
|
||
set["targetLevels"] = param.TargetLevels
|
||
}
|
||
if param.ProjectId != 0 {
|
||
set["projectId"] = param.ProjectId
|
||
}
|
||
if param.AdvicerId != 0 {
|
||
set["advicerId"] = param.AdvicerId
|
||
}
|
||
// 状态显式覆盖(0草稿/1进行中/2停止)
|
||
set["status"] = param.Status
|
||
|
||
_, err = a.mongo.Co(a.activityMongo).UpdateOne(ctx, bson.M{"_id": objectID}, bson.M{"$set": set})
|
||
return err
|
||
}
|
||
|
||
// List 活动列表查询(按更新时间倒序)
|
||
func (a *AdviceActivityBiz) List(ctx context.Context, param *entitys.AdvicerActivityListReq) (list []mongo_model.AdvicerActivityItem, err error) {
|
||
filter := bson.M{}
|
||
if param.ProjectId != 0 {
|
||
filter["projectId"] = param.ProjectId
|
||
}
|
||
if param.AdvicerId != 0 {
|
||
filter["advicerId"] = param.AdvicerId
|
||
}
|
||
if param.Status != nil {
|
||
filter["status"] = *param.Status
|
||
}
|
||
if len(param.Id) != 0 {
|
||
objectID, e := primitive.ObjectIDFromHex(param.Id)
|
||
if e != nil {
|
||
return nil, fmt.Errorf("ID转换失败: %w", e)
|
||
}
|
||
filter["_id"] = objectID
|
||
}
|
||
|
||
opts := options.Find().SetSort(bson.D{{Key: "updateAt", Value: -1}})
|
||
if param.PageSize > 0 {
|
||
page := param.Page
|
||
if page < 1 {
|
||
page = 1
|
||
}
|
||
size := int64(param.PageSize)
|
||
opts.SetSkip(int64(page-1) * size).SetLimit(size)
|
||
} else {
|
||
opts.SetLimit(500)
|
||
}
|
||
|
||
cursor, err := a.mongo.Co(a.activityMongo).Find(ctx, filter, opts)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
for cursor.Next(ctx) {
|
||
var item mongo_model.AdvicerActivityItem
|
||
if err = cursor.Decode(&item); err != nil {
|
||
return nil, err
|
||
}
|
||
list = append(list, item)
|
||
}
|
||
if err = cursor.Err(); err != nil {
|
||
return nil, err
|
||
}
|
||
return list, nil
|
||
}
|
||
|
||
// Del 删除活动
|
||
func (a *AdviceActivityBiz) Del(ctx context.Context, param *entitys.AdvicerActivityDelReq) (err error) {
|
||
if len(param.Id) == 0 {
|
||
return errors.New("ID不能为空")
|
||
}
|
||
objectID, err := primitive.ObjectIDFromHex(param.Id)
|
||
if err != nil {
|
||
return fmt.Errorf("ID转换失败: %w", err)
|
||
}
|
||
_, err = a.mongo.Co(a.activityMongo).DeleteOne(ctx, bson.M{"_id": objectID})
|
||
return err
|
||
}
|
||
|
||
// Info 活动详情
|
||
func (a *AdviceActivityBiz) Info(ctx context.Context, param *entitys.AdvicerActivityInfoReq) (info mongo_model.AdvicerActivityMongo, err error) {
|
||
if len(param.Id) == 0 {
|
||
return info, errors.New("ID不能为空")
|
||
}
|
||
objectID, err := primitive.ObjectIDFromHex(param.Id)
|
||
if err != nil {
|
||
return info, fmt.Errorf("ID转换失败: %w", err)
|
||
}
|
||
res := a.mongo.Co(a.activityMongo).FindOne(ctx, bson.M{"_id": objectID})
|
||
if res.Err() != nil {
|
||
return info, res.Err()
|
||
}
|
||
if err = res.Decode(&info); err != nil {
|
||
return info, err
|
||
}
|
||
return info, nil
|
||
}
|
||
|
||
// ActiveList 查询当前生效的活动(状态启用 + 已在时间范围内),供 AI 主动对话/推送取素材。
|
||
// level 非空时只返回"未限定等级"或目标等级匹配的活动。
|
||
func (a *AdviceActivityBiz) ActiveList(ctx context.Context, projectId int32, level string) (list []mongo_model.AdvicerActivityItem, err error) {
|
||
now := time.Now()
|
||
filter := bson.M{
|
||
"status": mongo_model.ActivityStatusActive,
|
||
"startAt": bson.M{"$lte": now},
|
||
}
|
||
if projectId != 0 {
|
||
filter["projectId"] = projectId
|
||
}
|
||
// endAt 为零值视为长期有效,否则需在结束时间之前
|
||
filter["$or"] = []bson.M{
|
||
{"endAt": bson.M{"$gte": now}},
|
||
{"endAt": time.Time{}},
|
||
}
|
||
if len(level) != 0 {
|
||
filter["$and"] = []bson.M{{
|
||
"$or": []bson.M{
|
||
{"targetLevels": bson.M{"$size": 0}},
|
||
{"targetLevels": level},
|
||
},
|
||
}}
|
||
}
|
||
|
||
cursor, err := a.mongo.Co(a.activityMongo).Find(ctx, filter, options.Find().SetSort(bson.D{{Key: "startAt", Value: -1}}))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
for cursor.Next(ctx) {
|
||
var item mongo_model.AdvicerActivityItem
|
||
if err = cursor.Decode(&item); err != nil {
|
||
return nil, err
|
||
}
|
||
list = append(list, item)
|
||
}
|
||
if err = cursor.Err(); err != nil {
|
||
return nil, err
|
||
}
|
||
return list, nil
|
||
}
|