Browse Source

种草公开&定向任务创建

Ethan 7 months ago
parent
commit
448ece88ae

+ 92 - 7
app/controller/task_controller.go

@@ -11,9 +11,15 @@ import (
 type TaskController struct{}
 
 type SelectionDetailParam struct {
-	SelectionId  string `json:"selection_id"`
-	EnterpriseId string `json:"enterprise_id"`
-	SubAccountId int    `json:"sub_account_id"`
+	SelectionId string `json:"selection_id"`
+	//EnterpriseId string `json:"enterprise_id"`
+	//SubAccountId int    `json:"sub_account_id"`
+}
+
+type ProjectDetailParam struct {
+	ProjectId string `json:"project_id"`
+	//EnterpriseId string `json:"enterprise_id"`
+	//SubAccountId int    `json:"sub_account_id"`
 }
 
 // 关联商品-已有商品展示
@@ -46,7 +52,7 @@ func (t TaskController) CreateProduct(c *gin.Context) {
 	}
 	productId, err := service.ProductService{}.CreateProduct(data)
 	resultMap := make(map[string]int64)
-	resultMap["product_id"] = productId
+	resultMap["productId"] = productId
 	returnSuccess(c, 20000, resultMap)
 }
 
@@ -66,7 +72,7 @@ func (t TaskController) CreateSelection(c *gin.Context) {
 		return
 	}
 	resultMap := make(map[string]string)
-	resultMap["selection_id"] = *selectionId
+	resultMap["selectionId"] = *selectionId
 	returnSuccess(c, 20000, resultMap)
 }
 
@@ -86,7 +92,7 @@ func (t TaskController) UpdateSelection(c *gin.Context) {
 		return
 	}
 	resultMap := make(map[string]string)
-	resultMap["selection_id"] = *selectionId
+	resultMap["selectionId"] = *selectionId
 	returnSuccess(c, 20000, resultMap)
 }
 
@@ -99,7 +105,7 @@ func (t TaskController) GetSelectionDetail(c *gin.Context) {
 		returnError(c, 40000, "参数错误")
 		return
 	}
-	res, err := service.SelectionInfoService{}.GetSelectionDetail(data.SelectionId, data.EnterpriseId)
+	res, err := service.SelectionInfoService{}.GetSelectionDetail(data.SelectionId)
 	if err != nil {
 		logrus.Errorf("[GetSelectionDetail] call Show err:%+v\n", err)
 		returnError(c, 40000, "error")
@@ -167,3 +173,82 @@ func (t TaskController) CheckSelectionInfo(c *gin.Context) {
 
 	returnSuccess(c, 20000, res3)
 }
+
+// 创建种草任务
+func (t TaskController) CreateProject(c *gin.Context) {
+	data := &vo.ProjectCreateParam{}
+	err := c.BindJSON(data)
+	if err != nil {
+		logrus.Errorf("Request bind err:%+v\n", err)
+		returnError(c, 40000, "参数错误")
+		return
+	}
+	projectId, err := service.ProjectService{}.CreateProject(data)
+	if err != nil {
+		logrus.Errorf("[CreateProject] call CreateProject err:%+v\n", err)
+		returnError(c, 40000, "error")
+		return
+	}
+	resultMap := make(map[string]string)
+	resultMap["projectId"] = *projectId
+	returnSuccess(c, 20000, resultMap)
+}
+
+// 更新种草任务
+func (t TaskController) UpdateProject(c *gin.Context) {
+	data := &vo.ProjectUpdateParam{}
+	err := c.BindJSON(data)
+	if err != nil {
+		logrus.Errorf("Request bind err:%+v\n", err)
+		returnError(c, 40000, "参数错误")
+		return
+	}
+	projectId, err := service.ProjectService{}.UpdateProject(data)
+	if err != nil {
+		logrus.Errorf("[UpdateProject] call UpdateProject err:%+v\n", err)
+		returnError(c, 40000, "error")
+		return
+	}
+	resultMap := make(map[string]string)
+	resultMap["projectId"] = *projectId
+	returnSuccess(c, 20000, resultMap)
+}
+
+// 更新定向种草任务
+func (t TaskController) UpdateProjectTarget(c *gin.Context) {
+	data := &vo.ProjectUpdateParam{}
+	err := c.BindJSON(data)
+	if err != nil {
+		logrus.Errorf("Request bind err:%+v\n", err)
+		returnError(c, 40000, "参数错误")
+		return
+	}
+	projectId, err := service.ProjectService{}.UpdateProjectTarget(data)
+	if err != nil {
+		logrus.Errorf("[UpdateProject] call UpdateProject err:%+v\n", err)
+		returnError(c, 40000, "error")
+		return
+	}
+	resultMap := make(map[string]string)
+	resultMap["projectId"] = *projectId
+	returnSuccess(c, 20000, resultMap)
+}
+
+// 种草任务预览
+func (t TaskController) GetProjectDetail(c *gin.Context) {
+	data := &ProjectDetailParam{}
+	err := c.BindJSON(data)
+	if err != nil {
+		logrus.Errorf("Request bind err:%+v\n", err)
+		returnError(c, 40000, "参数错误")
+		return
+	}
+	res, err := service.ProjectService{}.GetProjectDetail(data.ProjectId)
+	if err != nil {
+		logrus.Errorf("[GetSelectionDetail] call Show err:%+v\n", err)
+		returnError(c, 40000, "error")
+		return
+	}
+
+	returnSuccess(c, 20000, res)
+}

+ 43 - 0
app/dao/info_pricing_strategy_dao.go

@@ -0,0 +1,43 @@
+package dao
+
+import (
+	"fmt"
+	log "github.com/sirupsen/logrus"
+	"youngee_b_api/app/entity"
+)
+
+type InfoPricingStrategylDao struct{}
+
+func (d InfoPricingStrategylDao) GetPricingStrategy(fansLow int64, fansUp int64, feeForm int64, platForm int64) (*entity.InfoPricingStrategy, error) {
+	// fansLow粉丝量下限  fansUp粉丝量上限  feeForm稿费形式 1产品置换 2固定稿费 3自报价  platForm平台
+	var pricingStrategys []entity.InfoPricingStrategy
+	whereStr := fmt.Sprintf("fee_form = %d and platform = %d and fans_low <= %d and fans_up > %d", feeForm, platForm, fansLow, fansLow)
+	orStr := fmt.Sprintf("fee_form = %d and platform = %d and fans_low < %d and fans_up >= %d", feeForm, platForm, fansUp, fansUp)
+	orStr1 := fmt.Sprintf("fee_form = %d and platform = %d and fans_low >= %d and fans_up <= %d", feeForm, platForm, fansLow, fansUp)
+	orStr2 := fmt.Sprintf("fee_form = %d and platform = %d and fans_low <= %d and fans_up >= %d", feeForm, platForm, fansLow, fansUp)
+	err := Db.Model(entity.InfoPricingStrategy{}).Where(whereStr).Or(orStr).Or(orStr1).Or(orStr2).Scan(&pricingStrategys).Error
+	if err != nil {
+		log.Println("DB GetLastAutoDefaultID:", err)
+		return nil, err
+	}
+	fmt.Printf("PricingStrategys%+v \n", pricingStrategys)
+	pricingStrategy := entity.InfoPricingStrategy{}
+	if feeForm == 1 { // 如果是产品置换,则选取服务费最高时的定价策略
+		var maxCharge float64 = 0
+		for _, v := range pricingStrategys {
+			if v.ServiceCharge >= maxCharge {
+				maxCharge = v.ServiceCharge
+				pricingStrategy = v
+			}
+		}
+	} else { // 如果是固定稿费或自报价,则选取服务费率最高时的定价策略
+		var maxRate int64 = 0
+		for _, v := range pricingStrategys {
+			if v.ServiceRate >= maxRate {
+				maxRate = v.ServiceRate
+				pricingStrategy = v
+			}
+		}
+	}
+	return &pricingStrategy, nil
+}

+ 16 - 0
app/dao/product_dao.go

@@ -73,3 +73,19 @@ func (d ProductDAO) GetProductBySelectionId(selectionId string) (*entity.Product
 	}
 	return &productInfo, nil
 }
+
+func (d ProductDAO) GetProductByProjectId(projectId string) (*entity.Product, error) {
+	productId := 0
+	err := Db.Model(entity.Project{}).Select("product_id").Where("project_id = ?", projectId).Find(&productId).Error
+	if err != nil {
+		logrus.Errorf("[GetProductInfo] error query mysql, err:%+v", err)
+		return nil, err
+	}
+	productInfo := entity.Product{}
+	err = Db.Model(entity.Product{}).Where("product_id = ?", productId).Find(&productInfo).Error
+	if err != nil {
+		logrus.Errorf("[GetProductInfo] error query mysql, err:%+v", err)
+		return nil, err
+	}
+	return &productInfo, nil
+}

+ 16 - 0
app/dao/product_photo_dao.go

@@ -48,3 +48,19 @@ func (d ProductPhotoDAO) GetProductPhotosBySelectionId(selectionId string) ([]*e
 	}
 	return productPhotos, nil
 }
+
+func (d ProductPhotoDAO) GetProductPhotosByProjectId(projectId string) ([]*entity.ProductPhoto, error) {
+	productId := 0
+	err := Db.Model(entity.Project{}).Select("product_id").Where("project_id = ?", projectId).Find(&productId).Error
+	if err != nil {
+		logrus.Errorf("[GetProductInfo] error query mysql, err:%+v", err)
+		return nil, err
+	}
+	var productPhotos []*entity.ProductPhoto
+	err = Db.Model(entity.ProductPhoto{}).Where("product_id = ?", productId).Find(&productPhotos).Error
+	if err != nil {
+		logrus.Errorf("[GetProductInfo] error query mysql, err:%+v", err)
+		return nil, err
+	}
+	return productPhotos, nil
+}

+ 34 - 0
app/dao/project_brief_dao.go

@@ -0,0 +1,34 @@
+package dao
+
+import (
+	"github.com/sirupsen/logrus"
+	"youngee_b_api/app/entity"
+)
+
+type ProjectBriefDao struct{}
+
+func (p ProjectBriefDao) DeleteSecBriefBySelectionId(projectId string) error {
+	err := Db.Where("project_id = ?", projectId).Delete(entity.ProjectBrief{}).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (p ProjectBriefDao) CreateProjectBrief(briefInfo entity.ProjectBrief) error {
+	err := Db.Create(&briefInfo).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (p ProjectBriefDao) GetProjectBriefInfo(projectId string) ([]*entity.ProjectBrief, error) {
+	var projectBriefInfos []*entity.ProjectBrief
+	err := Db.Model(entity.ProjectBrief{}).Where("project_id = ?", projectId).Find(&projectBriefInfos).Error
+	if err != nil {
+		logrus.Errorf("[GetProjectBriefInfo] error query mysql, err:%+v", err)
+		return nil, err
+	}
+	return projectBriefInfos, nil
+}

+ 53 - 0
app/dao/project_dao.go

@@ -0,0 +1,53 @@
+package dao
+
+import (
+	"errors"
+	"gorm.io/gorm"
+	"time"
+	"youngee_b_api/app/entity"
+)
+
+type ProjectDAO struct{}
+
+func (d ProjectDAO) GetProjectById(ProjectId string) (*entity.Project, error) {
+	var Project entity.Project
+	err := Db.Where("project_id = ?", ProjectId).First(&Project).Error
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return nil, nil
+		} else {
+			return nil, err
+		}
+	}
+	return &Project, err
+}
+
+// 根据enterpriseId查询指定某天的所有带货数据
+func (d ProjectDAO) GetProjectListOfDay(enterpriseId string, date time.Time) ([]entity.Project, error) {
+	var Projects []entity.Project
+	// 构建查询
+	query := Db.Model(&entity.Project{})
+	if enterpriseId != "" {
+		query = query.Where("enterprise_id = ?", enterpriseId)
+	}
+	// 将日期部分提取出来进行匹配
+	query = query.Where("DATE(created_at) = ?", date.Format("2006-01-02"))
+	err := query.Find(&Projects).Error
+	return Projects, err
+}
+
+func (d ProjectDAO) CreateProject(project entity.Project) error {
+	err := Db.Omit("recruit_ddl", "auto_fail_at", "auto_script_break_at", "auto_sketch_break_at", "pay_at", "pass_at", "finish_at", "submit_at").Create(&project).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d ProjectDAO) UpdateProject(project entity.Project) error {
+	err := Db.Model(&entity.Project{}).Where("project_id = ?", project.ProjectId).Updates(project).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}

+ 34 - 0
app/dao/project_material_dao.go

@@ -0,0 +1,34 @@
+package dao
+
+import (
+	"github.com/sirupsen/logrus"
+	"youngee_b_api/app/entity"
+)
+
+type ProjectMaterialDao struct{}
+
+func (d ProjectMaterialDao) DeleteProjectMaterialByProjectId(projectId string) error {
+	err := Db.Where("project_id = ?", projectId).Delete(entity.ProjectMaterial{}).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d ProjectMaterialDao) CreateProjectMaterial(projectMaterial entity.ProjectMaterial) error {
+	err := Db.Create(&projectMaterial).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d ProjectMaterialDao) GetProjectMaterialInfo(projectId string) ([]*entity.ProjectMaterial, error) {
+	var projectMaterialInfos []*entity.ProjectMaterial
+	err := Db.Model(entity.ProjectMaterial{}).Where("project_id = ?", projectId).Find(&projectMaterialInfos).Error
+	if err != nil {
+		logrus.Errorf("[GetProjectMaterialInfo] error query, err:%+v", err)
+		return nil, err
+	}
+	return projectMaterialInfos, nil
+}

+ 34 - 0
app/dao/recruit_strategy_dao.go

@@ -0,0 +1,34 @@
+package dao
+
+import (
+	"github.com/sirupsen/logrus"
+	"youngee_b_api/app/entity"
+)
+
+type RecruitStrategyDao struct{}
+
+func (d RecruitStrategyDao) DeleteRecruitStrategyByProjectID(projectId string) error {
+	err := Db.Where("project_id = ?", projectId).Delete(&entity.RecruitStrategy{}).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d RecruitStrategyDao) CreateRecruitStrategy(recruitStrategys []entity.RecruitStrategy) error {
+	err := Db.Create(&recruitStrategys).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d RecruitStrategyDao) GetRecruitStrategyByProjectId(projectId string) ([]*entity.RecruitStrategy, error) {
+	var recruitStrategys []*entity.RecruitStrategy
+	err := Db.Model(entity.RecruitStrategy{}).Where("project_id = ?", projectId).Find(&recruitStrategys).Error
+	if err != nil {
+		logrus.Errorf("[GetRecruitStrategyByProjectId] error query, err:%+v", err)
+		return nil, err
+	}
+	return recruitStrategys, nil
+}

+ 0 - 34
app/dao/sec_example_dao.go

@@ -1,34 +0,0 @@
-package dao
-
-import (
-	"github.com/sirupsen/logrus"
-	"youngee_b_api/app/entity"
-)
-
-type SecExampleDao struct{}
-
-func (d SecExampleDao) DeleteSecExampleBySelectionId(selectionId string) error {
-	err := Db.Where("selection_id = ?", selectionId).Delete(entity.SecExample{}).Error
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-func (d SecExampleDao) CreateSecExample(secExample entity.SecExample) error {
-	err := Db.Create(&secExample).Error
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-func (d SecExampleDao) GetSelectionExampleInfo(selectionId string) ([]*entity.SecExample, error) {
-	var selectionExampleInfos []*entity.SecExample
-	err := Db.Model(entity.SecExample{}).Where("selection_id = ?", selectionId).Find(&selectionExampleInfos).Error
-	if err != nil {
-		logrus.Errorf("[GetSelectionExampleInfo] error query, err:%+v", err)
-		return nil, err
-	}
-	return selectionExampleInfos, nil
-}

+ 34 - 0
app/dao/sec_material_dao.go

@@ -0,0 +1,34 @@
+package dao
+
+import (
+	"github.com/sirupsen/logrus"
+	"youngee_b_api/app/entity"
+)
+
+type SecMaterialDao struct{}
+
+func (d SecMaterialDao) DeleteSecMaterialBySelectionId(selectionId string) error {
+	err := Db.Where("selection_id = ?", selectionId).Delete(entity.SecMaterial{}).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d SecMaterialDao) CreateSecMaterial(secExample entity.SecMaterial) error {
+	err := Db.Create(&secExample).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d SecMaterialDao) GetSelectionMaterialInfo(selectionId string) ([]*entity.SecMaterial, error) {
+	var selectionMaterialInfos []*entity.SecMaterial
+	err := Db.Model(entity.SecMaterial{}).Where("selection_id = ?", selectionId).Find(&selectionMaterialInfos).Error
+	if err != nil {
+		logrus.Errorf("[GetSelectionMaterialInfo] error query, err:%+v", err)
+		return nil, err
+	}
+	return selectionMaterialInfos, nil
+}

+ 1 - 10
app/dao/selection_info_dao.go

@@ -22,15 +22,6 @@ func (d SelectionInfoDAO) GetSelectionInfoById(selectionId string) (*entity.Sele
 	return &selectionInfo, err
 }
 
-//func (d SelectionInfoDAO) UpdateSelectionInfoById(id int, enterpriseId string) {
-//	Db.Model(&entity.SelectionInfo{}).Where("id = ?", id).Update("enterprise_id", enterpriseId)
-//}
-
-//func (d SelectionInfoDAO) DeleteSelectionInfoById(id int) error {
-//	err := Db.Delete(&entity.SelectionInfo{}, id).Error
-//	return err
-//}
-
 // 根据enterpriseId查询指定某天的所有带货数据
 func (d SelectionInfoDAO) GetSelectionInfoListOfDay(enterpriseId string, date time.Time) ([]entity.SelectionInfo, error) {
 	var selectionInfos []entity.SelectionInfo
@@ -46,7 +37,7 @@ func (d SelectionInfoDAO) GetSelectionInfoListOfDay(enterpriseId string, date ti
 }
 
 func (d SelectionInfoDAO) CreateSelectionInfo(selectionInfo entity.SelectionInfo) error {
-	err := Db.Omit("task_ddl", "submit_at", "pass_at", "auto_fail_at").Create(&selectionInfo).Error
+	err := Db.Omit("task_ddl", "submit_at", "pass_at", "pay_at", "finish_at", "auto_fail_at").Create(&selectionInfo).Error
 	if err != nil {
 		return err
 	}

+ 27 - 0
app/entity/info_pricing_strategy.go

@@ -0,0 +1,27 @@
+// Code generated by sql2gorm. DO NOT EDIT.
+package entity
+
+import (
+	"time"
+)
+
+type InfoPricingStrategy struct {
+	ID            int64     `gorm:"column:id;primary_key;AUTO_INCREMENT"` //  id
+	ProjectType   int64     `gorm:"column:project_type;NOT NULL"`         // 项目类型,0表示不限,1为全流程项目
+	StrategyId    string    `gorm:"column:strategyId;NOT NULL"`           // 定价策略编号
+	FeeForm       int64     `gorm:"column:fee_form;NOT NULL"`             // 稿费形式,1,2,3分别代表产品置换、固定稿费、自报价
+	Platform      int64     `gorm:"column:platform;NOT NULL"`             // 项目平台,1-7分别代表红book、抖音、微博、快手、b站、大众点评、知乎
+	FansLow       int64     `gorm:"column:fans_low;NOT NULL"`             // 对应粉丝量下限
+	FansUp        int64     `gorm:"column:fans_up;NOT NULL"`              // 对应粉丝量上限
+	ServiceCharge float64   `gorm:"column:service_charge"`                // 服务费,稿费形式为产品置换时填写,可以为空
+	BaseOffer     float64   `gorm:"column:base_offer"`                    // 基础报价
+	Status        int64     `gorm:"column:status;NOT NULL"`               // 定价策略当前状态,0表示正常,1表示禁用
+	ServiceRate   int64     `gorm:"column:service_rate"`                  // 服务费率*1000,稿费形式为固定稿费和自报价时填写,可以为空
+	UpdateID      int64     `gorm:"column:update_id"`                     // 修改管理人员id,对应user表中主键
+	UpdateAt      time.Time `gorm:"column:update_at"`                     // 修改时间
+	CreateAt      time.Time `gorm:"column:create_at;NOT NULL"`            // 创建时间
+}
+
+func (m *InfoPricingStrategy) TableName() string {
+	return "info_pricing_strategy"
+}

+ 47 - 0
app/entity/project.go

@@ -0,0 +1,47 @@
+// Code generated by sql2gorm. DO NOT EDIT.
+package entity
+
+import (
+	"time"
+)
+
+type Project struct {
+	ProjectId         string    `gorm:"column:project_id;primary_key;"`        // 项目id 项目ID生成规则:年(2位)+一年中的第几天(3位)+5位数随机数,雪花算法也可,生成10位订单号
+	ProjectName       string    `gorm:"column:project_name"`                   // 项目名称
+	ProjectStatus     int64     `gorm:"column:project_status"`                 // 项目状态,1-10分别代表创建中、待审核、审核通过、招募中、招募完毕、待支付、已支付、失效、执行中、已结案
+	ProjectType       int64     `gorm:"column:project_type"`                   // 项目类型,1代表全流程项目,2代表专项项目
+	ProjectPlatform   int64     `gorm:"column:project_platform"`               // 项目平台,1-7分别代表红book、抖音、微博、快手、b站、大众点评、知乎
+	ProjectForm       int64     `gorm:"column:project_form"`                   // 项目形式,1-4分别代表实体商品寄拍、虚拟产品测评、线下探店打卡、素材微原创
+	TalentType        string    `gorm:"column:talent_type"`                    // 达人类型
+	RecruitDdl        time.Time `gorm:"column:recruit_ddl"`                    // 招募截止时间
+	ContentType       int64     `gorm:"column:content_type"`                   // 内容形式,1代表图文,2代表视频
+	ProjectDetail     string    `gorm:"column:project_detail"`                 // 项目详情
+	ApplyNum          int64     `gorm:"column:apply_num;default:0;NOT NULL"`   // 报名人数
+	RecruitNum        int64     `gorm:"column:recruit_num;default:0;NOT NULL"` // 已招募人数
+	EnterpriseID      string    `gorm:"column:enterprise_id"`                  // 所属企业id
+	SubAccountId      int64     `gorm:"column:sub_account_id"`                 // 子账号id
+	ProductID         int64     `gorm:"column:product_id"`                     // 关联商品id
+	CreatedAt         time.Time `gorm:"column:created_at"`                     // 创建时间
+	UpdatedAt         time.Time `gorm:"column:updated_at"`                     // 修改时间
+	FeeForm           string    `gorm:"column:fee_form"`                       // 稿费形式列表
+	AutoFailAt        time.Time `gorm:"column:auto_fail_at"`                   // 失效自动处理时间
+	AutoTaskID        int64     `gorm:"column:auto_task_id;NOT NULL"`          // 定时任务id
+	AutoDefaultID     int64     `gorm:"column:auto_default_id;NOT NULL"`       // 违约状态id
+	PaymentAmount     float64   `gorm:"column:payment_amount"`                 // 支付金额
+	PayAt             time.Time `gorm:"column:pay_at"`                         // 支付时间
+	AutoScriptBreakAt time.Time `gorm:"column:auto_script_break_at"`           // 脚本违约自动处理时间
+	AutoSketchBreakAt time.Time `gorm:"column:auto_sketch_break_at"`           // 初稿违约自动处理时间
+	FailReason        int64     `gorm:"column:fail_reason"`                    // 失效原因,1、2分别表示逾期未支付、项目存在风险
+	PassAt            time.Time `gorm:"column:pass_at"`                        // 审核通过时间
+	FinishAt          time.Time `gorm:"column:finish_at"`                      // 结案时间
+	SubmitAt          time.Time `gorm:"column:submit_at"`                      // 结案时间
+	EstimatedCost     float64   `gorm:"column:estimated_cost"`                 // 预估成本
+	IsRead            int64     `gorm:"column:is_read"`                        // 是否已读
+	SettlementAmount  float64   `gorm:"column:settlement_amount"`              // 结算金额
+	ProductSnap       string    `gorm:"column:product_snap"`                   // 商品信息快照
+	ProductPhotoSnap  string    `gorm:"column:product_photo_snap"`             // 商品图片快照
+}
+
+func (m *Project) TableName() string {
+	return "project_info"
+}

+ 19 - 0
app/entity/project_brief.go

@@ -0,0 +1,19 @@
+// Code generated by sql2gorm. DO NOT EDIT.
+package entity
+
+import (
+	"time"
+)
+
+type ProjectBrief struct {
+	ProjectBriefID int64     `gorm:"column:project_brief_id;primary_key;AUTO_INCREMENT"` // 项目id
+	FileUrl        string    `gorm:"column:file_url"`                                    // 图片url
+	FileName       string    `gorm:"column:file_name"`                                   // 文件名称
+	FileUid        string    `gorm:"column:file_uid"`
+	ProjectID      string    `gorm:"column:project_id"` // 所属项目id
+	CreatedAt      time.Time `gorm:"column:created_at"` // 创建时间
+}
+
+func (m *ProjectBrief) TableName() string {
+	return "project_brief"
+}

+ 16 - 0
app/entity/project_material.go

@@ -0,0 +1,16 @@
+package entity
+
+import "time"
+
+type ProjectMaterial struct {
+	MaterialID int       `gorm:"column:material_id;primary_key;AUTO_INCREMENT"` // 种草任务素材id
+	FileUrl    string    `gorm:"column:file_url"`                               // 文件url
+	FileUid    string    `gorm:"column:file_uid"`                               // 文件uid
+	ProjectID  string    `gorm:"column:project_id"`                             // 所属项目id
+	CreatedAt  time.Time `gorm:"column:created_at"`                             // 创建时间
+	FileName   string    `gorm:"column:file_name"`                              // 文件名称
+}
+
+func (m *ProjectMaterial) TableName() string {
+	return "project_material"
+}

+ 32 - 0
app/entity/recruit_strategy.go

@@ -0,0 +1,32 @@
+// Code generated by sql2gorm. DO NOT EDIT.
+package entity
+
+type RecruitStrategy struct {
+	RecruitStrategyID int64   `gorm:"column:recruit_strategy_id;primary_key;AUTO_INCREMENT"` // 招募策略id
+	FeeForm           int64   `gorm:"column:fee_form"`                                       // 稿费形式,1-3分别代表产品置换、固定稿费、自报价
+	StrategyID        int64   `gorm:"column:strategy_id"`                                    // 策略id
+	FollowersLow      int64   `gorm:"column:followers_low"`                                  // 达人粉丝数下限
+	FollowersUp       int64   `gorm:"column:followers_up"`                                   // 达人粉丝数上限
+	RecruitNumber     int64   `gorm:"column:recruit_number"`                                 // 招募数量
+	Offer             float64 `gorm:"column:offer"`                                          // 报价
+	TOffer            float64 `gorm:"column:t_offer"`                                        // 达人所见报价
+	ProjectID         string  `gorm:"column:project_id"`                                     // 所属项目id
+	ServiceCharge     float64 `gorm:"column:service_charge"`                                 // 平台服务费,稿费形式为产品置换时必填
+	SelectedNumber    int64   `gorm:"column:selected_number;default:0"`                      // 已选数量,被企业选择的达人数量
+	WaitingNumber     int64   `gorm:"column:waiting_number;default:0"`                       // 待发货
+	DeliveredNumber   int64   `gorm:"column:delivered_number;default:0"`                     // 已发货
+	SignedNumber      int64   `gorm:"column:signed_number;default:0"`                        // 已签收
+	MaxOffer          int64   `gorm:"column:max_offer;default:0"`                            // 报价上限
+	MinOffer          int64   `gorm:"column:min_offer;default:0"`                            // 报价下限
+	FanNumber         int64   `gorm:"column:fan_number;default:0"`                           // 总粉丝量
+	PlayNumber        int64   `gorm:"column:play_number;default:0"`                          // 总播放量
+	LikeNumber        int64   `gorm:"column:like_number;default:0"`                          // 总点赞数
+	CollectNumber     int64   `gorm:"column:collect_number;default:0"`                       // 总收藏量
+	CommentNumber     int64   `gorm:"column:comment_number;default:0"`                       // 总评论数
+	FinishNumber      int64   `gorm:"column:finish_number;default:0"`                        // 结案数量
+	TotalOffer        float64 `gorm:"column:total_offer;default:0"`                          // 支付合计
+}
+
+func (m *RecruitStrategy) TableName() string {
+	return "recruit_strategy"
+}

+ 9 - 9
app/entity/sec_example.go → app/entity/sec_material.go

@@ -2,15 +2,15 @@ package entity
 
 import "time"
 
-type SecExample struct {
-	ExampleID   int       `gorm:"column:example_id;primary_key;AUTO_INCREMENT"` // 选品示例图id
-	FileUrl     string    `gorm:"column:file_url"`                              // 文件url
-	FileUid     string    `gorm:"column:file_uid"`                              // 文件uid
-	SelectionID string    `gorm:"column:selection_id"`                          // 所属项目id
-	CreatedAt   time.Time `gorm:"column:created_at"`                            // 创建时间
-	FileName    string    `gorm:"column:file_name"`                             // 文件名称
+type SecMaterial struct {
+	MaterialID  int       `gorm:"column:material_id;primary_key;AUTO_INCREMENT"` // 带货任务素材id
+	FileUrl     string    `gorm:"column:file_url"`                               // 文件url
+	FileUid     string    `gorm:"column:file_uid"`                               // 文件uid
+	SelectionID string    `gorm:"column:selection_id"`                           // 所属项目id
+	CreatedAt   time.Time `gorm:"column:created_at"`                             // 创建时间
+	FileName    string    `gorm:"column:file_name"`                              // 文件名称
 }
 
-func (m *SecExample) TableName() string {
-	return "younggee_sec_example"
+func (m *SecMaterial) TableName() string {
+	return "younggee_sec_material"
 }

+ 34 - 33
app/entity/selection_info.go

@@ -7,39 +7,40 @@ import (
 )
 
 type SelectionInfo struct {
-	SelectionID      string     `gorm:"column:selection_id;primary_key"` // 选品项目id
-	SelectionName    string     `gorm:"column:selection_name"`           // 任务名称
-	EnterpriseID     string     `gorm:"column:enterprise_id"`            // 所属企业id
-	ProductID        int64      `gorm:"column:product_id"`               // 关联商品id
-	ContentType      int64      `gorm:"column:content_type"`             // 内容形式,1代表图文,2代表视频,3代表直播
-	SelectionStatus  int64      `gorm:"column:selection_status"`         // 选品项目状态,1-8分别代表创建中、待审核、审核通过、待支付、已支付、执行中、失效、已结案
-	TaskMode         int64      `gorm:"column:task_mode"`                // 任务形式,1、2分别表示悬赏任务、纯佣带货
-	Platform         int64      `gorm:"column:platform"`                 // 项目平台,1-7分别代表小红书、抖音、微博、快手、b站、大众点评、知乎
-	SampleMode       int64      `gorm:"column:sample_mode"`              // 领样形式,1、2分别表示免费领样、垫付领样
-	ProductUrl       string     `gorm:"column:product_url"`              // 带货链接
-	SampleNum        int64      `gorm:"column:sample_num"`               // 样品数量
-	RemainNum        int64      `gorm:"column:remain_num"`               // 剩余数量
-	CommissionRate   float64    `gorm:"column:commission_rate"`          // 佣金比例
-	EstimatedCost    float64    `gorm:"column:estimated_cost"`           // 预估成本
-	TaskReward       float64    `gorm:"column:task_reward"`              // 任务悬赏
-	SampleCondition  string     `gorm:"column:sample_condition"`         // 领样条件
-	RewardCondition  string     `gorm:"column:reward_condition"`         // 返现悬赏条件
-	SettlementAmount float64    `gorm:"column:settlement_amount"`        // 结算金额
-	TaskDdl          time.Time  `gorm:"column:task_ddl"`                 // 招募截止时间
-	Detail           string     `gorm:"column:detail"`                   // 卖点总结
-	ProductSnap      string     `gorm:"column:product_snap"`             // 商品信息快照
-	ProductPhotoSnap string     `gorm:"column:product_photo_snap"`       // 商品图片快照
-	CreatedAt        time.Time  `gorm:"column:created_at"`               // 创建时间
-	UpdatedAt        time.Time  `gorm:"column:updated_at"`               // 修改时间
-	SubmitAt         time.Time  `gorm:"column:submit_at"`                // 提交审核时间
-	PassAt           time.Time  `gorm:"column:pass_at"`                  // 审核通过时间
-	FailReason       int64      `gorm:"column:fail_reason"`              // 失效原因,1、2分别表示逾期未支付、项目存在风险
-	PayAt            *time.Time `gorm:"column:pay_at"`                   // 支付时间
-	FinishAt         *time.Time `gorm:"column:finish_at"`                // 结案时间
-	IsRead           int64      `gorm:"column:is_read"`                  // 是否已读
-	AutoTaskID       int64      `gorm:"column:auto_task_id"`             // 定时任务id
-	AutoFailAt       time.Time  `gorm:"column:auto_fail_at"`             // 失效自动处理时间
-	Status           int64      `gorm:"column:status"`                   // 选品是否删除 2代表删除
+	SelectionID      string    `gorm:"column:selection_id;primary_key"` // 选品项目id
+	SelectionName    string    `gorm:"column:selection_name"`           // 任务名称
+	EnterpriseID     string    `gorm:"column:enterprise_id"`            // 所属企业id
+	SubAccountId     int64     `gorm:"column:sub_account_id"`           // 子账号id
+	ProductID        int64     `gorm:"column:product_id"`               // 关联商品id
+	ContentType      int64     `gorm:"column:content_type"`             // 内容形式,1代表图文,2代表视频,3代表直播
+	SelectionStatus  int64     `gorm:"column:selection_status"`         // 选品项目状态,1-8分别代表创建中、待审核、审核通过、待支付、已支付、执行中、失效、已结案
+	TaskMode         int64     `gorm:"column:task_mode"`                // 任务形式,1、2分别表示悬赏任务、纯佣带货
+	Platform         int64     `gorm:"column:platform"`                 // 项目平台,1-7分别代表小红书、抖音、微博、快手、b站、大众点评、知乎
+	SampleMode       int64     `gorm:"column:sample_mode"`              // 领样形式,1、2分别表示免费领样、垫付领样
+	ProductUrl       string    `gorm:"column:product_url"`              // 带货链接
+	SampleNum        int64     `gorm:"column:sample_num"`               // 样品数量
+	RemainNum        int64     `gorm:"column:remain_num"`               // 剩余数量
+	CommissionRate   float64   `gorm:"column:commission_rate"`          // 佣金比例
+	EstimatedCost    float64   `gorm:"column:estimated_cost"`           // 预估成本
+	TaskReward       float64   `gorm:"column:task_reward"`              // 任务悬赏
+	SampleCondition  string    `gorm:"column:sample_condition"`         // 领样条件
+	RewardCondition  string    `gorm:"column:reward_condition"`         // 返现悬赏条件
+	SettlementAmount float64   `gorm:"column:settlement_amount"`        // 结算金额
+	TaskDdl          time.Time `gorm:"column:task_ddl"`                 // 招募截止时间
+	Detail           string    `gorm:"column:detail"`                   // 卖点总结
+	ProductSnap      string    `gorm:"column:product_snap"`             // 商品信息快照
+	ProductPhotoSnap string    `gorm:"column:product_photo_snap"`       // 商品图片快照
+	CreatedAt        time.Time `gorm:"column:created_at"`               // 创建时间
+	UpdatedAt        time.Time `gorm:"column:updated_at"`               // 修改时间
+	SubmitAt         time.Time `gorm:"column:submit_at"`                // 提交审核时间
+	PassAt           time.Time `gorm:"column:pass_at"`                  // 审核通过时间
+	FailReason       int64     `gorm:"column:fail_reason"`              // 失效原因,1、2分别表示逾期未支付、项目存在风险
+	PayAt            time.Time `gorm:"column:pay_at"`                   // 支付时间
+	FinishAt         time.Time `gorm:"column:finish_at"`                // 结案时间
+	IsRead           int64     `gorm:"column:is_read"`                  // 是否已读
+	AutoTaskID       int64     `gorm:"column:auto_task_id"`             // 定时任务id
+	AutoFailAt       time.Time `gorm:"column:auto_fail_at"`             // 失效自动处理时间
+	Status           int64     `gorm:"column:status"`                   // 选品是否删除 2代表删除
 }
 
 func (m *SelectionInfo) TableName() string {

+ 421 - 0
app/service/project_service.go

@@ -0,0 +1,421 @@
+package service
+
+import (
+	"encoding/json"
+	"errors"
+	"github.com/issue9/conv"
+	"github.com/sirupsen/logrus"
+	"reflect"
+	"time"
+	"youngee_b_api/app/dao"
+	"youngee_b_api/app/entity"
+	"youngee_b_api/app/util"
+	"youngee_b_api/app/vo"
+)
+
+type ProjectService struct{}
+
+// 创建种草任务
+func (s ProjectService) CreateProject(param *vo.ProjectCreateParam) (*string, error) {
+	// a) 生成种草项目id
+	projectId := util.GetProjectID()
+	// b) 查找关联商品信息
+	product, err := dao.ProductDAO{}.GetProductByID(conv.MustInt64(param.ProductId, 0))
+	if err != nil {
+		return nil, err
+	}
+	if product == nil {
+		return nil, errors.New("未找到关联商品")
+	}
+	productPhotos, err := dao.ProductPhotoDAO{}.GetProductPhotoByProductID(param.ProductId)
+	productInfoToJson, _ := json.Marshal(product)
+	productPhotosToJson, _ := json.Marshal(productPhotos)
+	// d)创建种草任务
+	t := time.Now()
+	newProject := entity.Project{
+		ProjectStatus:    1,
+		ProjectType:      param.ProjectType,
+		ProjectId:        projectId,
+		ProductID:        param.ProductId,
+		EnterpriseID:     param.EnterpriseId,
+		SubAccountId:     param.SubAccountId,
+		ProjectPlatform:  param.Platform,
+		ProductSnap:      string(productInfoToJson),
+		ProductPhotoSnap: string(productPhotosToJson),
+		CreatedAt:        t,
+		UpdatedAt:        t,
+		EstimatedCost:    0,
+		SettlementAmount: 0,
+	}
+	err = dao.ProjectDAO{}.CreateProject(newProject)
+	if err != nil {
+		return nil, err
+	}
+
+	return &projectId, nil
+}
+
+// 更新公开种草任务(招募要求、执行要求)
+func (s ProjectService) UpdateProject(projectUpdateParam *vo.ProjectUpdateParam) (*string, error) {
+	// 1. 检查该企业id和商品id有无种草任务
+	projectID := projectUpdateParam.ProjectID
+	project, err := dao.ProjectDAO{}.GetProjectById(projectID)
+	if err != nil {
+		return nil, err
+	}
+	if project == nil {
+		return nil, errors.New("种草项目不存在")
+	}
+	// 2. 数据准备
+	// a) 查找关联商品信息
+	product, err := dao.ProductDAO{}.GetProductByID(project.ProductID)
+	if err != nil {
+		return nil, err
+	}
+	productPhotos, err := dao.ProductPhotoDAO{}.GetProductPhotoByProductID(project.ProductID)
+	productInfoToJson, _ := json.Marshal(product)
+	productPhotosToJson, _ := json.Marshal(productPhotos)
+	// d) 任务截止时间
+	recruitDdl := time.Time{} //赋零值
+	recruitDdl, _ = time.ParseInLocation("2006-01-02 15:04:05", projectUpdateParam.RecruitDdl, time.Local)
+	// f) 更新选品状态
+	if projectUpdateParam.ProjectStatus != 2 && projectUpdateParam.ProjectStatus != 8 {
+		projectUpdateParam.ProjectStatus = 1
+	}
+	t := time.Now()
+	updateProject := entity.Project{
+		EnterpriseID:     projectUpdateParam.EnterpriseId,
+		SubAccountId:     projectUpdateParam.SubAccountId,
+		ProjectId:        projectUpdateParam.ProjectID,
+		ProjectType:      projectUpdateParam.ProjectType,
+		ProjectStatus:    projectUpdateParam.ProjectStatus,
+		ProjectName:      projectUpdateParam.ProjectName,
+		ProductID:        projectUpdateParam.ProductId,
+		TalentType:       projectUpdateParam.TalentType,
+		RecruitDdl:       recruitDdl,
+		ProductSnap:      string(productInfoToJson),
+		ProductPhotoSnap: string(productPhotosToJson),
+		CreatedAt:        project.CreatedAt,
+		UpdatedAt:        t,
+		ProjectForm:      projectUpdateParam.ProjectForm,
+		ContentType:      projectUpdateParam.ContentType,
+		ProjectDetail:    projectUpdateParam.ProjectDetail,
+	}
+	if projectUpdateParam.ProjectStatus == 2 {
+		updateProject.SubmitAt = t
+	}
+	// 合并传入参数和数据表中原记录,若传入参数字段值为空,则将字段赋值为原记录中值
+	result := util.MergeStructValue(&updateProject, project)
+	// 利用反射机制将interface类型转换为结构体类型
+	v := reflect.ValueOf(&result).Elem()
+	if v.Kind() == reflect.Struct {
+		updateProject = v.Interface().(entity.Project)
+		//fmt.Println(p)
+	}
+	// c) 计算预估成本(如果有)
+	/*
+		var estimatedCost float64
+		if conv.MustInt(updateSelection.TaskMode, 0) == 1 {
+			estimatedCost = conv.MustFloat64(updateSelection.TaskReward, 0) * conv.MustFloat64(updateSelection.SampleNum, 0)
+		}
+		estimatedCostToString, _ := conv.String(estimatedCost)
+		updateSelection.EstimatedCost = estimatedCostToString
+	*/
+	// 3. 更新选品
+	err = dao.ProjectDAO{}.UpdateProject(updateProject)
+	if err != nil {
+		return nil, err
+	}
+	// 4. 更新选品brief和示例(种草任务补充信息)
+	if projectUpdateParam.ProjectBrief != nil {
+		// 删除已有brief
+		err = dao.ProjectBriefDao{}.DeleteSecBriefBySelectionId(project.ProjectId)
+		if err != nil {
+			return nil, err
+		}
+		// 插入新的brief
+		for _, v := range projectUpdateParam.ProjectBrief {
+			brief := entity.ProjectBrief{
+				ProjectID: project.ProjectId,
+				FileUid:   v.FileUid,
+				FileName:  v.Name,
+				FileUrl:   v.FileUrl,
+				CreatedAt: time.Now(),
+			}
+			err = dao.ProjectBriefDao{}.CreateProjectBrief(brief)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	if projectUpdateParam.ProjectMaterial != nil {
+		// 删除已有示例
+		err = dao.ProjectMaterialDao{}.DeleteProjectMaterialByProjectId(project.ProjectId)
+		if err != nil {
+			return nil, err
+		}
+		// 插入新的示例
+		for _, v := range projectUpdateParam.ProjectMaterial {
+			projectMaterial := entity.ProjectMaterial{
+				ProjectID: project.ProjectId,
+				FileUid:   v.FileUid,
+				FileName:  v.Name,
+				FileUrl:   v.FileUrl,
+				CreatedAt: time.Now(),
+			}
+			err = dao.ProjectMaterialDao{}.CreateProjectMaterial(projectMaterial)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	println("更新种草任务的招募策略")
+	// 更新种草任务的招募策略
+	if projectUpdateParam.RecruitStrategys != nil {
+		// 1. 删除已有的招募策略
+		err = dao.RecruitStrategyDao{}.DeleteRecruitStrategyByProjectID(projectUpdateParam.ProjectID)
+		if err != nil {
+			return nil, err
+		}
+		// 2. 接收并创建新的招募策略
+		if len(projectUpdateParam.RecruitStrategys) != 0 {
+			var recruits []entity.RecruitStrategy
+			for _, strategy := range projectUpdateParam.RecruitStrategys {
+				// 查询对应定价策略
+				pricingStrategy, err := dao.InfoPricingStrategylDao{}.GetPricingStrategy(strategy.FollowersLow, strategy.FollowersUp, strategy.FeeForm, project.ProjectPlatform)
+				if err != nil {
+					return nil, err
+				}
+				// 根据定价策略计算达人所见报价
+				if strategy.FeeForm == 2 {
+					strategy.TOffer = strategy.Offer * (1 - conv.MustFloat64(pricingStrategy.ServiceRate)/1000)
+				}
+				recruitStrategy := entity.RecruitStrategy{
+					FeeForm:       conv.MustInt64(strategy.FeeForm),
+					StrategyID:    conv.MustInt64(strategy.StrategyID),
+					FollowersLow:  conv.MustInt64(strategy.FollowersLow),
+					FollowersUp:   conv.MustInt64(strategy.FollowersUp),
+					RecruitNumber: conv.MustInt64(strategy.RecruitNumber),
+					ServiceCharge: strategy.ServiceCharge,
+					Offer:         strategy.Offer,
+					TOffer:        strategy.TOffer,
+					ProjectID:     project.ProjectId,
+				}
+				//fmt.Printf("Offer:\t %+v", Strategy.Offer)
+				recruits = append(recruits, recruitStrategy)
+			}
+			err = dao.RecruitStrategyDao{}.CreateRecruitStrategy(recruits)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return &updateProject.ProjectId, nil
+}
+
+// 更新定向种草任务(招募要求、执行要求)
+func (s ProjectService) UpdateProjectTarget(projectUpdateParam *vo.ProjectUpdateParam) (*string, error) {
+	// 1. 检查该企业id和商品id有无种草任务
+	projectID := projectUpdateParam.ProjectID
+	project, err := dao.ProjectDAO{}.GetProjectById(projectID)
+	if err != nil {
+		return nil, err
+	}
+	if project == nil {
+		return nil, errors.New("种草项目不存在")
+	}
+	// 2. 数据准备
+	// a) 查找关联商品信息
+	product, err := dao.ProductDAO{}.GetProductByID(project.ProductID)
+	if err != nil {
+		return nil, err
+	}
+	productPhotos, err := dao.ProductPhotoDAO{}.GetProductPhotoByProductID(project.ProductID)
+	productInfoToJson, _ := json.Marshal(product)
+	productPhotosToJson, _ := json.Marshal(productPhotos)
+	// d) 任务截止时间
+	recruitDdl := time.Time{} //赋零值
+	recruitDdl, _ = time.ParseInLocation("2006-01-02 15:04:05", projectUpdateParam.RecruitDdl, time.Local)
+	// f) 更新选品状态
+	if projectUpdateParam.ProjectStatus != 2 && projectUpdateParam.ProjectStatus != 8 {
+		projectUpdateParam.ProjectStatus = 1
+	}
+	t := time.Now()
+	updateProject := entity.Project{
+		EnterpriseID:     projectUpdateParam.EnterpriseId,
+		SubAccountId:     projectUpdateParam.SubAccountId,
+		ProjectId:        projectUpdateParam.ProjectID,
+		ProjectType:      projectUpdateParam.ProjectType,
+		ProjectStatus:    projectUpdateParam.ProjectStatus,
+		ProjectName:      projectUpdateParam.ProjectName,
+		ProductID:        projectUpdateParam.ProductId,
+		TalentType:       projectUpdateParam.TalentType,
+		RecruitDdl:       recruitDdl,
+		ProductSnap:      string(productInfoToJson),
+		ProductPhotoSnap: string(productPhotosToJson),
+		CreatedAt:        project.CreatedAt,
+		UpdatedAt:        t,
+		ProjectForm:      projectUpdateParam.ProjectForm,
+		ContentType:      projectUpdateParam.ContentType,
+		ProjectDetail:    projectUpdateParam.ProjectDetail,
+	}
+	if projectUpdateParam.ProjectStatus == 2 {
+		updateProject.SubmitAt = t
+	}
+	// 合并传入参数和数据表中原记录,若传入参数字段值为空,则将字段赋值为原记录中值
+	result := util.MergeStructValue(&updateProject, project)
+	// 利用反射机制将interface类型转换为结构体类型
+	v := reflect.ValueOf(&result).Elem()
+	if v.Kind() == reflect.Struct {
+		updateProject = v.Interface().(entity.Project)
+		//fmt.Println(p)
+	}
+	// c) 计算预估成本(如果有)
+	/*
+		var estimatedCost float64
+		if conv.MustInt(updateSelection.TaskMode, 0) == 1 {
+			estimatedCost = conv.MustFloat64(updateSelection.TaskReward, 0) * conv.MustFloat64(updateSelection.SampleNum, 0)
+		}
+		estimatedCostToString, _ := conv.String(estimatedCost)
+		updateSelection.EstimatedCost = estimatedCostToString
+	*/
+	// 3. 更新选品
+	err = dao.ProjectDAO{}.UpdateProject(updateProject)
+	if err != nil {
+		return nil, err
+	}
+	// 4. 更新选品brief和示例(种草任务补充信息)
+	if projectUpdateParam.ProjectBrief != nil {
+		// 删除已有brief
+		err = dao.ProjectBriefDao{}.DeleteSecBriefBySelectionId(project.ProjectId)
+		if err != nil {
+			return nil, err
+		}
+		// 插入新的brief
+		for _, v := range projectUpdateParam.ProjectBrief {
+			brief := entity.ProjectBrief{
+				ProjectID: project.ProjectId,
+				FileUid:   v.FileUid,
+				FileName:  v.Name,
+				FileUrl:   v.FileUrl,
+				CreatedAt: time.Now(),
+			}
+			err = dao.ProjectBriefDao{}.CreateProjectBrief(brief)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	if projectUpdateParam.ProjectMaterial != nil {
+		// 删除已有示例
+		err = dao.ProjectMaterialDao{}.DeleteProjectMaterialByProjectId(project.ProjectId)
+		if err != nil {
+			return nil, err
+		}
+		// 插入新的示例
+		for _, v := range projectUpdateParam.ProjectMaterial {
+			projectMaterial := entity.ProjectMaterial{
+				ProjectID: project.ProjectId,
+				FileUid:   v.FileUid,
+				FileName:  v.Name,
+				FileUrl:   v.FileUrl,
+				CreatedAt: time.Now(),
+			}
+			err = dao.ProjectMaterialDao{}.CreateProjectMaterial(projectMaterial)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	println("更新种草任务的招募策略")
+	// 更新种草任务的招募策略
+	if projectUpdateParam.RecruitStrategys != nil {
+		// 1. 删除已有的招募策略
+		err = dao.RecruitStrategyDao{}.DeleteRecruitStrategyByProjectID(projectUpdateParam.ProjectID)
+		if err != nil {
+			return nil, err
+		}
+		// 2. 接收并创建新的招募策略
+		if len(projectUpdateParam.RecruitStrategys) != 0 {
+			var recruits []entity.RecruitStrategy
+			for _, strategy := range projectUpdateParam.RecruitStrategys {
+				//// 查询对应定价策略
+				//pricingStrategy, err := dao.InfoPricingStrategylDao{}.GetPricingStrategy(strategy.FollowersLow, strategy.FollowersUp, strategy.FeeForm, project.ProjectPlatform)
+				//if err != nil {
+				//	return nil, err
+				//}
+				//// 根据定价策略计算达人所见报价
+				//if strategy.FeeForm == 2 {
+				//	strategy.TOffer = strategy.Offer * (1 - conv.MustFloat64(pricingStrategy.ServiceRate)/1000)
+				//}
+				recruitStrategy := entity.RecruitStrategy{
+					FeeForm:      conv.MustInt64(strategy.FeeForm),
+					StrategyID:   conv.MustInt64(strategy.StrategyID),
+					FollowersLow: conv.MustInt64(strategy.FollowersLow),
+					FollowersUp:  conv.MustInt64(strategy.FollowersUp),
+					//ServiceCharge: strategy.ServiceCharge,
+					Offer: strategy.Offer,
+					//TOffer:    strategy.TOffer,
+					ProjectID: project.ProjectId,
+				}
+				//fmt.Printf("Offer:\t %+v", Strategy.Offer)
+				recruits = append(recruits, recruitStrategy)
+			}
+			err = dao.RecruitStrategyDao{}.CreateRecruitStrategy(recruits)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return &updateProject.ProjectId, nil
+}
+
+// 种草任务预览
+func (s ProjectService) GetProjectDetail(projectId string) (*vo.ReProjectDetail, error) {
+	projectDetail := vo.ReProjectDetail{}
+	project, err := dao.ProjectDAO{}.GetProjectById(projectId)
+	if err != nil {
+		logrus.Errorf("[projectDB service] call GetProject error,err:%+v", err)
+		return nil, err
+	}
+	projectBriefInfos, err := dao.ProjectBriefDao{}.GetProjectBriefInfo(projectId)
+	if err != nil {
+		logrus.Errorf("[projectDB service] call GetProjectBriefInfo error,err:%+v", err)
+		return nil, err
+	}
+	projectMaterials, err := dao.ProjectMaterialDao{}.GetProjectMaterialInfo(projectId)
+	if err != nil {
+		logrus.Errorf("[projectDB service] call GetprojectMaterialInfo error,err:%+v", err)
+		return nil, err
+	}
+	productInfo, err := dao.ProductDAO{}.GetProductByProjectId(projectId)
+	if err != nil {
+		logrus.Errorf("[projectDB service] call GetProductInfo error,err:%+v", err)
+		return nil, err
+	}
+	productPhotos, err := dao.ProductPhotoDAO{}.GetProductPhotosByProjectId(projectId)
+	if err != nil {
+		logrus.Errorf("[projectDB service] call GetProductPhotoInfo error,err:%+v", err)
+		return nil, err
+	}
+	// 查找招募策略
+	recruitStrategys, err := dao.RecruitStrategyDao{}.GetRecruitStrategyByProjectId(projectId)
+	if err != nil {
+		logrus.Errorf("[projectDB service] call GetRecruitStrategy error,err:%+v", err)
+		return nil, err
+	}
+	projectDetail.ProjectBriefs = projectBriefInfos
+	projectDetail.Project = project
+	projectDetail.ProjectMaterials = projectMaterials
+	projectDetail.ProductInfo = productInfo
+	projectDetail.ProductPhotos = productPhotos
+	projectDetail.RecruitStrategys = recruitStrategys
+	return &projectDetail, nil
+
+}

+ 16 - 15
app/service/selection_info_service.go

@@ -75,6 +75,7 @@ func (s SelectionInfoService) CreateSelectionInfo(param *vo.SelectionInfoCreateP
 		SelectionID:      selectionId,
 		ProductID:        param.ProductId,
 		EnterpriseID:     param.EnterpriseId,
+		SubAccountId:     param.SubAccountId,
 		Platform:         param.Platform,
 		ProductSnap:      string(productInfoToJson),
 		ProductPhotoSnap: string(productPhotosToJson),
@@ -126,10 +127,10 @@ func (s SelectionInfoService) UpdateSelectionInfo(selectionUpdateParam *vo.Selec
 		SelectionStatus: selectionUpdateParam.SelectionStatus,
 		SelectionName:   selectionUpdateParam.SelectionName,
 		EnterpriseID:    selectionUpdateParam.EnterpriseId,
+		SubAccountId:    selectionUpdateParam.SubAccountId,
 		ProductID:       selectionUpdateParam.ProductId,
 		//ContentType: selectionUpdateParam.ContentType,
-		TaskMode: selectionUpdateParam.TaskMode,
-		//Platform:         selectionUpdateParam.Platform,
+		TaskMode:         selectionUpdateParam.TaskMode,
 		SampleMode:       selectionUpdateParam.SampleMode,
 		ProductUrl:       selectionUpdateParam.ProductUrl,
 		SampleNum:        selectionUpdateParam.SampleNum,
@@ -187,9 +188,9 @@ func (s SelectionInfoService) UpdateSelectionInfo(selectionUpdateParam *vo.Selec
 		for _, v := range selectionUpdateParam.SecBrief {
 			brief := entity.SecBrief{
 				SelectionID: selectionInfo.SelectionID,
-				FileUid:     v.PhotoUid,
+				FileUid:     v.FileUid,
 				FileName:    v.Name,
-				FileUrl:     v.PhotoUrl,
+				FileUrl:     v.FileUrl,
 				CreatedAt:   time.Now(),
 			}
 			err = dao.SecBriefDao{}.CreateSecBrief(brief)
@@ -199,22 +200,22 @@ func (s SelectionInfoService) UpdateSelectionInfo(selectionUpdateParam *vo.Selec
 		}
 	}
 
-	if selectionUpdateParam.SecExample != nil {
+	if selectionUpdateParam.SecMaterial != nil {
 		// 删除已有示例
-		err = dao.SecExampleDao{}.DeleteSecExampleBySelectionId(selectionInfo.SelectionID)
+		err = dao.SecMaterialDao{}.DeleteSecMaterialBySelectionId(selectionInfo.SelectionID)
 		if err != nil {
 			return nil, err
 		}
 		// 插入新的示例
-		for _, v := range selectionUpdateParam.SecExample {
-			secExample := entity.SecExample{
+		for _, v := range selectionUpdateParam.SecMaterial {
+			secMaterial := entity.SecMaterial{
 				SelectionID: selectionInfo.SelectionID,
-				FileUid:     v.PhotoUid,
+				FileUid:     v.FileUid,
 				FileName:    v.Name,
-				FileUrl:     v.PhotoUrl,
+				FileUrl:     v.FileUrl,
 				CreatedAt:   time.Now(),
 			}
-			err = dao.SecExampleDao{}.CreateSecExample(secExample)
+			err = dao.SecMaterialDao{}.CreateSecMaterial(secMaterial)
 			if err != nil {
 				return nil, err
 			}
@@ -282,7 +283,7 @@ func (s SelectionInfoService) UpdateSelectionInfo(selectionUpdateParam *vo.Selec
 }
 
 // 电商带货任务预览
-func (s SelectionInfoService) GetSelectionDetail(selectionId string, enterpriseId string) (*vo.ReSelectionDetail, error) {
+func (s SelectionInfoService) GetSelectionDetail(selectionId string) (*vo.ReSelectionDetail, error) {
 	selectionDetail := vo.ReSelectionDetail{}
 	selectionInfo, err := dao.SelectionInfoDAO{}.GetSelectionInfoById(selectionId)
 	if err != nil {
@@ -294,9 +295,9 @@ func (s SelectionInfoService) GetSelectionDetail(selectionId string, enterpriseI
 		logrus.Errorf("[selectionDB service] call GetSelectionBriefInfo error,err:%+v", err)
 		return nil, err
 	}
-	selectionExamples, err := dao.SecExampleDao{}.GetSelectionExampleInfo(selectionId)
+	selectionMaterials, err := dao.SecMaterialDao{}.GetSelectionMaterialInfo(selectionId)
 	if err != nil {
-		logrus.Errorf("[selectionDB service] call GetSelectionExampleInfo error,err:%+v", err)
+		logrus.Errorf("[selectionDB service] call GetSelectionMaterialInfo error,err:%+v", err)
 		return nil, err
 	}
 	productInfo, err := dao.ProductDAO{}.GetProductBySelectionId(selectionId)
@@ -324,7 +325,7 @@ func (s SelectionInfoService) GetSelectionDetail(selectionId string, enterpriseI
 
 	selectionDetail.SelectionBriefs = selectionBriefInfos
 	selectionDetail.SelectionInfo = selectionInfo
-	selectionDetail.SelectionExamples = selectionExamples
+	selectionDetail.SelectionMaterials = selectionMaterials
 	selectionDetail.ProductInfo = productInfo
 	selectionDetail.ProductPhotos = productPhotos
 	selectionDetail.FreeStrategys = freeStrategys

+ 13 - 0
app/util/uuid.go

@@ -36,3 +36,16 @@ func GetSelectionID() string {
 	selectionId := conv.MustString(time.Now().Year())[2:] + td + conv.MustString(rand.Intn(100000-10000)+10000)
 	return selectionId
 }
+
+func GetProjectID() string {
+	rand.Seed(time.Now().UnixNano())
+	td := conv.MustString(time.Now().Day())
+	for {
+		if len(td) == 3 {
+			break
+		}
+		td = "0" + td
+	}
+	selectionId := conv.MustString(time.Now().Year())[2:] + td + conv.MustString(rand.Intn(100000-10000)+10000)
+	return selectionId
+}

+ 9 - 0
app/vo/project_create_param.go

@@ -0,0 +1,9 @@
+package vo
+
+type ProjectCreateParam struct {
+	EnterpriseId string `json:"enterprise_id"`
+	SubAccountId int64  `json:"sub_account_id"`
+	Platform     int64  `json:"platform"`
+	ProductId    int64  `json:"product_id"`
+	ProjectType  int64  `json:"project_type"` // 项目类型,1代表全流程项目,2代表专项项目
+}

+ 44 - 0
app/vo/project_update_param.go

@@ -0,0 +1,44 @@
+package vo
+
+type ProjectUpdateParam struct {
+	EnterpriseId     string                  `json:"enterprise_id"`
+	SubAccountId     int64                   `json:"sub_account_id"`
+	ProjectID        string                  `json:"project_id"`
+	ProductId        int64                   `json:"product_id"`
+	ProjectType      int64                   `json:"project_type"`      // 项目类型,1代表全流程项目,2代表专项项目
+	ProjectStatus    int64                   `json:"project_status"`    // 项目状态,1-10分别代表创建中、待审核、审核通过、招募中、招募完毕、待支付、已支付、失效、执行中、已结案
+	ProjectName      string                  `json:"task_name"`         // 项目名称(任务标题)
+	TalentType       string                  `json:"talent_type"`       // 达人类型
+	RecruitDdl       string                  `json:"recruit_ddl"`       // 招募截止时间
+	RecruitStrategys []CreateRecruitStrategy `json:"recruit_strategys"` // 招募策略
+
+	ProjectForm     int64                  `json:"project_form"`   // 项目形式,1-4分别代表实体商品寄拍、虚拟产品测评、线下探店打卡、素材微原创
+	ContentType     int64                  `json:"content_type"`   // 内容形式,1代表图文,2代表视频
+	ProjectDetail   string                 `json:"project_detail"` // 项目详情
+	ProjectBrief    []*ProjectBriefInfo    `json:"project_brief"`
+	ProjectMaterial []*ProjectMaterialInfo `json:"project_material"`
+}
+
+type ProjectBriefInfo struct {
+	FileUrl string `json:"file_url"`
+	FileUid string `json:"file_uid"`
+	Name    string `json:"name"`
+}
+
+type ProjectMaterialInfo struct {
+	FileUrl string `json:"file_url"`
+	FileUid string `json:"file_uid"`
+	Name    string `json:"name"`
+}
+
+// 招募策略
+type CreateRecruitStrategy struct {
+	StrategyID    int64   `json:"strategy_id"`    // 策略id
+	FeeForm       int64   `json:"fee_form"`       // 稿费形式,1-3分别代表自报价、一口价、产品置换
+	FollowersLow  int64   `json:"followers_low"`  // 达人粉丝数下限
+	FollowersUp   int64   `json:"followers_up"`   // 达人粉丝数上限
+	RecruitNumber int64   `json:"recruit_number"` // 招募数量
+	Offer         float64 `json:"offer"`          // 报价
+	TOffer        float64 `json:"t_offer"`        // 达人所见报价
+	ServiceCharge float64 `json:"service_charge"` // 服务费
+}

+ 14 - 0
app/vo/re_project_detail.go

@@ -0,0 +1,14 @@
+package vo
+
+import (
+	"youngee_b_api/app/entity"
+)
+
+type ReProjectDetail struct {
+	Project          *entity.Project           // 选品详情
+	ProjectBriefs    []*entity.ProjectBrief    // 选品brief列表
+	ProjectMaterials []*entity.ProjectMaterial // 选品示例列表
+	ProductInfo      *entity.Product           // 商品详情
+	ProductPhotos    []*entity.ProductPhoto    // 商品图片列表
+	RecruitStrategys []*entity.RecruitStrategy // 招募策略
+}

+ 7 - 7
app/vo/re_selection_detail.go

@@ -5,11 +5,11 @@ import (
 )
 
 type ReSelectionDetail struct {
-	SelectionInfo     *entity.SelectionInfo    // 选品详情
-	SelectionBriefs   []*entity.SecBrief       // 选品brief列表
-	SelectionExamples []*entity.SecExample     // 选品示例列表
-	ProductInfo       *entity.Product          // 商品详情
-	ProductPhotos     []*entity.ProductPhoto   // 商品图片列表
-	FreeStrategys     []*entity.FreeStrategy   // 免费领样策略
-	RewardStrategys   []*entity.RewardStrategy // 悬赏策略
+	SelectionInfo      *entity.SelectionInfo    // 选品详情
+	SelectionBriefs    []*entity.SecBrief       // 选品brief列表
+	SelectionMaterials []*entity.SecMaterial    // 选品示例列表
+	ProductInfo        *entity.Product          // 商品详情
+	ProductPhotos      []*entity.ProductPhoto   // 商品图片列表
+	FreeStrategys      []*entity.FreeStrategy   // 免费领样策略
+	RewardStrategys    []*entity.RewardStrategy // 悬赏策略
 }

+ 8 - 8
app/vo/re_task_product.go

@@ -3,12 +3,12 @@ package vo
 import "time"
 
 type ReTaskProduct struct {
-	ProductID     int64     `json:"product_id"`
-	ProductName   string    `json:"product_name"`
-	ProductType   string    `json:"product_type"`
-	ProductPrice  float64   `json:"product_price"`
-	ProductDetail string    `json:"product_detail"`
-	CreatedAt     time.Time `json:"created_at"`
-	BrandName     string    `json:"brand_name"`
-	PhotoUrl      string    `json:"photo_url"`
+	ProductID     int64     `json:"productId"`
+	ProductName   string    `json:"productName"`
+	ProductType   string    `json:"productType"`
+	ProductPrice  float64   `json:"productPrice"`
+	ProductDetail string    `json:"productDetail"`
+	CreatedAt     time.Time `json:"createdAt"`
+	BrandName     string    `json:"brandName"`
+	PhotoUrl      string    `json:"photoUrl"`
 }

+ 14 - 13
app/vo/selection_info_update_param.go

@@ -1,12 +1,11 @@
 package vo
 
 type SelectionInfoUpdateParam struct {
-	SelectionID     string `json:"selection_id"`     // 选品id
-	SelectionStatus int64  `json:"selection_status"` // 选品项目状态,1-8分别代表创建中、待审核、审核通过、待支付、已支付、执行中、失效、已结案
-	ProductId       int64  `json:"product_id"`
 	EnterpriseId    string `json:"enterprise_id"`
-	SubAccountId    int    `json:"sub_account_id"`
-	//Platform        int64 `json:"platform"`
+	SubAccountId    int64  `json:"sub_account_id"`
+	SelectionID     string `json:"selection_id"` // 选品id
+	ProductId       int64  `json:"product_id"`
+	SelectionStatus int64  `json:"selection_status"` // 选品项目状态,1-8分别代表创建中、待审核、审核通过、待支付、已支付、执行中、失效、已结案
 	//ContentType      int64                   `json:"content_type"`	// 内容形式,1图文,2视频,3直播
 	SelectionName   string                  `json:"task_name"`        // 任务名称
 	TaskDdl         string                  `json:"task_ddl"`         // 招募截止时间
@@ -14,7 +13,7 @@ type SelectionInfoUpdateParam struct {
 	RewardStrategys []UpdateRewardStrategys `json:"reward_strategys"` // 悬赏策略
 	SampleNum       int64                   `json:"sample_num"`       // 样品数量
 	SecBrief        []*SecBriefInfo         `json:"sec_brief"`
-	SecExample      []*SecExampleInfo       `json:"sec_example"`
+	SecMaterial     []*SecMaterialInfo      `json:"sec_material"`
 
 	TaskMode         int64   `json:"task_mode"`         // 任务形式,1悬赏任务 2纯佣带货
 	RemainNum        int64   `json:"remain_num"`        // 剩余数量
@@ -30,17 +29,18 @@ type SelectionInfoUpdateParam struct {
 }
 
 type SecBriefInfo struct {
-	PhotoUrl string `json:"photo_url"`
-	PhotoUid string `json:"photo_uid"`
-	Name     string `json:"name"`
+	FileUrl string `json:"file_url"`
+	FileUid string `json:"file_uid"`
+	Name    string `json:"name"`
 }
 
-type SecExampleInfo struct {
-	PhotoUrl string `json:"photo_url"`
-	PhotoUid string `json:"photo_uid"`
-	Name     string `json:"name"`
+type SecMaterialInfo struct {
+	FileUrl string `json:"file_url"`
+	FileUid string `json:"file_uid"`
+	Name    string `json:"name"`
 }
 
+// 领样策略
 type UpdateFreeStrategys struct {
 	StrategyId int64 `json:"strategy_id"` // 策略编号
 	FansNum    int64 `json:"fans_num"`    // 粉丝数目
@@ -49,6 +49,7 @@ type UpdateFreeStrategys struct {
 	ChooseNum  int64 `json:"choose_num"`  // 已选人数
 }
 
+// 悬赏策略
 type UpdateRewardStrategys struct {
 	Reward     float64 `json:"reward"`      // 悬赏池总金额
 	SaleActual int64   `json:"sale_actual"` // 实际带货销量

+ 8 - 3
route/init.go

@@ -170,13 +170,18 @@ func InitRoute(r *gin.Engine) {
 	task := r.Group("/youngee/b/task")
 	{
 		task.Use(middleware.LoginAuthMiddleware)
-		task.POST("/product/findAll", controller.TaskController{}.GetAllProduct)       // 关联商品-已有商品展示
-		task.POST("/product/create", controller.TaskController{}.CreateProduct)        // 关联商品-新建商品
-		task.POST("/selection/create", controller.TaskController{}.CreateSelection)    // 关联商品-完成关联创建带货任务
+		task.POST("/product/findAll", controller.TaskController{}.GetAllProduct) // 关联商品-已有商品展示
+		task.POST("/product/create", controller.TaskController{}.CreateProduct)  // 关联商品-新建商品
+
+		task.POST("/selection/create", controller.TaskController{}.CreateSelection)    // 创建带货任务
 		task.POST("/selection/update", controller.TaskController{}.UpdateSelection)    // 更新带货任务(样品奖励、补充信息)
 		task.POST("/selection/detail", controller.TaskController{}.GetSelectionDetail) // 电商带货任务预览
 		task.POST("/selection/check", controller.TaskController{}.CheckSelectionInfo)  // 电商带货任务审核
 
+		task.POST("/project/create", controller.TaskController{}.CreateProject)              // 创建种草任务
+		task.POST("/project/update", controller.TaskController{}.UpdateProject)              // 更新种草任务
+		task.POST("/project/target/update", controller.TaskController{}.UpdateProjectTarget) // 更新定向种草任务
+		task.POST("/project/detail", controller.TaskController{}.GetProjectDetail)           // 电商带货任务预览
 	}
 
 }

+ 16 - 18
service/autoTask.go

@@ -9,24 +9,22 @@ import (
 
 func AutoTask() error {
 	c := cron.New(cron.WithSeconds())
-	spec := "0 * */10 * * ?" //cron表达式,每半小时执行一次
-	//spec := "0 */1 * * * ?" //cron表达式,每1分钟一次
-	//spec := "*/10 * * * * ?" //cron表达式,每10秒一次
-	_, err1 := c.AddFunc(spec, AutoTaskUpdateStatus)
-	if err1 != nil {
-		log.Println("service [AutoTaskUpdateStatus] error:", err1)
-		return err1
-	}
-	_, err2 := c.AddFunc("@midnight", AutoTaskUpdateApplyTimes)
-	if err2 != nil {
-		log.Println("service [AutoTaskUpdateApplyTimes] error:", err2)
-		return err2
-	}
-	_, err3 := c.AddFunc(spec, AutoTaskCompleteSelection)
-	if err3 != nil {
-		log.Println("service [AutoTaskCompleteSecTask] error:", err2)
-		return err3
-	}
+	//spec := "0 * */10 * * ?" //cron表达式,每半小时执行一次
+	//_, err1 := c.AddFunc(spec, AutoTaskUpdateStatus)
+	//if err1 != nil {
+	//	log.Println("service [AutoTaskUpdateStatus] error:", err1)
+	//	return err1
+	//}
+	//_, err2 := c.AddFunc("@midnight", AutoTaskUpdateApplyTimes)
+	//if err2 != nil {
+	//	log.Println("service [AutoTaskUpdateApplyTimes] error:", err2)
+	//	return err2
+	//}
+	//_, err3 := c.AddFunc(spec, AutoTaskCompleteSelection)
+	//if err3 != nil {
+	//	log.Println("service [AutoTaskCompleteSecTask] error:", err2)
+	//	return err3
+	//}
 	c.Start()
 	return nil
 }