ai_scheduler/internal/biz/advice_project.go

367 lines
12 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 (
errorcode "ai_scheduler/internal/data/error"
"ai_scheduler/internal/data/impl"
"ai_scheduler/internal/data/model"
"ai_scheduler/internal/data/mongo_model"
"ai_scheduler/internal/entitys"
"ai_scheduler/internal/pkg"
"ai_scheduler/tmpl/dataTemp"
"errors"
"fmt"
"time"
"context"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"xorm.io/builder"
)
type AdviceProjectBiz struct {
AdvicerProjectMongo *mongo_model.AdvicerProjectMongo
AdvicerProjectDataMongo *mongo_model.AdvicerProjectDataMongo
adviceProjectImpl *impl.AdviceProjectImpl
aiAdviceModelSupImpl *impl.AiAdviceModelSupImpl
industryImpl *impl.AdviceIndustryImpl
mongo *pkg.Mongo
}
func NewAdviceProjectBiz(
advicerProjectMongo *mongo_model.AdvicerProjectMongo,
advicerProjectDataMongo *mongo_model.AdvicerProjectDataMongo,
adviceProjectImpl *impl.AdviceProjectImpl,
aiAdviceModelSupImpl *impl.AiAdviceModelSupImpl,
industryImpl *impl.AdviceIndustryImpl,
mongo *pkg.Mongo,
) *AdviceProjectBiz {
return &AdviceProjectBiz{
AdvicerProjectMongo: advicerProjectMongo,
AdvicerProjectDataMongo: advicerProjectDataMongo,
mongo: mongo,
adviceProjectImpl: adviceProjectImpl,
aiAdviceModelSupImpl: aiAdviceModelSupImpl,
industryImpl: industryImpl,
}
}
// BaseAdd 新建项目基础信息;IndustryId>0 时自动复制行业模板的维度内容
func (a *AdviceProjectBiz) BaseAdd(ctx context.Context, param *entitys.AdvicerProjectBaseAddReq) (res *entitys.AdvicerProjectBaseAddRes, err error) {
add := &model.AiAdviceProject{
Name: param.Name,
ModelSupID: param.ModelSupId,
}
if param.IndustryId > 0 {
if err = a.fillTemplateFromIndustry(ctx, add, param.IndustryId); err != nil {
return nil, err
}
}
err = a.adviceProjectImpl.AddWithData(add)
if err != nil {
return nil, err
}
return &entitys.AdvicerProjectBaseAddRes{
ProjectId: add.ProjectID,
}, err
}
// BaseUpdate 更新项目基础信息与项目级模板字段(仅更新传入非空字段)
func (a *AdviceProjectBiz) BaseUpdate(ctx context.Context, param *entitys.AdvicerProjectBaseUpdateReq) (err error) {
if param.ProjectId == 0 {
return errorcode.ParamErr("projectId is empty")
}
updates := make(map[string]interface{})
if param.Name != "" {
updates["name"] = param.Name
}
if param.ModelSupId != 0 {
updates["model_sup_id"] = param.ModelSupId
}
if param.Desc != "" {
updates["template_desc"] = param.Desc
}
if param.AdvicerDesc != "" {
updates["template_advicer_desc"] = param.AdvicerDesc
}
if param.ClientDimension != "" {
updates["client_dimension"] = param.ClientDimension
}
if param.ProjectDimension != "" {
updates["project_dimension"] = param.ProjectDimension
}
if param.AdvicerDimension != "" {
updates["advicer_dimension"] = param.AdvicerDimension
}
if param.TalkSkillDimension != "" {
updates["talk_skill_dimension"] = param.TalkSkillDimension
}
if param.RuleDimension != "" {
updates["rule_dimension"] = param.RuleDimension
}
if param.WxToken != "" {
updates["wx_token"] = param.WxToken
}
// IndustryId>0 时重新从行业模板复制(覆盖模板字段)
if param.IndustryId > 0 {
var industry model.AiAdviceIndustryTemp
if err = a.industryImpl.GetByKey(ctx, "industry_id", param.IndustryId, &industry); err != nil {
return err
}
if industry.IndustryId == 0 {
return errorcode.ParamErr("行业模板不存在")
}
a.mergeIndustryTemplate(updates, &industry)
}
if len(updates) == 0 {
return nil
}
cond := builder.NewCond()
cond = cond.And(builder.Eq{"project_id": param.ProjectId})
err = a.adviceProjectImpl.UpdateByCond(&cond, updates)
return err
}
// TemplateCopy 重新应用行业模板(全量覆盖项目模板字段)
func (a *AdviceProjectBiz) TemplateCopy(ctx context.Context, param *entitys.AdvicerProjectTemplateCopyReq) (err error) {
if param.ProjectId == 0 {
return errorcode.ParamErr("projectId is empty")
}
if param.IndustryId == 0 {
return errorcode.ParamErr("industryId is empty")
}
var industry model.AiAdviceIndustryTemp
if err = a.industryImpl.GetByKey(ctx, "industry_id", param.IndustryId, &industry); err != nil {
return err
}
if industry.IndustryId == 0 {
return errorcode.ParamErr("行业模板不存在")
}
updates := make(map[string]interface{})
a.mergeIndustryTemplate(updates, &industry)
cond := builder.NewCond()
cond = cond.And(builder.Eq{"project_id": param.ProjectId})
return a.adviceProjectImpl.UpdateByCond(&cond, updates)
}
// fillTemplateFromIndustry 从行业模板复制维度内容到项目实体
func (a *AdviceProjectBiz) fillTemplateFromIndustry(ctx context.Context, project *model.AiAdviceProject, industryId int32) error {
var industry model.AiAdviceIndustryTemp
if err := a.industryImpl.GetByKey(ctx, "industry_id", industryId, &industry); err != nil {
return err
}
if industry.IndustryId == 0 {
return errorcode.ParamErr("行业模板不存在")
}
project.IndustryID = industry.IndustryId
project.TemplateDesc = industry.Desc
project.TemplateAdvicerDesc = industry.AdvicerDesc
project.ClientDimension = industry.ClientDimension
project.ProjectDimension = industry.ProjectDimension
project.AdvicerDimension = industry.AdvicerDimension
project.TalkSkillDimension = industry.TalkSkillDimension
project.RuleDimension = industry.RuleDimension
return nil
}
// mergeIndustryTemplate 将行业模板内容合并到更新 map(全量覆盖语义)
func (a *AdviceProjectBiz) mergeIndustryTemplate(updates map[string]interface{}, industry *model.AiAdviceIndustryTemp) {
updates["industry_id"] = industry.IndustryId
updates["template_desc"] = industry.Desc
updates["template_advicer_desc"] = industry.AdvicerDesc
updates["client_dimension"] = industry.ClientDimension
updates["project_dimension"] = industry.ProjectDimension
updates["advicer_dimension"] = industry.AdvicerDimension
updates["talk_skill_dimension"] = industry.TalkSkillDimension
updates["rule_dimension"] = industry.RuleDimension
}
// List 分页查询项目列表
func (a *AdviceProjectBiz) List(ctx context.Context, param *entitys.AdvicerProjectListReq) (list []model.AiAdviceProject, total int64, err error) {
list = make([]model.AiAdviceProject, 0)
cond := builder.NewCond()
if param.Name != "" {
cond = cond.And(builder.Like{"name", "%" + param.Name + "%"})
}
page, err := a.adviceProjectImpl.GetListToStruct(ctx, &cond, &dataTemp.ReqPageBo{Page: param.Page, Limit: param.PageSize}, &list, "")
if err != nil {
return nil, 0, err
}
return list, page.Total, nil
}
func (a *AdviceProjectBiz) Add(ctx context.Context, param *entitys.AdvicerProjectAddReq) (id interface{}, err error) {
res, err := a.mongo.Co(a.AdvicerProjectMongo).InsertOne(ctx, &mongo_model.AdvicerProjectMongo{
ProjectId: param.ProjectId,
ProjectInfo: param.ProjectInfo,
RegionValue: param.RegionValue,
CompetitionComparison: param.CompetitionComparison,
CoreSellingPoints: param.CoreSellingPoints,
SupportingFacilities: param.SupportingFacilities,
DeveloperBacking: param.DeveloperBacking,
LastUpdateTime: time.Now(),
})
return res.InsertedID, err
}
func (a *AdviceProjectBiz) Update(ctx context.Context, param *entitys.AdvicerrProjectUpdateReq) (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
}
if param.ProjectId != 0 {
filter["projectId"] = param.ProjectId
}
update := bson.M{
"$set": &mongo_model.AdvicerProjectMongo{
ProjectId: param.ProjectId,
ProjectInfo: param.ProjectInfo,
RegionValue: param.RegionValue,
CompetitionComparison: param.CompetitionComparison,
CoreSellingPoints: param.CoreSellingPoints,
SupportingFacilities: param.SupportingFacilities,
DeveloperBacking: param.DeveloperBacking,
LastUpdateTime: time.Now(),
},
}
res := a.mongo.Co(a.AdvicerProjectMongo).FindOneAndUpdate(ctx, filter, update)
return res.Err()
}
func (a *AdviceProjectBiz) Info(ctx context.Context, param *entitys.AdvicerProjectInfoReq) (info *entitys.AdvicerProjectInfoRes, err error) {
configInfo, err := a.ConfigInfo(ctx, param)
if err != nil {
return nil, err
}
baseProjectId := configInfo.ProjectId
// mongo 中暂无配置记录时,回退用请求参数中的 projectId 查询基础信息
if baseProjectId == 0 {
baseProjectId = param.ProjectId
}
baseInfo, err := a.BaseInfo(baseProjectId)
if err != nil {
return nil, err
}
supInfo, err := a.ModelInfo(baseInfo.ModelSupID)
if err != nil {
return nil, err
}
return &entitys.AdvicerProjectInfoRes{
ConfigInfo: configInfo,
Base: baseInfo,
ModelInfo: supInfo,
}, nil
}
func (a *AdviceProjectBiz) BaseInfo(projectId int32) (baseInfo model.AiAdviceProject, err error) {
if projectId == 0 {
return
}
cond := builder.NewCond()
cond = cond.And(builder.Eq{"project_id": projectId})
err = a.adviceProjectImpl.GetOneBySearchToStrut(&cond, &baseInfo)
if err != nil {
return baseInfo, err
}
return baseInfo, nil
}
func (a *AdviceProjectBiz) ModelInfo(supId int32) (supInfo model.AiAdviceModelSup, err error) {
if supId == 0 {
return
}
cond := builder.NewCond()
cond = cond.And(builder.Eq{"sup_id": supId})
err = a.aiAdviceModelSupImpl.GetOneBySearchToStrut(&cond, &supInfo)
if err != nil {
return supInfo, err
}
return supInfo, nil
}
func (a *AdviceProjectBiz) ConfigInfo(ctx context.Context, param *entitys.AdvicerProjectInfoReq) (info mongo_model.AdvicerProjectMongo, err error) {
filter := bson.M{}
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 info, fmt.Errorf("ID转换失败: %w", err)
}
filter["_id"] = objectID
}
res := a.mongo.Co(a.AdvicerProjectMongo).FindOne(ctx, filter)
if res.Err() != nil && !errors.Is(res.Err(), mongo.ErrNoDocuments) {
return info, res.Err()
}
// 遍历结果
if err := res.Decode(&info); err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
return info, err
}
return info, nil
}
// ProjectDataLoad 加载项目资料(新表)
// 文档中除 projectId / lastUpdateTime 外的字段均为栏目数据
func (a *AdviceProjectBiz) ProjectDataLoad(ctx context.Context, projectId int32) (info mongo_model.AdvicerProjectDataMongo, err error) {
filter := bson.M{"projectId": projectId}
res := a.mongo.Co(a.AdvicerProjectDataMongo).FindOne(ctx, filter)
if res.Err() != nil && !errors.Is(res.Err(), mongo.ErrNoDocuments) {
return info, res.Err()
}
var raw bson.M
if err := res.Decode(&raw); err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
return info, err
}
if raw == nil {
return info, nil
}
info.ProjectId = projectId
if t, ok := raw["lastUpdateTime"].(primitive.DateTime); ok {
info.LastUpdateTime = t.Time()
}
// 除已知字段外,其余均为栏目数据
info.Data = make(map[string]interface{})
for k, v := range raw {
if k == "_id" || k == "projectId" || k == "lastUpdateTime" {
continue
}
info.Data[k] = v
}
return info, nil
}
// ProjectDataSave 保存项目资料(新表,upsert)
// 栏目数据直接展平到文档顶层字段
func (a *AdviceProjectBiz) ProjectDataSave(ctx context.Context, param *entitys.AdvicerProjectDataSaveReq) error {
filter := bson.M{"projectId": param.ProjectId}
setFields := bson.M{
"projectId": param.ProjectId,
"lastUpdateTime": time.Now(),
}
for k, v := range param.Data {
setFields[k] = v
}
update := bson.M{"$set": setFields}
opts := options.Update().SetUpsert(true)
_, err := a.mongo.Co(a.AdvicerProjectDataMongo).UpdateOne(ctx, filter, update, opts)
return err
}