Browse Source

feat: 收藏&物流

yankun 1 day ago
parent
commit
c63d9fb661
34 changed files with 1790 additions and 759 deletions
  1. 42 0
      app/api/youngee_talent_api/talent_auth_get_api.go
  2. 1 0
      app/model/model.go
  3. 18 1
      app/model/youngee_talent_model/local_info.go
  4. 1 0
      app/model/youngee_talent_model/project_info.go
  5. 47 47
      app/model/youngee_talent_model/selection_task.go
  6. 6 0
      app/model/youngee_talent_model/talent_info.go
  7. 125 110
      app/model/youngee_talent_model/task_info.go
  8. 22 20
      app/model/youngee_talent_model/task_sketch.go
  9. 22 0
      app/service/auto_task/auto_task.go
  10. 75 97
      app/service/youngee_sectask_service/seletion_square.go
  11. 23 2
      app/service/youngee_talent_service/talent_account.go
  12. 15 11
      app/service/youngee_talent_service/talent_info.go
  13. 5 11
      app/service/youngee_talent_service/talent_ks_auth.go
  14. 76 124
      app/service/youngee_task_service/local_life_info.go
  15. 84 143
      app/service/youngee_task_service/project_info.go
  16. 43 8
      app/service/youngee_task_service/task_book.go
  17. 42 43
      app/service/youngee_task_service/task_data.go
  18. 33 46
      app/service/youngee_task_service/task_info.go
  19. 6 1
      app/service/youngee_task_service/task_link.go
  20. 211 57
      app/service/youngee_task_service/task_logistics.go
  21. 11 5
      app/service/youngee_task_service/task_sketch.go
  22. 15 15
      app/system/sectask/sectask_service.go
  23. BIN
      bin/main
  24. BIN
      bin/v4.1.8/.DS_Store
  25. BIN
      bin/v4.1.9/.DS_Store
  26. BIN
      bin/v4.1.9/linux_amd64/youngmini_server
  27. 8 0
      config/config.toml
  28. 2 0
      main.go
  29. 18 18
      router/router.go
  30. 145 0
      vendor/github.com/gogf/gf/os/gcron/gcron.go
  31. 253 0
      vendor/github.com/gogf/gf/os/gcron/gcron_cron.go
  32. 175 0
      vendor/github.com/gogf/gf/os/gcron/gcron_entry.go
  33. 265 0
      vendor/github.com/gogf/gf/os/gcron/gcron_schedule.go
  34. 1 0
      vendor/modules.txt

+ 42 - 0
app/api/youngee_talent_api/talent_auth_get_api.go

@@ -342,6 +342,22 @@ func (*talentAuthGetApi) GetLocalTaskDetail(r *ghttp.Request) {
 	}
 }
 
+func (*talentAuthGetApi) GetTaskLogisticsNumber(r *ghttp.Request) {
+	res := youngee_task_service.GetTaskLogisticsNumber(r)
+	err := r.Response.WriteJson(res)
+	if err != nil {
+		panic("write response error")
+	}
+}
+
+func (*talentAuthGetApi) GetTaskLogisticsList(r *ghttp.Request) {
+	res := youngee_task_service.GetTaskLogisticsList(r)
+	err := r.Response.WriteJson(res)
+	if err != nil {
+		panic("write response error")
+	}
+}
+
 func (*talentAuthGetApi) GetTaskLogisticsInfo(r *ghttp.Request) {
 	res := youngee_task_service.GetTaskLogisticsInfo(r)
 	err := r.Response.WriteJson(res)
@@ -418,6 +434,15 @@ func (*talentAuthGetApi) GetUnsubmitTaskSketch(r *ghttp.Request) {
 	}
 }
 
+// GetUnSubmitTaskSketch 获取未处理的任探店时间
+func (*talentAuthGetApi) GetUnsubmitLocalTaskBook(r *ghttp.Request) {
+	res := youngee_task_service.GetUnSubmitLocalTaskBook(r)
+	err := r.Response.WriteJson(res)
+	if err != nil {
+		panic("write response error")
+	}
+}
+
 // GetTaskData 获取任务数据提交审阅记录
 // younggee_data_info
 func (*talentAuthGetApi) GetTaskData(r *ghttp.Request) {
@@ -700,6 +725,15 @@ func (*talentAuthGetApi) ProjectCollection(r *ghttp.Request) {
 	}
 }
 
+// 收藏/取消收藏种草项目
+func (*talentAuthGetApi) LocalCollection(r *ghttp.Request) {
+	res := youngee_task_service.LocalCollection(r)
+	err := r.Response.WriteJson(res)
+	if err != nil {
+		panic("write response error")
+	}
+}
+
 // 种草收藏列表,点击收藏卡片调用getdetail即可进入详情页
 func (*talentAuthGetApi) GetProjectCollectionList(r *ghttp.Request) {
 	res := youngee_sectask_service.GetProjectCollectionList(r)
@@ -709,6 +743,14 @@ func (*talentAuthGetApi) GetProjectCollectionList(r *ghttp.Request) {
 	}
 }
 
+func (*talentAuthGetApi) GetLocalCollectionList(r *ghttp.Request) {
+	res := youngee_sectask_service.GetLocalCollectionList(r)
+	err := r.Response.WriteJson(res)
+	if err != nil {
+		panic("write response error")
+	}
+}
+
 // 达人是否已收藏商品
 func (*talentAuthGetApi) IsSecCollection(r *ghttp.Request) {
 	res := youngee_talent_service.IsSecCollection(r)

+ 1 - 0
app/model/model.go

@@ -1052,6 +1052,7 @@ type YoungeeTaskLogistics struct {
 	AutoScriptBreakAt     *gtime.Time `orm:"auto_script_break_at"    json:"auto_script_break_at"`    // 脚本违约自动处理时间
 	AutoSketchBreakAt     *gtime.Time `orm:"auto_sketch_break_at"    json:"auto_sketch_break_at"`    // 初稿违约自动处理时间
 	Status                int         `orm:"status"                  json:"status"`                  // 签收状态,0为未签收,1为已签收
+	TaskType              int         `orm:"task_type"               json:"task_type"`               // 任务类型:1 带货 、2.种草 3 本地生活
 }
 
 // YounggeeAssignmentInfo is the golang structure for table younggee_assignment_info.

+ 18 - 1
app/model/youngee_talent_model/local_info.go

@@ -130,7 +130,7 @@ type LocalInfoDetail struct {
 	LocalInfoSupplier    *LocalInfoSupplier      //服务商提供的LocalInfo
 	ProjectBrief         []*ProjectBrief         `orm:"with:project_id=id"` // 项目brief图
 	ProjectMaterial      []*ProjectMaterial      `orm:"with:project_id=id"` // 项目brief图
-	YounggeeProductPhoto []*YounggeeProductPhoto `json:"younggee_product_photo"`
+	YounggeeProductPhoto []*YounggeeProductPhoto `orm:"with:store_id=store_id" json:"younggee_product_photo"`
 	YounggeeTeamBuying   *YounggeeTeamBuying     `orm:"with:team_buying_id=team_buying_id"`
 	//违约说明
 	DraftBreakTime    int `json:"draft_break_time"`    //初稿上传截止时间
@@ -139,6 +139,7 @@ type LocalInfoDetail struct {
 	LinkBreakPercent  int `json:"link_break_percent"`  //超时扣款比例
 	DataBreakTime     int `json:"data_break_time"`     //数据上传截止时间
 	DataBreakPercent  int `json:"data_break_percent"`  //超时扣款比例
+	IsCollected       int `json:"is_collected"`        //是否收藏
 
 }
 
@@ -180,6 +181,22 @@ type YounggeeTeamBuying struct {
 	SubAccountId       int         `json:"sub_account_id"`       // 商家子账号id
 }
 
+// 种草收藏表信息
+type LocalCollection struct {
+	gmeta.Meta   `orm:"younggee_project_collect_info"`
+	CollectionId int         `json:"collection_id"` // 主键自增长
+	TalentId     string      `json:"talent_id"`     //
+	LocalId      string      `json:"local_id"`
+	CreateTime   *gtime.Time `json:"create_time"`
+	Deleted      int         `json:"deleted"` //默认为0。0:收藏。1:取消收藏
+}
+
+// 展示种草收藏list
+type LocalCollectionInfoList struct {
+	Count               int                `json:"count"`
+	LocalCollectionList []*LocalInfoDetail `json:"LocalCollectionList"`
+}
+
 type LocalInfoList struct {
 	MaxPage    int `json:"max_page"`
 	LocalInfos []*YounggeeLocalLifeInfo

+ 1 - 0
app/model/youngee_talent_model/project_info.go

@@ -41,6 +41,7 @@ type ProjectInfo struct {
 	Enterprise           *Enterprise             `orm:"with:enterprise_id=enterprise_id"`
 	ProductSnap          string                  `orm:"product_snap"         json:"product_snap"`       // 商品信息快照
 	ProductPhotoSnap     string                  `orm:"product_photo_snap"   json:"product_photo_snap"` // 商品图片快照
+	AllRecruitNum        int                     `json:"all_recruit_num"`                               // 所有招募人数
 }
 
 // 种草收藏表信息

+ 47 - 47
app/model/youngee_talent_model/selection_task.go

@@ -33,53 +33,53 @@ type SignSecTaskResp struct {
 
 type SecTaskInfoDetail struct {
 	gmeta.Meta             `orm:"table:younggee_sec_task_info"`
-	Id                     int                          `orm:"id,primary"                json:"id"`           // 递增id
-	TaskId                 string                       `orm:"task_id"                   json:"task_id"`      // 选品任务id
-	SelectionId            string                       `orm:"selection_id"              json:"selection_id"` // 选品id
-	OpenId                 string                       `orm:"open_id"                   json:"open_id"`      //快手唯一标识
-	ProductId              string                       `orm:"product_id"                json:"product_id"`
-	TalentId               string                       `orm:"talent_id"                 json:"talent_id"`                 // 达人id
-	AccountId              int                          `orm:"account_id"                json:"account_id"`                // 账号id
-	PlatformId             int                          `orm:"platform_id"                json:"platform_id"`              // 平台id
-	TalentPlatformInfoSnap string                       `orm:"talent_platform_info_snap" json:"talent_platform_info_snap"` // 达人平台信息快照
-	TalentPersonalInfoSnap string                       `orm:"talent_personal_info_snap" json:"talent_personal_info_snap"` // 达人个人信息快照
-	TalentPostAddrSnap     string                       `orm:"talent_post_addr_snap"     json:"talent_post_addr_snap"`     // 收货地址快照
-	TaskReward             float64                      `orm:"task_reward"               json:"task_reward"`               // 达人赏金
-	TalentPayment          float64                      `orm:"talent_payment"            json:"talent_payment"`            // 达人垫付金额
-	IsPayPayment           int                          `orm:"is_pay_payment"            json:"is_pay_payment"`            // 企业是否返样品钱
-	IsPayReward            int                          `orm:"is_pay_reward"             json:"is_pay_reward"`             // 企业是否结算悬赏
-	TaskMode               int                          `orm:"task_mode"                 json:"task_mode"`                 // 任务形式,1、2分别表示悬赏任务、纯佣带货',
-	SampleMode             int                          `orm:"sample_mode"               json:"sample_mode"`               // 领样形式,1-3分别表示免费领样、垫付买样、不提供样品
-	TaskStatus             int                          `orm:"task_status"               json:"task_status"`               // 任务状态 1待选 2已选 3落选
-	TaskStage              int                          `orm:"task_stage"                json:"task_stage"`                // 任务阶段,详情见info_sec_task_stage表
-	CreateDate             *gtime.Time                  `orm:"create_date"               json:"create_date"`               // 创建时间
-	SelectDate             *gtime.Time                  `orm:"select_date"               json:"select_date"`               // 反选时间
-	DeliveryDate           *gtime.Time                  `orm:"delivery_date"             json:"delivery_date"`             // 发货时间
-	CompleteDate           *gtime.Time                  `orm:"complete_date"             json:"complete_date"`             // 结束时间
-	WithdrawDate           *gtime.Time                  `orm:"withdraw_date"             json:"withdraw_date"`             // 提现时间
-	CompleteStatus         int                          `orm:"complete_status"           json:"complete_status"`           // 结束方式 1未结束 2正常结束 3反选失败
-	LogisticsStatus        int                          `orm:"logistics_status"          json:"logistics_status"`          // 发货状态 1 待发货 2已发货 3 已签收
-	AssignmentStatus       uint                         `orm:"assignment_status"         json:"assignment_status"`         // 作业上传状态 1-5分别代表待添加、已添加、待修改、已修改、已通过
-	UpdateAt               *gtime.Time                  `orm:"update_at"                 json:"update_at"`                 // 更新时间
-	WithdrawStatus         int                          `orm:"withdraw_status"           json:"withdraw_status"`           // 提现状态,1-4分别代表不可提现、可提现、提现中、已提现
-	LeadTeamId             string                       `orm:"lead_team_id"              json:"lead_team_id"`              // 作为团长的young之团id,对应younggee_talent_team中的team_id字段
-	TeamId                 string                       `orm:"team_id"                   json:"team_id"`                   // 作为团员的young之团id,对应younggee_talent_team中的team_id字段
-	TeamIncome             int                          `orm:"team_income"               json:"team_income"`               // young之团团长现金收益
-	TeamPoint              int                          `orm:"team_point"                json:"team_point"`                // young之团团长积分收益
-	FansNum                int                          `orm:"fans_num"                json:"fans_num"`                    // 粉丝数
-	SaleNum                int                          `orm:"sale_num"                json:"sale_num"`                    // 30天橱窗销量
-	FreeStage              int                          `orm:"free_stage"                json:"free_stage"`                // 免费领样阶段,1-5分别代表已申请、已拒绝、待发货、已发货、已收货',
-	RewardStage            int                          `orm:"reward_stage"                json:"reward_stage"`            //悬赏阶段,1-2分别代表待结算、已结算',
-	SaleActual             int                          `orm:"sale_actual"                json:"sale_actual"`
-	SaleNumAll             int                          `orm:"sale_num_all"                json:"sale_num_all"` //达人对此商品的全部销售量(大于1表示已出单)
-	RewardStrategy         []*RewardStrategy            `orm:"with:selection_id=selection_id"`                  // 悬赏策略表
-	SelectionInfo          *model.YounggeeSelectionInfo `orm:"with:selection_id=selection_id"`                  //选品表
-	YounggeeProduct        *YounggeeProduct             `orm:"with:product_id=product_id"`                      // 商品基本表
-	YounggeeProductPhoto   []*YounggeeProductPhoto      `orm:"with:product_id=product_id"`                      // 商品图片表
-	PlatformInfo           *PlatformInfo                `orm:"with:platform_id=platform_id"`                    //platform_id=8的是快手平台信息,含有粉丝数和作品数
-	KsUserInfo             []*KuaishouUserInfo          `orm:"with:open_id=open_id"`
-	TaskDdl                *gtime.Time                  `json:"task_ddl"`
-	WxNum                  string                       `orm:"wx_num"                  json:"wx_num"`
+	Id                     int                     `orm:"id,primary"                json:"id"`           // 递增id
+	TaskId                 string                  `orm:"task_id"                   json:"task_id"`      // 选品任务id
+	SelectionId            string                  `orm:"selection_id"              json:"selection_id"` // 选品id
+	OpenId                 string                  `orm:"open_id"                   json:"open_id"`      //快手唯一标识
+	ProductId              string                  `orm:"product_id"                json:"product_id"`
+	TalentId               string                  `orm:"talent_id"                 json:"talent_id"`                 // 达人id
+	AccountId              int                     `orm:"account_id"                json:"account_id"`                // 账号id
+	PlatformId             int                     `orm:"platform_id"                json:"platform_id"`              // 平台id
+	TalentPlatformInfoSnap string                  `orm:"talent_platform_info_snap" json:"talent_platform_info_snap"` // 达人平台信息快照
+	TalentPersonalInfoSnap string                  `orm:"talent_personal_info_snap" json:"talent_personal_info_snap"` // 达人个人信息快照
+	TalentPostAddrSnap     string                  `orm:"talent_post_addr_snap"     json:"talent_post_addr_snap"`     // 收货地址快照
+	TaskReward             float64                 `orm:"task_reward"               json:"task_reward"`               // 达人赏金
+	TalentPayment          float64                 `orm:"talent_payment"            json:"talent_payment"`            // 达人垫付金额
+	IsPayPayment           int                     `orm:"is_pay_payment"            json:"is_pay_payment"`            // 企业是否返样品钱
+	IsPayReward            int                     `orm:"is_pay_reward"             json:"is_pay_reward"`             // 企业是否结算悬赏
+	TaskMode               int                     `orm:"task_mode"                 json:"task_mode"`                 // 任务形式,1、2分别表示悬赏任务、纯佣带货',
+	SampleMode             int                     `orm:"sample_mode"               json:"sample_mode"`               // 领样形式,1-3分别表示免费领样、垫付买样、不提供样品
+	TaskStatus             int                     `orm:"task_status"               json:"task_status"`               // 任务状态 1待选 2已选 3落选
+	TaskStage              int                     `orm:"task_stage"                json:"task_stage"`                // 任务阶段,详情见info_sec_task_stage表
+	CreateDate             *gtime.Time             `orm:"create_date"               json:"create_date"`               // 创建时间
+	SelectDate             *gtime.Time             `orm:"select_date"               json:"select_date"`               // 反选时间
+	DeliveryDate           *gtime.Time             `orm:"delivery_date"             json:"delivery_date"`             // 发货时间
+	CompleteDate           *gtime.Time             `orm:"complete_date"             json:"complete_date"`             // 结束时间
+	WithdrawDate           *gtime.Time             `orm:"withdraw_date"             json:"withdraw_date"`             // 提现时间
+	CompleteStatus         int                     `orm:"complete_status"           json:"complete_status"`           // 结束方式 1未结束 2正常结束 3反选失败
+	LogisticsStatus        int                     `orm:"logistics_status"          json:"logistics_status"`          // 发货状态 1 待发货 2已发货 3 已签收
+	AssignmentStatus       uint                    `orm:"assignment_status"         json:"assignment_status"`         // 作业上传状态 1-5分别代表待添加、已添加、待修改、已修改、已通过
+	UpdateAt               *gtime.Time             `orm:"update_at"                 json:"update_at"`                 // 更新时间
+	WithdrawStatus         int                     `orm:"withdraw_status"           json:"withdraw_status"`           // 提现状态,1-4分别代表不可提现、可提现、提现中、已提现
+	LeadTeamId             string                  `orm:"lead_team_id"              json:"lead_team_id"`              // 作为团长的young之团id,对应younggee_talent_team中的team_id字段
+	TeamId                 string                  `orm:"team_id"                   json:"team_id"`                   // 作为团员的young之团id,对应younggee_talent_team中的team_id字段
+	TeamIncome             int                     `orm:"team_income"               json:"team_income"`               // young之团团长现金收益
+	TeamPoint              int                     `orm:"team_point"                json:"team_point"`                // young之团团长积分收益
+	FansNum                int                     `orm:"fans_num"                json:"fans_num"`                    // 粉丝数
+	SaleNum                int                     `orm:"sale_num"                json:"sale_num"`                    // 30天橱窗销量
+	FreeStage              int                     `orm:"free_stage"                json:"free_stage"`                // 免费领样阶段,1-5分别代表已申请、已拒绝、待发货、已发货、已收货',
+	RewardStage            int                     `orm:"reward_stage"                json:"reward_stage"`            //悬赏阶段,1-2分别代表待结算、已结算',
+	SaleActual             int                     `orm:"sale_actual"                json:"sale_actual"`
+	SaleNumAll             int                     `orm:"sale_num_all"                json:"sale_num_all"` //达人对此商品的全部销售量(大于1表示已出单)
+	RewardStrategy         []*RewardStrategy       `orm:"with:selection_id=selection_id"`                  // 悬赏策略表
+	SelectionInfo          *SelectionInfo          `orm:"with:selection_id=selection_id"`                  //选品表
+	YounggeeProduct        *YounggeeProduct        `orm:"with:product_id=product_id"`                      // 商品基本表
+	YounggeeProductPhoto   []*YounggeeProductPhoto `orm:"with:product_id=product_id"`                      // 商品图片表
+	PlatformInfo           *PlatformInfo           `orm:"with:platform_id=platform_id"`                    //platform_id=8的是快手平台信息,含有粉丝数和作品数
+	KsUserInfo             []*KuaishouUserInfo     `orm:"with:open_id=open_id"`
+	TaskDdl                *gtime.Time             `json:"task_ddl"`
+	WxNum                  string                  `orm:"wx_num"                  json:"wx_num"`
 }
 
 type SecTaskInfoWindowDetail struct {

+ 6 - 0
app/model/youngee_talent_model/talent_info.go

@@ -23,6 +23,12 @@ type UpdateWxNameReq struct {
 	WxNum string `json:"wx_num"`
 }
 
+type YounggeeTalentCategory struct {
+	gmeta.Meta `orm:"table:younggee_talent_category"`
+	Id         int    `json:"id"`       // 主键id
+	Category   string `json:"category"` // 达人分类
+}
+
 type TalentInfo struct {
 	gmeta.Meta        `orm:"table:youngee_talent_info"`
 	Id                string      `json:"id"`                 // 达人id

+ 125 - 110
app/model/youngee_talent_model/task_info.go

@@ -34,67 +34,69 @@ import (
 //	}
 type YoungeeTaskInfo struct {
 	gmeta.Meta             `orm:"table:youngee_task_info"`
-	TaskId                 string         `json:"task_id"`    // 任务ID
-	ProjectId              string         `json:"project_id"` // 项目ID
-	TalentId               string         `json:"talent_id"`  // 达人ID
-	AccountId              int            `json:"account_id"` // 账号ID
-	PlatformId             int            `json:"platform_id"`
-	OpenId                 string         `json:"open_id"`                                            // 快手唯一标识
-	StrategyId             int            `json:"strategy_id"`                                        // 报名选择的招募策略ID
-	TalentPlatformInfoSnap string         `json:"talent_platform_info_snap"`                          // 达人平台信息快照
-	TalentPersonalInfoSnap string         `json:"talent_personal_info_snap"`                          // 达人个人信息快照
-	TalentPostAddrSnap     string         `json:"talent_post_addr_snap"`                              // 收货地址快照
-	TaskReward             float64        `json:"task_reward"`                                        // 达人报酬
-	SettleAmount           float64        `json:"settle_amount"`                                      // 达人实际所得(扣除违约扣款)
-	AllPayment             float64        `json:"all_payment"`                                        // 企业支付总额
-	RealPayment            float64        `json:"real_payment"`                                       // 企业实际支付(扣除违约扣款)
-	ServiceRate            float64        `json:"service_rate"`                                       // 服务费率(千分比)
-	ServiceCharge          float64        `json:"service_charge"`                                     // 服务费
-	FeeForm                int            `json:"fee_form"`                                           // 稿费形式 1: 产品置换 2: 固定稿费 3: 自报价
-	ErrBreakRate           int            `json:"err_break_rate"`                                     // 未上传类型违约扣款比例(百分比)
-	ScriptBreakRate        int            `json:"script_break_rate"`                                  // 脚本超时违约扣款比例(百分比)
-	SketchBreakRate        int            `json:"sketch_break_rate"`                                  // 初稿超时违约扣款比例(百分比)
-	LinkBreakRate          int            `json:"link_break_rate"`                                    // 链接超时违约扣款比例(百分比)
-	DataBreakRate          int            `json:"data_break_rate"`                                    // 数据超时违约扣款比例(百分比)
-	TaskStage              int            `json:"task_stage"`                                         // 任务阶段
-	TaskStatus             int            `json:"task_status"`                                        // 商家任务状态 1: 待选 2: 已选 3: 落选
-	LogisticsStatus        int            `json:"logistics_status"`                                   // 发货状态 1: 待发货 2: 已发货 3: 已签收
-	ScriptStatus           int            `json:"script_status"`                                      // 脚本上传状态 1-5 表示各阶段
-	SketchStatus           int            `json:"sketch_status"`                                      // 初稿上传状态 1-5 表示各阶段
-	LinkStatus             int            `json:"link_status"`                                        // 链接上传状态 1-5 表示各阶段
-	DataStatus             int            `json:"data_status"`                                        // 数据上传状态 1-5 表示各阶段
-	CompleteStatus         int            `json:"complete_status"`                                    // 结束方式 1: 未结束 2: 正常结束 3: 反选失败 4: 被解约
-	UpdateAt               *gtime.Time    `json:"update_at"`                                          // 更新时间
-	CreateDate             *gtime.Time    `json:"create_date"`                                        // 创建时间
-	SelectDate             *gtime.Time    `json:"select_date"`                                        // 反选时间
-	DeliveryDate           *gtime.Time    `json:"delivery_date"`                                      // 发货时间
-	CompleteDate           *gtime.Time    `json:"complete_date"`                                      // 结束时间
-	WithdrawDate           *gtime.Time    `json:"withdraw_date"`                                      // 提现时间
-	CurDefaultType         int            `json:"cur_default_type"`                                   // 当前处于的违约类型
-	WithdrawStatus         int            `json:"withdraw_status"`                                    // 提现状态 1-4 表示不同状态
-	LeadTeamId             string         `json:"lead_team_id"`                                       // 团长young之团ID
-	TeamId                 string         `json:"team_id"`                                            // 团员young之团ID
-	SettleStatus           int            `json:"settle_status"`                                      // 结算状态 1: 待结算 2: 已结算
-	TeamIncome             float64        `json:"team_income"`                                        // 团长现金收益
-	TeamPoint              int            `json:"team_point"`                                         // 团长积分收益
-	CurBreakAt             *gtime.Time    `json:"cur_break_at"`                                       // 当前阶段截止时间
-	SupplierId             int            `json:"supplier_id"`                                        // 服务商ID
-	SupplierStatus         int            `json:"supplier_status"`                                    // 服务商任务状态
-	DraftFee               float64        `json:"draft_fee"`                                          // 达人稿费
-	SupportFee             float64        `json:"support_fee"`                                        //提报价格
-	SignedTime             *gtime.Time    `json:"signed_time"`                                        // 签收时间
-	FansNum                int            `json:"fans_num"`                                           // 粉丝数
-	VoteAvg                int            `json:"vote_avg"`                                           // 平均点赞数
-	CommitAvg              int            `json:"commit_avg"`                                         // 平均评论数
-	BOperator              string         `json:"b_operator"`                                         // 商家确定达人操作人ID
-	BOperatorType          int            `json:"b_operator_type"`                                    // 商家操作人类型
-	SOperator              int            `json:"s_operator"`                                         // 服务商提报达人操作人ID
-	SOperatorType          int            `json:"s_operator_type"`                                    // 服务商操作人类型
-	SProjectId             int            `json:"s_project_id"`                                       // 服务商种草任务ID
-	ProjectDetail          *ProjectDetail `orm:"with:project_id = project_id " json:"project_detail"` //项目详情
-	WxNum                  string         `json:"wx_num"`
-	TalentName             string         `json:"talent_name"`    //达人昵称
-	SOperateName           string         `json:"s_operate_name"` //服务商昵称
+	TaskId                 string              `json:"task_id"`    // 任务ID
+	ProjectId              string              `json:"project_id"` // 项目ID
+	TalentId               string              `json:"talent_id"`  // 达人ID
+	AccountId              int                 `json:"account_id"` // 账号ID
+	PlatformId             int                 `json:"platform_id"`
+	OpenId                 string              `json:"open_id"`                                            // 快手唯一标识
+	StrategyId             int                 `json:"strategy_id"`                                        // 报名选择的招募策略ID
+	TalentPlatformInfoSnap string              `json:"talent_platform_info_snap"`                          // 达人平台信息快照
+	TalentPersonalInfoSnap string              `json:"talent_personal_info_snap"`                          // 达人个人信息快照
+	TalentPostAddrSnap     string              `json:"talent_post_addr_snap"`                              // 收货地址快照
+	TaskReward             float64             `json:"task_reward"`                                        // 达人报酬
+	SettleAmount           float64             `json:"settle_amount"`                                      // 达人实际所得(扣除违约扣款)
+	AllPayment             float64             `json:"all_payment"`                                        // 企业支付总额
+	RealPayment            float64             `json:"real_payment"`                                       // 企业实际支付(扣除违约扣款)
+	ServiceRate            float64             `json:"service_rate"`                                       // 服务费率(千分比)
+	ServiceCharge          float64             `json:"service_charge"`                                     // 服务费
+	FeeForm                int                 `json:"fee_form"`                                           // 稿费形式 1: 产品置换 2: 固定稿费 3: 自报价
+	ErrBreakRate           int                 `json:"err_break_rate"`                                     // 未上传类型违约扣款比例(百分比)
+	ScriptBreakRate        int                 `json:"script_break_rate"`                                  // 脚本超时违约扣款比例(百分比)
+	SketchBreakRate        int                 `json:"sketch_break_rate"`                                  // 初稿超时违约扣款比例(百分比)
+	LinkBreakRate          int                 `json:"link_break_rate"`                                    // 链接超时违约扣款比例(百分比)
+	DataBreakRate          int                 `json:"data_break_rate"`                                    // 数据超时违约扣款比例(百分比)
+	TaskStage              int                 `json:"task_stage"`                                         // 任务阶段
+	TaskStatus             int                 `json:"task_status"`                                        // 商家任务状态 1: 待选 2: 已选 3: 落选
+	LogisticsStatus        int                 `json:"logistics_status"`                                   // 发货状态 1: 待发货 2: 已发货 3: 已签收
+	ScriptStatus           int                 `json:"script_status"`                                      // 脚本上传状态 1-5 表示各阶段
+	SketchStatus           int                 `json:"sketch_status"`                                      // 初稿上传状态 1-5 表示各阶段
+	LinkStatus             int                 `json:"link_status"`                                        // 链接上传状态 1-5 表示各阶段
+	DataStatus             int                 `json:"data_status"`                                        // 数据上传状态 1-5 表示各阶段
+	CompleteStatus         int                 `json:"complete_status"`                                    // 结束方式 1: 未结束 2: 正常结束 3: 反选失败 4: 被解约
+	UpdateAt               *gtime.Time         `json:"update_at"`                                          // 更新时间
+	CreateDate             *gtime.Time         `json:"create_date"`                                        // 创建时间
+	SelectDate             *gtime.Time         `json:"select_date"`                                        // 反选时间
+	DeliveryDate           *gtime.Time         `json:"delivery_date"`                                      // 发货时间
+	CompleteDate           *gtime.Time         `json:"complete_date"`                                      // 结束时间
+	WithdrawDate           *gtime.Time         `json:"withdraw_date"`                                      // 提现时间
+	CurDefaultType         int                 `json:"cur_default_type"`                                   // 当前处于的违约类型
+	WithdrawStatus         int                 `json:"withdraw_status"`                                    // 提现状态 1-4 表示不同状态
+	LeadTeamId             string              `json:"lead_team_id"`                                       // 团长young之团ID
+	TeamId                 string              `json:"team_id"`                                            // 团员young之团ID
+	SettleStatus           int                 `json:"settle_status"`                                      // 结算状态 1: 待结算 2: 已结算
+	TeamIncome             float64             `json:"team_income"`                                        // 团长现金收益
+	TeamPoint              int                 `json:"team_point"`                                         // 团长积分收益
+	CurBreakAt             *gtime.Time         `json:"cur_break_at"`                                       // 当前阶段截止时间
+	SupplierId             int                 `json:"supplier_id"`                                        // 服务商ID
+	SupplierStatus         int                 `json:"supplier_status"`                                    // 服务商任务状态
+	DraftFee               float64             `json:"draft_fee"`                                          // 达人稿费
+	SupportFee             float64             `json:"support_fee"`                                        //提报价格
+	SignedTime             *gtime.Time         `json:"signed_time"`                                        // 签收时间
+	FansNum                int                 `json:"fans_num"`                                           // 粉丝数
+	VoteAvg                int                 `json:"vote_avg"`                                           // 平均点赞数
+	CommitAvg              int                 `json:"commit_avg"`                                         // 平均评论数
+	BOperator              string              `json:"b_operator"`                                         // 商家确定达人操作人ID
+	BOperatorType          int                 `json:"b_operator_type"`                                    // 商家操作人类型
+	SOperator              int                 `json:"s_operator"`                                         // 服务商提报达人操作人ID
+	SOperatorType          int                 `json:"s_operator_type"`                                    // 服务商操作人类型
+	SProjectId             int                 `json:"s_project_id"`                                       // 服务商种草任务ID
+	ProjectDetail          *ProjectDetail      `orm:"with:project_id = project_id " json:"project_detail"` //项目详情
+	WxNum                  string              `json:"wx_num"`
+	TalentName             string              `json:"talent_name"`    //达人昵称
+	SOperateName           string              `json:"s_operate_name"` //服务商昵称
+	ProjectType            int                 `json:"project_type"`   //项目类型 1.公开, 2,定向
+	KsUserInfo             []*KuaishouUserInfo `orm:"with:open_id=open_id"`
 }
 
 type YounggeeLocalTaskLog struct {
@@ -117,55 +119,57 @@ type YoungeeLocalTaskInfo struct {
 	TalentPlatformInfoSnap string `json:"talent_platform_info_snap"` // 达人平台信息快照
 	TalentPersonalInfoSnap string `json:"talent_personal_info_snap"` // 达人个人信息快照
 	//TalentPostAddrSnap     string         `json:"talent_post_addr_snap"`     // 收货地址快照
-	TaskReward      float64          `json:"task_reward"`                               // 达人报酬
-	SettleAmount    float64          `json:"settle_amount"`                             // 达人实际所得(扣除违约扣款)
-	AllPayment      float64          `json:"all_payment"`                               // 企业支付总额
-	RealPayment     float64          `json:"real_payment"`                              // 企业实际支付(扣除违约扣款)
-	ServiceRate     float64          `json:"service_rate"`                              // 服务费率(千分比)
-	ServiceCharge   float64          `json:"service_charge"`                            // 服务费
-	FeeForm         int              `json:"fee_form"`                                  // 稿费形式 1: 产品置换 2: 固定稿费 3: 自报价
-	ErrBreakRate    int              `json:"err_break_rate"`                            // 未上传类型违约扣款比例(百分比)
-	ScriptBreakRate int              `json:"script_break_rate"`                         // 脚本超时违约扣款比例(百分比)
-	SketchBreakRate int              `json:"sketch_break_rate"`                         // 初稿超时违约扣款比例(百分比)
-	LinkBreakRate   int              `json:"link_break_rate"`                           // 链接超时违约扣款比例(百分比)
-	DataBreakRate   int              `json:"data_break_rate"`                           // 数据超时违约扣款比例(百分比)
-	TaskStage       int              `json:"task_stage"`                                // 任务阶段
-	TaskStatus      int              `json:"task_status"`                               // 商家任务状态 1: 待选 2: 已选 3: 落选
-	LogisticsStatus int              `json:"logistics_status"`                          // 发货状态 1: 待发货 2: 已发货 3: 已签收
-	BookStatus      int              `json:"book_status"`                               // 脚本上传状态 1-5 表示各阶段
-	SketchStatus    int              `json:"sketch_status"`                             // 初稿上传状态 1-5 表示各阶段
-	LinkStatus      int              `json:"link_status"`                               // 链接上传状态 1-5 表示各阶段
-	DataStatus      int              `json:"data_status"`                               // 数据上传状态 1-5 表示各阶段
-	CompleteStatus  int              `json:"complete_status"`                           // 结束方式 1: 未结束 2: 正常结束 3: 反选失败 4: 被解约
-	UpdateAt        *gtime.Time      `json:"update_at"`                                 // 更新时间
-	CreateDate      *gtime.Time      `json:"create_date"`                               // 创建时间
-	SelectDate      *gtime.Time      `json:"select_date"`                               // 反选时间
-	DeliveryDate    *gtime.Time      `json:"delivery_date"`                             // 发货时间
-	CompleteDate    *gtime.Time      `json:"complete_date"`                             // 结束时间
-	WithdrawDate    *gtime.Time      `json:"withdraw_date"`                             // 提现时间
-	CurDefaultType  int              `json:"cur_default_type"`                          // 当前处于的违约类型
-	WithdrawStatus  int              `json:"withdraw_status"`                           // 提现状态 1-4 表示不同状态
-	LeadTeamId      string           `json:"lead_team_id"`                              // 团长young之团ID
-	TeamId          string           `json:"team_id"`                                   // 团员young之团ID
-	SettleStatus    int              `json:"settle_status"`                             // 结算状态 1: 待结算 2: 已结算
-	TeamIncome      float64          `json:"team_income"`                               // 团长现金收益
-	TeamPoint       int              `json:"team_point"`                                // 团长积分收益
-	CurBreakAt      *gtime.Time      `json:"cur_break_at"`                              // 当前阶段截止时间
-	SupplierId      int              `json:"supplier_id"`                               // 服务商ID
-	SupplierStatus  int              `json:"supplier_status"`                           // 服务商任务状态
-	DraftFee        float64          `json:"draft_fee"`                                 // 达人稿费
-	SupportFee      float64          `json:"support_fee"`                               //提报价格
-	SignedTime      *gtime.Time      `json:"signed_time"`                               // 签收时间
-	FansNum         int              `json:"fans_num"`                                  // 粉丝数
-	VoteAvg         int              `json:"vote_avg"`                                  // 平均点赞数
-	CommitAvg       int              `json:"commit_avg"`                                // 平均评论数
-	BOperator       string           `json:"b_operator"`                                // 商家确定达人操作人ID
-	BOperatorType   int              `json:"b_operator_type"`                           // 商家操作人类型
-	SOperator       int              `json:"s_operator"`                                // 服务商提报达人操作人ID
-	SOperatorType   int              `json:"s_operator_type"`                           // 服务商操作人类型
-	SProjectId      int              `json:"s_project_id"`                              // 服务商种草任务ID
-	LocalInfoDetail *LocalInfoDetail `orm:"with:local_id=local_id" json:"local_detail"` //项目详情
-	WxNum           string           `json:"wx_num"`
+	TaskReward      float64             `json:"task_reward"`                               // 达人报酬
+	SettleAmount    float64             `json:"settle_amount"`                             // 达人实际所得(扣除违约扣款)
+	AllPayment      float64             `json:"all_payment"`                               // 企业支付总额
+	RealPayment     float64             `json:"real_payment"`                              // 企业实际支付(扣除违约扣款)
+	ServiceRate     float64             `json:"service_rate"`                              // 服务费率(千分比)
+	ServiceCharge   float64             `json:"service_charge"`                            // 服务费
+	FeeForm         int                 `json:"fee_form"`                                  // 稿费形式 1: 产品置换 2: 固定稿费 3: 自报价
+	ErrBreakRate    int                 `json:"err_break_rate"`                            // 未上传类型违约扣款比例(百分比)
+	ScriptBreakRate int                 `json:"script_break_rate"`                         // 脚本超时违约扣款比例(百分比)
+	SketchBreakRate int                 `json:"sketch_break_rate"`                         // 初稿超时违约扣款比例(百分比)
+	LinkBreakRate   int                 `json:"link_break_rate"`                           // 链接超时违约扣款比例(百分比)
+	DataBreakRate   int                 `json:"data_break_rate"`                           // 数据超时违约扣款比例(百分比)
+	TaskStage       int                 `json:"task_stage"`                                // 任务阶段
+	TaskStatus      int                 `json:"task_status"`                               // 商家任务状态 1: 待选 2: 已选 3: 落选
+	LogisticsStatus int                 `json:"logistics_status"`                          // 发货状态 1: 待发货 2: 已发货 3: 已签收
+	BookStatus      int                 `json:"book_status"`                               // 脚本上传状态 1-5 表示各阶段
+	SketchStatus    int                 `json:"sketch_status"`                             // 初稿上传状态 1-5 表示各阶段
+	LinkStatus      int                 `json:"link_status"`                               // 链接上传状态 1-5 表示各阶段
+	DataStatus      int                 `json:"data_status"`                               // 数据上传状态 1-5 表示各阶段
+	CompleteStatus  int                 `json:"complete_status"`                           // 结束方式 1: 未结束 2: 正常结束 3: 反选失败 4: 被解约
+	UpdateAt        *gtime.Time         `json:"update_at"`                                 // 更新时间
+	CreateDate      *gtime.Time         `json:"create_date"`                               // 创建时间
+	SelectDate      *gtime.Time         `json:"select_date"`                               // 反选时间
+	DeliveryDate    *gtime.Time         `json:"delivery_date"`                             // 发货时间
+	CompleteDate    *gtime.Time         `json:"complete_date"`                             // 结束时间
+	WithdrawDate    *gtime.Time         `json:"withdraw_date"`                             // 提现时间
+	CurDefaultType  int                 `json:"cur_default_type"`                          // 当前处于的违约类型
+	WithdrawStatus  int                 `json:"withdraw_status"`                           // 提现状态 1-4 表示不同状态
+	LeadTeamId      string              `json:"lead_team_id"`                              // 团长young之团ID
+	TeamId          string              `json:"team_id"`                                   // 团员young之团ID
+	SettleStatus    int                 `json:"settle_status"`                             // 结算状态 1: 待结算 2: 已结算
+	TeamIncome      float64             `json:"team_income"`                               // 团长现金收益
+	TeamPoint       int                 `json:"team_point"`                                // 团长积分收益
+	CurBreakAt      *gtime.Time         `json:"cur_break_at"`                              // 当前阶段截止时间
+	SupplierId      int                 `json:"supplier_id"`                               // 服务商ID
+	SupplierStatus  int                 `json:"supplier_status"`                           // 服务商任务状态
+	DraftFee        float64             `json:"draft_fee"`                                 // 达人稿费
+	SupportFee      float64             `json:"support_fee"`                               //提报价格
+	SignedTime      *gtime.Time         `json:"signed_time"`                               // 签收时间
+	FansNum         int                 `json:"fans_num"`                                  // 粉丝数
+	VoteAvg         int                 `json:"vote_avg"`                                  // 平均点赞数
+	CommitAvg       int                 `json:"commit_avg"`                                // 平均评论数
+	BOperator       string              `json:"b_operator"`                                // 商家确定达人操作人ID
+	BOperatorType   int                 `json:"b_operator_type"`                           // 商家操作人类型
+	SOperator       int                 `json:"s_operator"`                                // 服务商提报达人操作人ID
+	SOperatorType   int                 `json:"s_operator_type"`                           // 服务商操作人类型
+	SProjectId      int                 `json:"s_project_id"`                              // 服务商种草任务ID
+	LocalInfoDetail *LocalInfoDetail    `orm:"with:local_id=local_id" json:"local_detail"` //项目详情
+	WxNum           string              `json:"wx_num"`
+	LocalType       int                 `json:"local_type"` // 1: 公开  2: 定向
+	KsUserInfo      []*KuaishouUserInfo `orm:"with:open_id=open_id"`
 }
 
 type SignTaskInfo struct {
@@ -297,3 +301,14 @@ type IsSignSecTask struct {
 	IsSign      int                `json:"is_sign"`
 	SecTaskInfo *SecTaskInfoDetail `json:"sec_task_info"`
 }
+
+// 物流页面展示不同的task
+type YoungeeGeneralTaskInfo struct {
+	TalentId    string            `json:"talent_id"`    // 达人ID
+	TaskName    string            `json:"task_name"`    // 任务名称
+	TaskPhoto   string            `json:"task_photo"`   // 任务图片
+	TaskPrice   float64           `json:"task_price"`   // 任务价格
+	AccountInfo *KuaishouUserInfo `json:"account_info"` //报名平台账号信息
+	SourceType  int               `json:"source_type"`  // 任务来源 1: 公开 2: 定向
+	TaskType    int               `json:"task_type"`    // 1:带货 2.种草 3,本地生活
+}

+ 22 - 20
app/model/youngee_talent_model/task_sketch.go

@@ -44,26 +44,7 @@ type TaskSketchInfo struct {
 	AutoLinkBreakAt   *gtime.Time            `orm:"auto_link_break_at"   json:"auto_link_break_at"`   // 链接违约自动处理时间
 	AutoSketchBreakAt *gtime.Time            `orm:"auto_sketch_break_at" json:"auto_sketch_break_at"` // 初稿违约自动处理时间
 	Photo             []*YounggeeSketchPhoto `orm:"with:sketch_id=sketch_id"`
-}
-
-type LocalTaskBookInfo struct {
-	gmeta.Meta        `orm:"table:younggee_book_info"`
-	BookId            int                  `orm:"book_id,primary" json:"sketch_id"`                 // 初稿id
-	TaskId            string               `orm:"task_id"           json:"task_id"`                 // 任务id
-	Day               string               `orm:"day"             json:"day"`                       // 标题
-	Time              string               `orm:"time"             json:"time"`                     // 标题
-	ReviseOpinion     string               `orm:"revise_opinion"    json:"revise_opinion"`          // 反馈意见
-	IsSubmit          int                  `orm:"is_submit"         json:"is_submit"`               // 是否提交
-	IsReview          int                  `orm:"is_review"         json:"is_review"`               // 是否审核
-	IsOk              int                  `orm:"is_ok"             json:"is_ok"`                   // 是否合格
-	CreateAt          *gtime.Time          `orm:"create_at"            json:"create_at"`            // 创建时间
-	AgreeAt           *gtime.Time          `orm:"agree_at"             json:"agree_at"`             // 同意时间
-	RejectAt          *gtime.Time          `orm:"reject_at"            json:"reject_at"`            // 驳回时间
-	SubmitAt          *gtime.Time          `orm:"submit_at"            json:"submit_at"`            // 提交时间
-	AutoAgreeAt       *gtime.Time          `orm:"auto_agree_at"        json:"auto_agree_at"`        // 初稿自动审核时间
-	AutoLinkBreakAt   *gtime.Time          `orm:"auto_link_break_at"   json:"auto_link_break_at"`   // 链接违约自动处理时间
-	AutoSketchBreakAt *gtime.Time          `orm:"auto_sketch_break_at" json:"auto_sketch_break_at"` // 初稿违约自动处理时间
-	Photo             []*YounggeeBookPhoto `orm:"with:book_id=book_id"`
+	ISEditable        int                    `json:"is_editable"` // 是否可编辑
 }
 
 type YounggeeSketchPhoto struct {
@@ -85,3 +66,24 @@ type YounggeeBookPhoto struct {
 	PhotoUid   string      `orm:"photo_uid"  json:"photo_uid"` //
 	CreateAt   *gtime.Time `orm:"create_at"  json:"create_at"` //
 }
+
+type LocalTaskBookInfo struct {
+	gmeta.Meta        `orm:"table:younggee_book_info"`
+	BookId            int         `orm:"book_id,primary" json:"sketch_id"`                 // 初稿id
+	TaskId            string      `orm:"task_id"           json:"task_id"`                 // 任务id
+	Day               string      `orm:"day"             json:"day"`                       // 标题
+	Time              string      `orm:"time"             json:"time"`                     // 标题
+	ReviseOpinion     string      `orm:"revise_opinion"    json:"revise_opinion"`          // 反馈意见
+	IsSubmit          int         `orm:"is_submit"         json:"is_submit"`               // 是否提交
+	IsReview          int         `orm:"is_review"         json:"is_review"`               // 是否审核
+	IsOk              int         `orm:"is_ok"             json:"is_ok"`                   // 是否合格
+	CreateAt          *gtime.Time `orm:"create_at"            json:"create_at"`            // 创建时间
+	AgreeAt           *gtime.Time `orm:"agree_at"             json:"agree_at"`             // 同意时间
+	RejectAt          *gtime.Time `orm:"reject_at"            json:"reject_at"`            // 驳回时间
+	SubmitAt          *gtime.Time `orm:"submit_at"            json:"submit_at"`            // 提交时间
+	AutoAgreeAt       *gtime.Time `orm:"auto_agree_at"        json:"auto_agree_at"`        // 初稿自动审核时间
+	AutoLinkBreakAt   *gtime.Time `orm:"auto_link_break_at"   json:"auto_link_break_at"`   // 链接违约自动处理时间
+	AutoSketchBreakAt *gtime.Time `orm:"auto_sketch_break_at" json:"auto_sketch_break_at"` // 初稿违约自动处理时间
+	//Photo             []*YounggeeBookPhoto `orm:"with:book_id=book_id"`
+	ISEditable int `json:"is_editable"` // 是否可编辑
+}

+ 22 - 0
app/service/auto_task/auto_task.go

@@ -0,0 +1,22 @@
+package auto_task
+
+import (
+	"fmt"
+	"github.com/gogf/gf/os/gcron"
+	"time"
+)
+
+// Init 定义任务
+func Init() {
+	// 定义第一个定时任务,每隔 1 分钟执行一次
+	gcron.Add("@every 1s", func() {
+		// 任务1:打印当前时间
+		fmt.Println("Task 1: 当前时间为", time.Now())
+	})
+
+	// 定义第二个定时任务,每隔 5 分钟执行一次
+	gcron.Add("@every 20s", func() {
+		// 任务2:打印一条消息
+		fmt.Println("Task 2: 每隔 5 分钟执行一次")
+	})
+}

+ 75 - 97
app/service/youngee_sectask_service/seletion_square.go

@@ -6,8 +6,8 @@ import (
 	"fmt"
 	"github.com/gogf/gf/database/gdb"
 	"github.com/lin-jim-leon/kuaishou/open/merchant"
-	"reflect"
 	"sort"
+	"strings"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/model"
 	"youngmini_server/app/model/youngee_talent_model"
@@ -47,115 +47,58 @@ func GetSelectionList(r *ghttp.Request) *TalentHttpResult {
 
 	pageIndex := r.GetQueryInt("idx", -1)
 	cntPerPage := r.GetQueryInt("cnt", -1)
+	//测试 多参数拼接
+	params := r.Get("testParam")
+	if params != nil {
+		categoryFormList := strings.Split(params.(string), ",")
+		// 现在categoryFormList是一个字符串数组,可以用于进一步处理
+		fmt.Println("切割后的参数:", categoryFormList)
+	}
 	//排序字段
 	sortField := r.GetString("sortField", "")  //根据哪个字段排序
 	orderTag := r.GetQueryInt("sortOrder", -1) //1降序,0升序
 	//领样和悬赏条件
-	secForm := r.Get("secform")
-	taskForm := r.Get("taskform")
+	secForm := r.Get("secform", nil)
+	taskForm := r.Get("taskform", nil)
 	//任务上线时间
-	createTime := r.Get("createtime")
-	fmt.Println("createTime:----》", createTime)
+	createTime := r.Get("createtime", nil)
 	//商品类目 智能家居、食品饮料等20种
-	categoryForm := r.Get("categoryform")
+	categoryForm := r.Get("categoryform", nil)
 	//搜索条件
-	searchValue := r.Get("searchvalue")
-
-	// 如果有领样形式的过滤条件,则将过滤条件保存于secFormList
-	var secFormList []interface{}
-	if secForm != nil {
-		if reflect.TypeOf(secForm).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件领样形式错误"}
-		}
-
-		secFormList = make([]interface{}, 0)
-		secFormList = secForm.([]interface{})
-	}
-
-	// 如果有任务形式的过滤条件,则将过滤条件保存于taskFormList
-	var taskFormList []interface{}
-	if taskForm != nil {
-		if reflect.TypeOf(taskForm).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-		}
-
-		taskFormList = make([]interface{}, 0)
-		taskFormList = taskForm.([]interface{})
-	}
-
-	// 上线时间
-	var createTimeList []interface{}
-	if createTime != nil {
-		if reflect.TypeOf(createTime).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-		}
-		createTimeList = make([]interface{}, 0)
-		createTimeList = createTime.([]interface{})
-	}
-
-	// 如果有商品类目的过滤条件,则将过滤条件保存于categoryFormList
-	var categoryFormList []interface{}
-	if categoryForm != nil {
-		if reflect.TypeOf(categoryForm).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-		}
-
-		categoryFormList = make([]interface{}, 0)
-		categoryFormList = categoryForm.([]interface{})
-	}
+	searchValue := r.Get("searchvalue", nil)
 
 	// 构造查询的条件
 	startId := pageIndex * cntPerPage
 	whereStr := fmt.Sprintf("(selection_status >= %d) AND (status = 0)", selectionStatusInProgress)
-	if taskFormList != nil {
-		whereStr += " and task_mode in ("
-		for _, v := range taskFormList {
-			whereStr += v.(string) + ", "
-		}
 
-		whereStr = whereStr[0 : len(whereStr)-2]
-		whereStr += ")"
+	if taskForm != nil {
+		whereStr += " and task_mode = " + taskForm.(string)
 	}
-	if secFormList != nil {
-		whereStr += " and sample_mode in ("
-		for _, v := range secFormList {
-			whereStr += v.(string) + ", "
-		}
-
-		whereStr = whereStr[0 : len(whereStr)-2]
-		whereStr += ")"
+	if secForm != nil {
+		whereStr += " and sample_mode = " + secForm.(string)
 	}
 
-	// 处理 selectionFormList (创建时间的过滤条件)
-	if createTimeList != nil {
-
-		for _, v := range createTimeList {
-			whereStr += " AND created_at >= (NOW() - INTERVAL "
-			switch v.(string) {
-			case "1": // 近7天
-				whereStr += "7 DAY"
-			case "2": // 近30天
-				whereStr += "30 DAY"
-			case "3": // 近90天
-				whereStr += "90 DAY"
-			default:
-				continue // 无效的过滤条件,跳过
+	if createTime != nil {
+		switch createTime.(string) {
+		case "1": // 近7天
+			whereStr += " AND created_at >= (NOW() - INTERVAL 7 DAY)"
+		case "2": // 近30天
+			whereStr += " AND created_at >= (NOW() - INTERVAL 30 DAY)"
+		case "3": // 近90天
+			whereStr += " AND created_at >= (NOW() - INTERVAL 90 DAY)"
+		default:
+			// 无效的过滤条件,跳过
+			return &TalentHttpResult{
+				Code: -2,
+				Msg:  "无效的创建时间过滤条件",
 			}
-			whereStr += ")"
 		}
-
-		fmt.Println("createTimeList:---->", whereStr)
 	}
 
 	//商品类目 来自product
-	if categoryFormList != nil {
-		whereStr += " and product_category in ("
-		for _, v := range categoryFormList {
-			whereStr += v.(string) + ", "
-		}
-
-		whereStr = whereStr[0 : len(whereStr)-2]
-		whereStr += ")"
+	// 商品类目 来自product
+	if categoryForm != nil {
+		whereStr += " and product_category = '" + categoryForm.(string) + "'"
 	}
 
 	//搜索栏
@@ -171,16 +114,15 @@ func GetSelectionList(r *ghttp.Request) *TalentHttpResult {
 	if err != nil {
 		return &TalentHttpResult{Code: -4, Msg: err.Error(), Data: nil}
 	}
-
+	// 全部数目 / 每页应该展示的数目 = 最大页数
 	maxPage := c / cntPerPage
 	if c%cntPerPage > 0 {
 		maxPage += 1
 	}
 
-	if pageIndex+1 > maxPage {
+	if pageIndex > maxPage {
 		return &TalentHttpResult{Code: -5, Msg: "over max page"}
 	}
-	fmt.Println("hereiiiii")
 
 	var selectionInfoList = youngee_talent_model.SelectionInfoList{
 		Count: c,
@@ -475,14 +417,50 @@ func GetProjectCollectionList(r *ghttp.Request) *TalentHttpResult {
 	return &TalentHttpResult{Code: 0, Msg: "success", Data: projectCollectionInfoList}
 }
 
+func GetLocalCollectionList(r *ghttp.Request) *TalentHttpResult {
+	tId, err := utils.SessionTalentInfo.GetTalentIdFromSession(r)
+	if err != nil {
+		return nil
+	}
+
+	var localIds []string
+	type LocalInfo struct {
+		LocalId string `json:"local_id"`
+	}
+	var projectInfos []LocalInfo
+	err = g.DB().Model("younggee_local_collect_info").Where("talent_id = ? AND deleted = ?", tId, 0).Fields("local_id").Scan(&projectInfos)
+	if err != nil {
+		return &TalentHttpResult{Code: -6, Msg: "查询数据库失败"}
+	}
+	for _, info := range projectInfos {
+		localIds = append(localIds, info.LocalId)
+	}
+
+	// 如果没有符合条件的 selection_id,则直接返回空的列表
+	if len(localIds) == 0 {
+		return &TalentHttpResult{Code: 0, Msg: "success", Data: youngee_talent_model.LocalCollectionInfoList{Count: 0}}
+	}
+
+	// 根据获取到的 selection_id 列表,从 younggee_selection_info 表中获取对应的信息
+	var localCollectionInfoList = youngee_talent_model.LocalCollectionInfoList{
+		Count: len(localIds),
+	}
+	err = g.DB().Model("younggee_local_life_info").WithAll().Where("local_id IN(?)", localIds).Scan(&localCollectionInfoList.LocalCollectionList)
+	if err != nil {
+		return &TalentHttpResult{Code: -6, Msg: "查询数据库失败"}
+	}
+
+	// 返回结果
+	return &TalentHttpResult{Code: 0, Msg: "success", Data: localCollectionInfoList}
+}
+
 // 获取单个选品详情service
 func GetSelectionDetail(r *ghttp.Request) *TalentHttpResult {
 	tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r)
 	if err != nil {
 		return &TalentHttpResult{Code: -1, Msg: "Get talent info failed"}
 	}
-	sid := r.GetQueryString("selectionid", 0)
-	pid := r.GetQueryString("productid", 0)
+	sid := r.GetQueryString("selection_id", 0)
 
 	if sid == "" {
 		return &TalentHttpResult{Code: -2, Msg: "data query failed"}
@@ -525,14 +503,14 @@ func GetSelectionDetail(r *ghttp.Request) *TalentHttpResult {
 	}
 	// 查询younggee_product表数据
 	var younggeeProduct *youngee_talent_model.YounggeeProduct
-	err = g.DB().Model(youngee_talent_model.YounggeeProduct{}).WithAll().Where("product_id", pid).Scan(&younggeeProduct)
+	err = g.DB().Model(youngee_talent_model.YounggeeProduct{}).WithAll().Where("product_id", selectionDetail.ProductId).Scan(&younggeeProduct)
 	if err != nil {
 		return &TalentHttpResult{Code: -3, Msg: err.Error()}
 	}
 
 	//查询younggee_product_photo表数据
 	var younggeeProductPhoto []*youngee_talent_model.YounggeeProductPhoto
-	err = g.DB().Model(youngee_talent_model.YounggeeProductPhoto{}).WithAll().Where("product_id", pid).Scan(&younggeeProductPhoto)
+	err = g.DB().Model(youngee_talent_model.YounggeeProductPhoto{}).WithAll().Where("product_id", selectionDetail.ProductId).Scan(&younggeeProductPhoto)
 	if err != nil {
 		return &TalentHttpResult{Code: -3, Msg: err.Error()}
 	}

+ 23 - 2
app/service/youngee_talent_service/talent_account.go

@@ -6,10 +6,12 @@ import (
 	"fmt"
 	"github.com/gogf/gf/os/gtime"
 	"io/ioutil"
+	"math/rand"
 	"net/http"
 	"net/url"
 	"regexp"
 	"strconv"
+	"time"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/model/youngee_talent_model"
 	"youngmini_server/app/utils"
@@ -207,6 +209,10 @@ func OnAddTalentAccount(r *ghttp.Request) *TalentHttpResult {
 	} else if account.PlatformId == 5 { //B站
 		//获取用户主页URL以及uid
 		shareText := account.HomePageUrl
+		// 正则表达式匹配以 https:// 开头的 URL
+		re := regexp.MustCompile(`https://[^\s]+`)
+		shareText = re.FindString(shareText)
+
 		//调用MoreAPI
 		userDetail := getBiLiUserDetail(shareText)
 		if userDetail == nil {
@@ -295,7 +301,20 @@ func CheckAccountBind(pId int, openId string) int {
 
 // 用于获取 XHS 用户详细信息的函数
 func getXHSUserDetail(homeURL string) *youngee_talent_model.XHSBasicInfo {
-	cookie := "acw_tc=0a00d7db17326882742197649ed1bf15848a5ff06232f5c37b7eaa2663f722; abRequestId=028b7a52-6c20-5315-aaf5-3bf365d26f20; webBuild=4.35.0; xsecappid=xhs-pc-web; a1=1936c44e2c4IjfanuIengZ3lEpOKmXeKdOan0rcbl50000544495; webId=021b26332dd3b74978a347eb885a1761; gid=yjJJWyiYfKMyyjJJWyiYYVIvqK2EfyMuuyMdE016fE2vSU286k88SE888yKJJq4800jJd8qq; websectiga=16f444b9ff5e3d7e258b5f7674489196303a0b160e16647c6c2b4dcb609f4134; sec_poison_id=58886b56-6f01-4f86-9ea1-0a1febfde070; unread={\\\"ub\\\":\\\"66e2f3690000000012011cb0\\\",\\\"ue\\\":\\\"66e823b9000000001e018443\\\",\\\"uc\\\":14}; web_session=040069b41c29aed16ac492f173354bfc129950"
+	//todo 使用cookie池
+	cookieList := g.Config().GetArray("xhsCookiePool.cookiesList")
+	// 随机选择一个cookie
+	// 将字符串解析为切片
+
+	// 如果 cookies 数组为空,返回一个错误
+	if len(cookieList) == 0 {
+		fmt.Println("Cookie list is empty")
+		return nil
+	}
+	rand.Seed(time.Now().UnixNano())
+	cookie := cookieList[rand.Intn(len(cookieList))]
+
+	//cookie := "abRequestId=023e90e1-a95a-58db-830a-d66c0cc67f60; a1=19566f0f66eglh42hy8peqvpak3xqglp49289p8xb50000109075; webId=d189df044ca380c74b5b97bc300db5a1; gid=yj2KKiyyyY4Yyj2KKi8iKjUYKdk1x4JxvYUdJCDAhU0TqY28CAk1Uj888y8j8W288q4Jif4i; xsecappid=xhs-pc-web; webBuild=4.62.3; loadts=1745844315922; acw_tc=0a4ad62517458443171336139e75772e8309d4caf46a5bbe75d13ed1f39023; websectiga=2a3d3ea002e7d92b5c9743590ebd24010cf3710ff3af8029153751e41a6af4a3; sec_poison_id=618e82ac-335a-4cc7-a4da-61f4d2b9740d; web_session=0400698c340cec15e62b1a303a3a4b527fb28b; unread={%22ub%22:%2267f51cef000000001c0051d9%22%2C%22ue%22:%2268085423000000001b027fce%22%2C%22uc%22:26}"
 	GetDetailUrl := "http://120.46.92.62:6888/api/xhs/user_detail"
 
 	// 构建请求体
@@ -315,7 +334,7 @@ func getXHSUserDetail(homeURL string) *youngee_talent_model.XHSBasicInfo {
 
 	// 设置请求头,包括 cookie
 	req.Header.Set("Content-Type", "application/json")
-	req.Header.Set("cookie", cookie)
+	req.Header.Set("cookie", cookie.(string))
 
 	// 发送请求
 	client := &http.Client{}
@@ -340,6 +359,8 @@ func getXHSUserDetail(homeURL string) *youngee_talent_model.XHSBasicInfo {
 		fmt.Println("Error parsing JSON:", err)
 		return nil
 	}
+	fmt.Println("responseMap--", responseMap)
+
 	// 提取 data.response_body.data.basic_info
 	if responseBody, ok := responseMap["data"].(map[string]interface{}); ok {
 		if responseBodyData, ok := responseBody["response_body"].(map[string]interface{}); ok {

+ 15 - 11
app/service/youngee_talent_service/talent_info.go

@@ -218,6 +218,10 @@ func GetMyInfoNum(r *ghttp.Request) *TalentHttpResult {
 	if err != nil {
 		return &TalentHttpResult{Code: -1, Msg: "Get talent info failed"}
 	}
+	taskType := r.GetInt("task_type", 0)
+	if taskType == 0 {
+		return &TalentHttpResult{Code: -1, Msg: "task_type is null"}
+	}
 
 	// 初始化 talentInfoNum
 	talentInfoNum := &youngee_talent_model.TalentInfoNum{
@@ -231,23 +235,23 @@ func GetMyInfoNum(r *ghttp.Request) *TalentHttpResult {
 
 	// 种草任务相关数量
 	fmt.Println("1")
-	talentInfoNum.TaskCountNum.AllTaskNum, err = g.DB().Model("youngee_task_info").Where("talent_id=?", tid).Count()
+	talentInfoNum.TaskCountNum.AllTaskNum, err = g.DB().Model("youngee_task_info").Where("talent_id=? AND project_type = ? ", tid, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
-	talentInfoNum.TaskCountNum.ApplyTaskNum, err = g.DB().Model("youngee_task_info").Where("talent_id = ? and task_stage = 1", tid).Count()
+	talentInfoNum.TaskCountNum.ApplyTaskNum, err = g.DB().Model("youngee_task_info").Where("talent_id = ? and task_stage = 1 AND project_type = ? ", tid, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
-	talentInfoNum.TaskCountNum.ExeTaskNum, err = g.DB().Model("youngee_task_info").Where("talent_id = ? and task_stage >= 4 and task_stage <= 14", tid).Count()
+	talentInfoNum.TaskCountNum.ExeTaskNum, err = g.DB().Model("youngee_task_info").Where("talent_id = ? and task_stage >= 4 and task_stage <= 14  and project_type = ? ", tid, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
-	talentInfoNum.TaskCountNum.EndTaskNum, err = g.DB().Model("youngee_task_info").Where("talent_id = ? and task_stage in (?)", tid, endTaskStageList).Count()
+	talentInfoNum.TaskCountNum.EndTaskNum, err = g.DB().Model("youngee_task_info").Where("talent_id = ? and task_stage in (?) and project_type = ? ", tid, endTaskStageList, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
-	talentInfoNum.TaskCountNum.ToDealNum, err = g.DB().Model("youngee_task_info").Where("talent_id = ? and task_stage = 15", tid).Count()
+	talentInfoNum.TaskCountNum.ToDealNum, err = g.DB().Model("youngee_task_info").Where("talent_id = ? and task_stage = 15 and project_type = ?", tid, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
@@ -285,27 +289,27 @@ func GetMyInfoNum(r *ghttp.Request) *TalentHttpResult {
 
 	// 本地生活任务相关数量
 	fmt.Println("3")
-	talentInfoNum.LocalTaskCountNum.AllLocalTaskNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id=?", tid).Count()
+	talentInfoNum.LocalTaskCountNum.AllLocalTaskNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id=? and local_type = ?", tid, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
-	talentInfoNum.LocalTaskCountNum.ApplyLocalTaskNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage = 1", tid).Count()
+	talentInfoNum.LocalTaskCountNum.ApplyLocalTaskNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage = 1 and local_type = ?", tid, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
-	talentInfoNum.LocalTaskCountNum.ToBookLocalNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage = 4", tid).Count()
+	talentInfoNum.LocalTaskCountNum.ToBookLocalNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage = 4 and local_type = ?", tid, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
-	talentInfoNum.LocalTaskCountNum.ExeLocalTaskNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage >= 4 and task_stage <= 14", tid).Count()
+	talentInfoNum.LocalTaskCountNum.ExeLocalTaskNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage >= 4 and task_stage <= 14 and local_type = ?", tid, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
-	talentInfoNum.LocalTaskCountNum.ToDealLocalNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage >= 4 and task_stage <= 14", tid).Count()
+	talentInfoNum.LocalTaskCountNum.ToDealLocalNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage >= 4 and task_stage <= 14 and local_type = ?", tid, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}
-	talentInfoNum.LocalTaskCountNum.EndLocalTaskNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage in (?)", tid, endTaskStageList).Count()
+	talentInfoNum.LocalTaskCountNum.EndLocalTaskNum, err = g.DB().Model("youngee_local_task_info").Where("talent_id = ? and task_stage in (?) and local_type = ?", tid, endTaskStageList, taskType).Count()
 	if err != nil {
 		return &TalentHttpResult{Code: -2, Msg: "Get task num failed"}
 	}

+ 5 - 11
app/service/youngee_talent_service/talent_ks_auth.go

@@ -116,12 +116,6 @@ func GetKsEcomQrcode(r *ghttp.Request) *TalentHttpResult {
 	startTime := time.Now()
 	// 创建一个新的上下文
 	ctx, cancel := chromedp.NewContext(context.Background())
-	//ctx, cancel := chromedp.NewContext(context.Background(), chromedp.WithDebugf(log.Printf))
-	// 设置定时器,100秒后关闭上下文
-	//go func() {
-	//	<-time.After(100 * time.Second)
-	//	CleanupChromedpContext(cancel)
-	//}()
 	//需要访问的网址,无state,扫码后跳转到订购页面
 	urlstr := fmt.Sprintf("https://login.kwaixiaodian.com/?biz=fuwu&redirect_url=https://fuwu.kwaixiaodian.com/new/detail?id=22328015871939")
 	// 执行任务
@@ -136,13 +130,13 @@ func GetKsEcomQrcode(r *ghttp.Request) *TalentHttpResult {
 		// 获取二维码
 		chromedp.AttributeValue(`#root > div > div.UqM2VqEDB3qdOFvSOHAB > div > div > div > div.Kmu1OHb3un0JBPZDkGa8 > div.JAc4fjotOx_h8lOtGzuB > div.dIaAe1BsCdQL6GtURkNI > img`, "src", &text, &ok),
 	}
-
 	//浏览器启动!
 	err = chromedp.Run(ctx, tasks)
+	fmt.Println("登录码url----->", text)
 	if err != nil {
 		fmt.Println("errInfo---", err.Error())
 	}
-	fmt.Println("代码运行时间:", time.Since(startTime))
+	fmt.Println("获取ks电商授权码代码运行时间:", time.Since(startTime))
 	// 返回二维码的操作已经完成,后续操作(go fun)在后台继续进行
 	// 启动后台 goroutine 监听重定向并处理
 	go HandleAfterRedirect(r, ctx, cancel)
@@ -151,7 +145,7 @@ func GetKsEcomQrcode(r *ghttp.Request) *TalentHttpResult {
 
 // 此函数执行完毕后
 func HandleAfterRedirect(r *ghttp.Request, ctx context.Context, cancel context.CancelFunc) *TalentHttpResult {
-	fmt.Println("HandleAfterRedirect-----")
+	fmt.Println("HandleAfterRedirect函数开始执行")
 	//达人id获取
 	tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r)
 	fmt.Println("tid:", tid, "err:", err)
@@ -165,8 +159,8 @@ func HandleAfterRedirect(r *ghttp.Request, ctx context.Context, cancel context.C
 	fmt.Println("扫码跳转成功,正在提交订单...")
 	err = chromedp.Run(ctx, chromedp.Tasks{
 		// 等待用户扫码并跳转后,点击“立即购买”按钮,在这识别用户是否扫码完成
-		chromedp.WaitVisible(`#main_root > div > div.yPXHTHq9cx_6vEhWohw_ > div.Jb15b0XMeXvmyWfEfrvq > div.m5IIGVbmvqsfZdb00GFO > div.JktibAFTihy_wzOaJXHl > div.Cbz2c2xjrwvEPJnVK4iA > div.KY1LeQ_L_xVgT9RzkLow.cgxWbYdA4fs28QuNN36F > button`, chromedp.ByQuery),
-		chromedp.Click(`#main_root > div > div.yPXHTHq9cx_6vEhWohw_ > div.Jb15b0XMeXvmyWfEfrvq > div.m5IIGVbmvqsfZdb00GFO > div.JktibAFTihy_wzOaJXHl > div.Cbz2c2xjrwvEPJnVK4iA > div.KY1LeQ_L_xVgT9RzkLow.cgxWbYdA4fs28QuNN36F > button`, chromedp.ByQuery),
+		chromedp.WaitVisible(`#main_root > div > div.detailWrapper___FZReo > div.container____QivN > div.leftContainer___q1wja > div.wrapper___d3jbD > div.buyContainer___IOXb7 > div.formItem___VaNwi.buyBtnWrapper___qTv77 > button`, chromedp.ByQuery),
+		chromedp.Click(`#main_root > div > div.detailWrapper___FZReo > div.container____QivN > div.leftContainer___q1wja > div.wrapper___d3jbD > div.buyContainer___IOXb7 > div.formItem___VaNwi.buyBtnWrapper___qTv77 > button`, chromedp.ByQuery),
 		// 等待第一个 checkbox 元素可见
 		chromedp.WaitVisible(`#app > div > section > main > div.cart-container > div.price-content > div.checkbox > label > span.ant-checkbox > input`, chromedp.ByQuery),
 		// 检查第一个 checkbox 是否已选中

+ 76 - 124
app/service/youngee_task_service/local_life_info.go

@@ -8,9 +8,9 @@ import (
 	"github.com/gogf/gf/os/gtime"
 	"github.com/gogf/gf/util/gconv"
 	"math"
-	"reflect"
 	"sort"
 	"strconv"
+	"strings"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/model"
 	"youngmini_server/app/model/youngee_talent_model"
@@ -21,13 +21,12 @@ func GetLocalLifeList(r *ghttp.Request) *TalentHttpResult {
 	pageIndex := r.GetQueryInt("idx", -1)
 	cntPerPage := r.GetQueryInt("cnt", -1)
 	//组合筛选
-	platform := r.Get("platform", nil) //抖音、快手、红Book、B站、微博
-	//taskForm := r.Get("task_form", nil)      //任务形式,1-2分别代表线下探店,素材分发
+	platform := r.Get("platform", nil)       //抖音、快手、红Book、B站、微博
+	taskForm := r.Get("task_form", nil)      //任务形式,1-2分别代表线下探店,素材分发
 	contentType := r.Get("contenttype", nil) //图文形式、视频形式
 	createTime := r.Get("createTime", nil)   //任务上线时间
-	//categoryForm := r.Get("categoryform", "") ////商品类目 智能家居、食品饮料等20种
 	//todo 城市参数?
-	//Location := r.GetQueryString("city", "")  //门店store所属城市,
+	//Location := r.GetQueryString("city", "") //门店store所属城市,
 
 	//排根据浏览量排序
 	viewOrder := r.GetQueryInt("pageViewOrder", -1) //根据哪个字段排序
@@ -39,120 +38,39 @@ func GetLocalLifeList(r *ghttp.Request) *TalentHttpResult {
 	if pageIndex == -1 || cntPerPage == -1 || cntPerPage == 0 {
 		return &TalentHttpResult{Code: -1, Msg: "参数错误"}
 	}
-	// 如果有任务形式的过滤条件,则将过滤条件保存于taskModeList
-	//var taskFormList []interface{}
-	//taskFormList = nil
-	//if taskForm != nil {
-	//
-	//	if reflect.TypeOf(taskForm).Kind() != reflect.Slice {
-	//		return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-	//	}
-	//
-	//	taskFormList = make([]interface{}, 0)
-	//	taskFormList = taskForm.([]interface{})
-	//} else {
-	//	taskFormList = make([]interface{}, 0)
-	//}
-
-	// 如果有平台的过滤条件,则将平台列表保存于platformList
-	var platformList []interface{}
-	if platform != nil {
-		if reflect.TypeOf(platform).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件平台类型错误"}
-		}
-
-		platformList = make([]interface{}, 0)
-		platformList = platform.([]interface{})
-	}
-
-	// 如果有内容形式的过滤条件,则将过滤条件保存于taskModeList
-	var contentTypeList []interface{}
-	if contentType != nil {
-		if reflect.TypeOf(contentType).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-		}
-
-		contentTypeList = make([]interface{}, 0)
-		contentTypeList = contentType.([]interface{})
-	}
-
-	// 上线时间
-	var createTimeList []interface{}
-	if createTime != nil {
-		if reflect.TypeOf(createTime).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-		}
-		createTimeList = make([]interface{}, 0)
-		createTimeList = createTime.([]interface{})
-	}
-
-	// 如果有商品类目的过滤条件,则将过滤条件保存于categoryFormList
-	//var categoryFormList []interface{}
-	//if categoryForm != nil {
-	//	if reflect.TypeOf(categoryForm).Kind() != reflect.Slice {
-	//		return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-	//	}
-	//
-	//	categoryFormList = make([]interface{}, 0)
-	//	categoryFormList = categoryForm.([]interface{})
-	//}
-	//if len(categoryFormList) > 0 {
-	//	// 使用 categoryFormList 进行某些操作
-	//	fmt.Println("Filtered categoryFormList:", categoryFormList)
-	//}
 
 	// 构造查询的条件
 	startId := pageIndex * cntPerPage
 	// whereStr := fmt.Sprintf("(project_status >= %d and project_status <> %d and project_type = 1)", projectStatusRecruiting, projectStatusInvalid)
 	whereStr := fmt.Sprintf("(task_status >= %d and  local_type = 1)", projectStatusRecruiting)
-	if platformList != nil {
-		whereStr = whereStr + " and local_platform in ("
-		for _, v := range platformList {
-			whereStr += v.(string) + ", "
-		}
 
-		whereStr = whereStr[0 : len(whereStr)-2]
-		whereStr += ")"
+	if taskForm != nil {
+		whereStr += " and task_mode = " + taskForm.(string)
 	}
 
-	if contentTypeList != nil {
-		whereStr = whereStr + " and content_type in ("
-		for _, v := range contentTypeList {
-			whereStr += v.(string) + ", "
-		}
-
-		whereStr = whereStr[0 : len(whereStr)-2]
-		whereStr += ")"
-	}
-
-	// 处理 selectionFormList (创建时间的过滤条件)
-	if createTimeList != nil {
-		whereStr += " AND created_at >= (NOW() - INTERVAL "
-		for _, v := range createTimeList {
-			switch v.(string) {
-			case "1": // 近7天
-				whereStr += "7 DAY"
-			case "2": // 近30天
-				whereStr += "30 DAY"
-			case "3": // 近90天
-				whereStr += "90 DAY"
-			default:
-				continue // 无效的过滤条件,跳过
+	if createTime != nil {
+		switch createTime.(string) {
+		case "1": // 近7天
+			whereStr += " AND created_at >= (NOW() - INTERVAL 7 DAY)"
+		case "2": // 近30天
+			whereStr += " AND created_at >= (NOW() - INTERVAL 30 DAY)"
+		case "3": // 近90天
+			whereStr += " AND created_at >= (NOW() - INTERVAL 90 DAY)"
+		default:
+			// 无效的过滤条件,跳过
+			return &TalentHttpResult{
+				Code: -2,
+				Msg:  "无效的创建时间过滤条件",
 			}
 		}
-		whereStr += ")"
-	}
-
-	//if taskFormList != nil {
-	//	fmt.Println("????")
-	//	whereStr += " and task_form in ("
-	//	for _, v := range taskFormList {
-	//		whereStr += v.(string) + ", "
-	//	}
-	//
-	//	whereStr = whereStr[0 : len(whereStr)-2]
-	//	whereStr += ")"
-	//}
+	}
+
+	if contentType != nil {
+		whereStr += " and content_type = " + contentType.(string)
+	}
+	if platform != nil {
+		whereStr += " and local_platform = " + platform.(string)
+	}
 
 	if searchValue != nil {
 		whereStr += " and local_name like '%" + searchValue.(string) + "%'"
@@ -295,11 +213,7 @@ func GetLocalLifeList(r *ghttp.Request) *TalentHttpResult {
 
 func GetLocalLifeDetail(r *ghttp.Request) *TalentHttpResult {
 	tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r)
-	local_id := r.GetQueryString("id", "")
-	//通过首页进入的详情页,获取服务商id,younggee_supplier表
-	enterprise_id := r.GetQueryString("enterprise_id", "")
-	//通过扫服务商码进入的详情页,获取服务商id,younggee_supplier表
-	//supplier_id := r.GetQueryString("supplier_id", "")
+	local_id := r.GetQueryString("local_id", "")
 	s_local_id := r.GetQueryString("s_local_id", "")
 	localInfoSupplier := youngee_talent_model.LocalInfoSupplier{}
 	if s_local_id != "" {
@@ -323,17 +237,49 @@ func GetLocalLifeDetail(r *ghttp.Request) *TalentHttpResult {
 		glog.Error(err)
 		return &TalentHttpResult{Code: 0, Msg: "Redis error"}
 	}
+
+	var talentCategory []*youngee_talent_model.YounggeeTalentCategory
+	err = g.DB().Model("younggee_talent_category").Scan(&talentCategory)
+	if err != nil {
+		// 处理查询错误
+		return &TalentHttpResult{Code: -1, Msg: err.Error()}
+	}
+	// 创建一个数字到汉字的映射
+	categoryMap := make(map[string]string)
+	for _, category := range talentCategory {
+		categoryMap[fmt.Sprint(category.Id)] = category.Category
+	}
+
 	var LocalDetail *youngee_talent_model.LocalInfoDetail
 	err = g.DB().Model("younggee_local_life_info").WithAll().Where("local_id", local_id).Scan(&LocalDetail)
 	if err != nil {
 		return &TalentHttpResult{Code: -3, Msg: err.Error()}
 	}
 
-	//var younggeeProductPhoto []*youngee_talent_model.YounggeeProductPhoto
-	//err = g.DB().Model(youngee_talent_model.YounggeeProductPhoto{}).WithAll().Where("product_id", pid).Scan(&younggeeProductPhoto)
-	//if err != nil {
-	//	return &TalentHttpResult{Code: -3, Msg: err.Error()}
-	//}
+	//填充收藏信息
+	collectionInfo := []youngee_talent_model.LocalCollection{}
+	err = g.DB().Model("younggee_local_collect_info").Where("local_id=? and talent_id = ?", local_id, tid).Scan(&collectionInfo)
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: err.Error()}
+	}
+	//已被收藏
+	if len(collectionInfo) != 0 && collectionInfo[0].Deleted == 0 { //有数据  且   没取消收藏
+		LocalDetail.IsCollected = 1
+	} else {
+		LocalDetail.IsCollected = 0 //没数据  或  有数据但取消了收藏
+	}
+
+	// 将 TalentType 转换为逗号隔开的汉字字符串
+	talentTypes := strings.Split(LocalDetail.TalentType, ",")
+	var result []string
+	for _, t := range talentTypes {
+		if name, ok := categoryMap[t]; ok {
+			result = append(result, name)
+		}
+	}
+	// 将结果拼接成逗号隔开的字符串
+	resultStr := strings.Join(result, ",")
+	LocalDetail.TalentType = resultStr
 
 	var younggeePhoto []*youngee_talent_model.YounggeeProductPhoto
 
@@ -405,9 +351,9 @@ func GetLocalLifeDetail(r *ghttp.Request) *TalentHttpResult {
 		return &TalentHttpResult{Code: 0, Msg: "Redis 设置过期时间失败"}
 	}
 
-	if enterprise_id != "" { //project来自商家
+	if LocalDetail.EnterpriseId != "" { //project来自商家
 		var enterprise *youngee_talent_model.Enterprise
-		err = g.DB().Model("enterprise").WithAll().Where("enterprise_id", enterprise_id).Scan(&enterprise)
+		err = g.DB().Model("enterprise").WithAll().Where("enterprise_id", LocalDetail.EnterpriseId).Scan(&enterprise)
 		if err != nil {
 			return &TalentHttpResult{Code: -3, Msg: err.Error()}
 		}
@@ -434,8 +380,13 @@ func GetLocalTaskBriefList(r *ghttp.Request) *TalentHttpResult {
 		return &TalentHttpResult{Code: -1, Msg: "Get talent info failed"}
 	}
 
-	// 构造查询条件
-	whereStr := fmt.Sprintf("talent_id = '%s'", tid)
+	taskType := r.GetInt("task_type", 0) //任务类型
+
+	if taskType == 0 {
+		return &TalentHttpResult{Code: -1, Msg: "task_type is nil"}
+	}
+	// 构造查询条件tid和taskType
+	whereStr := fmt.Sprintf("talent_id = %s and local_type = %d", tid, taskType)
 
 	// 获取任务列表
 	var taskList []*youngee_talent_model.YoungeeLocalTaskInfo
@@ -504,7 +455,8 @@ func GetLocalTaskBriefList(r *ghttp.Request) *TalentHttpResult {
 
 		}
 		taskBriefList.AllTaskInfoList = append(taskBriefList.AllTaskInfoList, taskInfoBrief)
-
+		//1:已报名, 2:申请成功, 3:申请失败, 4:待预约探店, 5:预约确认中 6:预约成功  , 7:待传探底图片, 8:脚本待审, 9:待传初稿, 10:初稿待审,
+		//11:待传链接, 12:链接待审, 13:待传数据, 14:数据待审, 15:已结案, 16:解约, 17:终止合作(过渡态)',
 		if v.TaskStage <= 2 {
 			taskBriefList.SignUpTaskInfoList = append(taskBriefList.SignUpTaskInfoList, taskInfoBrief)
 		} else if v.TaskStage == 4 { //如果是线下探店

+ 84 - 143
app/service/youngee_task_service/project_info.go

@@ -6,8 +6,8 @@ import (
 	"github.com/gogf/gf/os/gtime"
 	"github.com/gogf/gf/util/gconv"
 	"math"
-	"reflect"
 	"sort"
+	"strings"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/model/youngee_talent_model"
 	"youngmini_server/app/service/youngee_talent_service"
@@ -54,132 +54,44 @@ func GetProjectInfoList(r *ghttp.Request) *TalentHttpResult {
 		return &TalentHttpResult{Code: -1, Msg: "参数错误"}
 	}
 
-	// 如果有稿费形式的过滤条件,则将过滤条件保存于taskModeList
-	//var feeFormList []interface{}
-	//if feeForm != nil {
-	//	if reflect.TypeOf(feeForm).Kind() != reflect.Slice {
-	//		return &TalentHttpResult{Code: -2, Msg: "搜索条件稿费形式错误"}
-	//	}
-	//
-	//	feeFormList = make([]interface{}, 0)
-	//	feeFormList = feeForm.([]interface{})
-	//}
-
-	// 如果有任务形式的过滤条件,则将过滤条件保存于taskModeList
-	var projectFormList []interface{}
-	if projectForm != nil {
-		if reflect.TypeOf(projectForm).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-		}
-
-		projectFormList = make([]interface{}, 0)
-		projectFormList = projectForm.([]interface{})
-	}
-
-	// 如果有平台的过滤条件,则将平台列表保存于platformList
-	var platformList []interface{}
-	if platform != nil {
-		if reflect.TypeOf(platform).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件平台类型错误"}
-		}
-
-		platformList = make([]interface{}, 0)   //初始化一个空的切片
-		platformList = platform.([]interface{}) //类型断言将 platform 的值赋给 platformList。
-	}
-
-	var contentTypeList []interface{}
-	if contentType != nil {
-		if reflect.TypeOf(projectForm).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-		}
-
-		contentTypeList = make([]interface{}, 0)
-		contentTypeList = contentType.([]interface{})
-	}
-
-	var createTimeList []interface{}
-	if createTime != nil {
-		if reflect.TypeOf(createTime).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-		}
-		createTimeList = make([]interface{}, 0)
-		createTimeList = createTime.([]interface{})
-	}
-
-	// 如果有商品类目的过滤条件,则将过滤条件保存于categoryFormList
-	var categoryFormList []interface{}
-	if categoryForm != nil {
-		if reflect.TypeOf(categoryForm).Kind() != reflect.Slice {
-			return &TalentHttpResult{Code: -2, Msg: "搜索条件任务形式错误"}
-		}
-
-		categoryFormList = make([]interface{}, 0)
-		categoryFormList = categoryForm.([]interface{})
-	}
-
 	// 构造查询的条件
 	startId := pageIndex * cntPerPage
 	// whereStr := fmt.Sprintf("(project_status >= %d and project_status <> %d and project_type = 1)", projectStatusRecruiting, projectStatusInvalid)
 	whereStr := fmt.Sprintf("project_status >= %d and fail_reason <> 2 and project_type = 1", projectStatusRecruiting)
-	// 处理 平台类型
-	if platformList != nil {
-		whereStr = whereStr + " and project_platform in ("
-		for _, v := range platformList {
-			whereStr += v.(string) + ", "
-		}
-
-		whereStr = whereStr[0 : len(whereStr)-2]
-		whereStr += ")"
+	// 处理 平台类型 project_platform
+	if platform != nil {
+		whereStr += " and project_platform = " + platform.(string)
 	}
 	//处理 内容类型
-	if contentTypeList != nil {
-		whereStr = whereStr + " and content_type in ("
-		for _, v := range contentTypeList {
-			whereStr += v.(string) + ", "
-		}
-
-		whereStr = whereStr[0 : len(whereStr)-2]
-		whereStr += ")"
+	if contentType != nil {
+		whereStr += " and content_type = " + contentType.(string)
 	}
 
 	// 处理 创建时间
-	if createTimeList != nil {
-		whereStr += " AND created_at >= (NOW() - INTERVAL "
-		for _, v := range createTimeList {
-			switch v.(string) {
-			case "1": // 近7天
-				whereStr += "7 DAY"
-			case "2": // 近30天
-				whereStr += "30 DAY"
-			case "3": // 近90天
-				whereStr += "90 DAY"
-			default:
-				continue // 无效的过滤条件,跳过
+	if createTime != nil {
+		switch createTime.(string) {
+		case "1": // 近7天
+			whereStr += " AND created_at >= (NOW() - INTERVAL 7 DAY)"
+		case "2": // 近30天
+			whereStr += " AND created_at >= (NOW() - INTERVAL 30 DAY)"
+		case "3": // 近90天
+			whereStr += " AND created_at >= (NOW() - INTERVAL 90 DAY)"
+		default:
+			// 无效的过滤条件,跳过
+			return &TalentHttpResult{
+				Code: -2,
+				Msg:  "无效的创建时间过滤条件",
 			}
 		}
-		whereStr += ")"
 	}
-	fmt.Println("query after createTimeList:", whereStr)
 
 	// 处理 项目形式
-	if projectFormList != nil {
-		whereStr += " and project_form in ("
-		for _, v := range projectFormList {
-			whereStr += v.(string) + ", "
-		}
-
-		whereStr = whereStr[0 : len(whereStr)-2]
-		whereStr += ")"
+	if projectForm != nil {
+		whereStr += " and project_form = " + projectForm.(string)
 	}
 	// 处理 商品类型
-	if categoryFormList != nil {
-		whereStr += " and product_category in ("
-		for _, v := range categoryFormList {
-			whereStr += v.(string) + ", "
-		}
-
-		whereStr = whereStr[0 : len(whereStr)-2]
-		whereStr += ")"
+	if categoryForm != nil {
+		whereStr += " and product_category = '" + categoryForm.(string) + "'"
 	}
 
 	// 处理搜索条件
@@ -223,21 +135,16 @@ func GetProjectInfoList(r *ghttp.Request) *TalentHttpResult {
 			return &TalentHttpResult{Code: 0, Msg: "Redis error"}
 		}
 		projectInfoList.ProjectInfos[i].WatchedNum = viewCount.Int()
-		// 根据 WatchedNum 从高到低排序
-		if viewOrder != -1 {
-			sort.Slice(projectInfoList.ProjectInfos, func(i, j int) bool {
-				return projectInfoList.ProjectInfos[i].WatchedNum > projectInfoList.ProjectInfos[j].WatchedNum
-			})
-		}
 
 		// 统计 RecruitStrategys 数组中的最低粉丝量和最高粉丝量
 		var minFollowers, maxFollowers int
 		// 初始值可以设为极大/极小值
 		minFollowers = math.MaxInt32
 		maxFollowers = math.MinInt32
-
-		// 遍历 RecruitStrategys,找出最低粉丝量和最高粉丝量
+		var totalRecruitNum int
+		// 遍历 RecruitStrategys,找出最低粉丝量和最高粉丝量,以及总招募任务
 		for _, strategy := range project.RecruitStrategys {
+			totalRecruitNum += strategy.RecruitNumber
 			if strategy.FollowersLow < minFollowers {
 				minFollowers = strategy.FollowersLow
 			}
@@ -252,7 +159,7 @@ func GetProjectInfoList(r *ghttp.Request) *TalentHttpResult {
 		// 如果需要,可以将这些值保存到 ProjectInfo 中,供后续使用
 		projectInfoList.ProjectInfos[i].MinFollowers = minFollowers
 		projectInfoList.ProjectInfos[i].MaxFollowers = maxFollowers
-
+		projectInfoList.ProjectInfos[i].AllRecruitNum = totalRecruitNum
 		//稿费的展示情况
 		allFeeFormNoFee := true // 假设都是无费置换
 		var hasSelfPrice bool
@@ -289,6 +196,14 @@ func GetProjectInfoList(r *ghttp.Request) *TalentHttpResult {
 			projectInfoList.ProjectInfos[i].MinOffer = minOffer
 		}
 	}
+
+	// 根据 WatchedNum 从高到低排序
+	if viewOrder != -1 {
+		sort.Slice(projectInfoList.ProjectInfos, func(i, j int) bool {
+			return projectInfoList.ProjectInfos[i].WatchedNum > projectInfoList.ProjectInfos[j].WatchedNum
+		})
+	}
+
 	projectInfoList.MaxPage = maxPage
 	var filteredProjects []*youngee_talent_model.ProjectInfo
 	//筛选出“仅稿费”+“稿费+赠品”任务,
@@ -318,19 +233,18 @@ func GetProjectInfoList(r *ghttp.Request) *TalentHttpResult {
 
 // 获取单个项目详情service
 func GetProjectDetail(r *ghttp.Request) *TalentHttpResult {
+	g.Log().Info("This is an GetProjectDetail message")
 	tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r)
 	//列表页面进入
-	pid := r.GetQueryString("project_id", "") //?value?value?
-	enterprise_id := r.GetQueryString("enterprise_id", "")
+	pid := r.GetQueryString("project_id", "")
+
 	//扫码进入:1. 商家端的码 2. 服务商的码
 	s_project_id := r.GetQueryInt("s_project_id", 0)
 
 	// Redis key
 	projectViewKey := "project:view:" + pid
 	userViewedKey := "user:viewed:" + tid + ":" + pid
-	if pid == "" {
-		return &TalentHttpResult{Code: -2, Msg: "parse param error"}
-	}
+
 	//在redis中增加浏览量
 	// Check if the user has already viewed the product
 	//DoVar方便进行类型转化
@@ -340,27 +254,54 @@ func GetProjectDetail(r *ghttp.Request) *TalentHttpResult {
 		return &TalentHttpResult{Code: 0, Msg: "Redis error"}
 	}
 	var ProjectDetail *youngee_talent_model.ProjectDetail
+	//TalentType转成String
+	var talentCategory []*youngee_talent_model.YounggeeTalentCategory
+	err = g.DB().Model("younggee_talent_category").Scan(&talentCategory)
+	if err != nil {
+		// 处理查询错误
+		return &TalentHttpResult{Code: -1, Msg: err.Error()}
+	}
+	// 创建一个数字到汉字的映射
+	categoryMap := make(map[string]string)
+	for _, category := range talentCategory {
+		categoryMap[fmt.Sprint(category.Id)] = category.Category
+	}
 	err = g.DB().Model("project_info").WithAll().Where("project_id", pid).Scan(&ProjectDetail)
 	if err != nil {
 		return &TalentHttpResult{Code: -3, Msg: err.Error()}
 	}
-	//各阶段扣款比例
-	one, err := g.DB().Model("info_auto_default_handle").Where("auto_default_id=?", ProjectDetail.AutoDefaultId).One()
-	if err != nil {
-		return &TalentHttpResult{Code: 0, Msg: err.Error()}
-	} else {
-		ProjectDetail.DraftBreakPercent = one["sketch_replace_not_upload"].Int()
-		ProjectDetail.LinkBreakPercent = one["link_replace_not_upload"].Int()
-		ProjectDetail.DataBreakPercent = one["data_replace_not_upload"].Int()
-	}
-	//各阶段扣款时间
-	one2, err2 := g.DB().Model("info_auto_task").Where("auto_task_id=?", ProjectDetail.AutoTaskId).One()
-	if err2 != nil {
-		return &TalentHttpResult{Code: 0, Msg: "one2 is nil"}
-	} else {
-		ProjectDetail.DraftBreakTime = one2["draft_default"].Int()
-		ProjectDetail.LinkBreakTime = one2["link_breach"].Int()
-		ProjectDetail.DataBreakTime = one2["case_close_default"].Int()
+
+	// 将 TalentType 转换为逗号隔开的汉字字符串
+	talentTypes := strings.Split(ProjectDetail.TalentType, ",")
+	var result []string
+	for _, t := range talentTypes {
+		if name, ok := categoryMap[t]; ok {
+			result = append(result, name)
+		}
+	}
+	// 将结果拼接成逗号隔开的字符串
+	resultStr := strings.Join(result, ",")
+	ProjectDetail.TalentType = resultStr
+
+	if ProjectDetail.ProjectType == 1 { //公开任务才有违约信息
+		//各阶段扣款比例
+		one, err := g.DB().Model("info_auto_default_handle").Where("auto_default_id=?", ProjectDetail.AutoDefaultId).One()
+		if err != nil {
+			return &TalentHttpResult{Code: 0, Msg: err.Error()}
+		} else {
+			ProjectDetail.DraftBreakPercent = one["sketch_replace_not_upload"].Int()
+			ProjectDetail.LinkBreakPercent = one["link_replace_not_upload"].Int()
+			ProjectDetail.DataBreakPercent = one["data_replace_not_upload"].Int()
+		}
+		//各阶段扣款时间
+		one2, err2 := g.DB().Model("info_auto_task").Where("auto_task_id=?", ProjectDetail.AutoTaskId).One()
+		if err2 != nil {
+			return &TalentHttpResult{Code: 0, Msg: "one2 is nil"}
+		} else {
+			ProjectDetail.DraftBreakTime = one2["draft_default"].Int()
+			ProjectDetail.LinkBreakTime = one2["link_breach"].Int()
+			ProjectDetail.DataBreakTime = one2["case_close_default"].Int()
+		}
 	}
 
 	if viewed.IsNil() {
@@ -436,7 +377,7 @@ func GetProjectDetail(r *ghttp.Request) *TalentHttpResult {
 	} else {
 		//商家发布的
 		var enterprise *youngee_talent_model.Enterprise
-		err = g.DB().Model("enterprise").Where("enterprise_id", enterprise_id).Scan(&enterprise)
+		err = g.DB().Model("enterprise").Where("enterprise_id", ProjectDetail.EnterpriseId).Scan(&enterprise)
 		if err != nil {
 			return &TalentHttpResult{Code: -3, Msg: err.Error()}
 		}

+ 43 - 8
app/service/youngee_task_service/task_book.go

@@ -4,6 +4,7 @@ import (
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/net/ghttp"
 	"github.com/gogf/gf/os/gtime"
+	"strings"
 	"youngmini_server/app/model/youngee_talent_model"
 )
 
@@ -64,7 +65,15 @@ func AddLocalTaskBook(r *ghttp.Request) *TalentHttpResult {
 	}
 	//task设置为预约确认中
 	_, err = g.DB().Model("youngee_local_task_info").Data(g.Map{"task_stage": "5"}).Where("task_id = ?", bookInfoReq.TaskId).Update()
-
+	//修改reserve_time
+	bookTime, err := gtime.StrToTime(bookInfoReq.Day + " " + bookInfoReq.Time)
+	if err != nil {
+		return &TalentHttpResult{Code: -7, Msg: "Convert time failed"}
+	}
+	_, err = g.DB().Model("youngee_local_task_info").Data(g.Map{"reserve_time": bookTime}).Where("task_id = ?", bookInfoReq.TaskId).Update()
+	if err != nil {
+		return &TalentHttpResult{Code: -8, Msg: err.Error()}
+	}
 	return &TalentHttpResult{Code: 0, Msg: "success"}
 }
 
@@ -86,15 +95,15 @@ func AddLocalTaskPhoto(r *ghttp.Request) *TalentHttpResult {
 	if err != nil {
 		return &TalentHttpResult{Code: -1, Msg: err.Error()}
 	}
+	photoUrl := strings.Split(bookInfoReq.PhotoUrl, ",")
 
-	bookPhotoInfo := youngee_talent_model.YounggeeBookPhoto{
-		TaskId:   bookInfoReq.TaskId,
-		PhotoUrl: bookInfoReq.PhotoUrl,
-		CreateAt: gtime.Now(),
+	//插入新图片
+	for _, v := range photoUrl {
+		_, err := g.DB().Model("younggee_book_photo").Data(g.Map{"task_id": bookInfoReq.TaskId, "photo_url": v, "create_at": gtime.Now()}).Insert()
+		if err != nil {
+			return &TalentHttpResult{Code: -3, Msg: err.Error()}
+		}
 	}
-
-	//修改task表中的字段待添加变成已添加,待修改变成已修改
-	_, err = g.DB().Model("younggee_book_photo").Data(&bookPhotoInfo).Insert()
 	if err != nil {
 		return &TalentHttpResult{Code: -5, Msg: "Get task info failed", Data: err.Error()}
 	}
@@ -102,9 +111,35 @@ func AddLocalTaskPhoto(r *ghttp.Request) *TalentHttpResult {
 	_, err = g.DB().Model("youngee_local_task_info").Where("task_id = ?", bookInfoReq.TaskId).Data(g.Map{"task_stage": 9}).Update()
 	//设置成已经探店
 	_, err = g.DB().Model("youngee_local_task_info").Where("task_id = ?", bookInfoReq.TaskId).Data(g.Map{"book_status": 6}).Update()
+	// 更新task表中finish_explore_time
+	_, err = g.DB().Model("youngee_local_task_info").Where("task_id = ?", bookInfoReq.TaskId).Data(g.Map{"finish_explore_time": gtime.Now()}).Update()
+
 	if err != nil {
 		return &TalentHttpResult{Code: -5, Msg: err.Error()}
 	}
 
 	return &TalentHttpResult{Code: 0, Msg: "success"}
 }
+
+// 还未被审核过的探店时间,如果有的话,返回,没有
+func GetUnSubmitLocalTaskBook(r *ghttp.Request) *TalentHttpResult {
+
+	taskId := r.Get("task_id")
+	var unSubmitSketch []*youngee_talent_model.LocalTaskBookInfo
+	// 获取当前任务的最新,未审核的初稿
+	err := g.DB().Model("younggee_book_info").Where("task_id = ?", taskId).OrderDesc("create_at").Scan(&unSubmitSketch)
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: err.Error()}
+	}
+	if len(unSubmitSketch) == 0 {
+		return &TalentHttpResult{Code: 0, Msg: "从未提交过初稿", Data: nil}
+	} else {
+		// 如果是初稿已提交,且被驳回,则可以编辑
+		if unSubmitSketch[0].IsReview == 1 && unSubmitSketch[0].IsOk == 0 { //最新一条是提交但被驳回
+			unSubmitSketch[0].ISEditable = 1
+		} else {
+			unSubmitSketch[0].ISEditable = 0
+		}
+		return &TalentHttpResult{Code: 0, Msg: "返回最新一条初稿,", Data: unSubmitSketch[0]}
+	}
+}

+ 42 - 43
app/service/youngee_task_service/task_data.go

@@ -44,7 +44,7 @@ func AddTaskData(r *ghttp.Request) *TalentHttpResult {
 			return &TalentHttpResult{Code: -2, Msg: "auto_task_id not found"}
 		}
 	} else if DataInfoReq.TaskType == 2 {
-		err = g.DB().Model("youngee_local_task_info").WithAll().Where("task_id = ?", DataInfoReq.TaskId).Scan(localTaskInfo)
+		err = g.DB().Model("youngee_local_task_info").WithAll().Where("task_id = ?", DataInfoReq.TaskId).Scan(&localTaskInfo)
 		if err != nil {
 			return &TalentHttpResult{Code: -2, Msg: "YoungeeLocalTaskInfo find failed", Data: err.Error()}
 		}
@@ -160,12 +160,10 @@ func AddTaskData(r *ghttp.Request) *TalentHttpResult {
 		}
 
 		taskInfo := youngee_talent_model.YoungeeLocalTaskInfo{}
-		// 查询是否处于违约状态
-		err = g.DB().Model(model.YoungeeTaskInfo{}).Where("task_id = ?", DataInfoReq.TaskId).Scan(&taskInfo)
 		//修改task表的属性
-		err1 := g.DB().Model(model.YoungeeTaskInfo{}).Where("task_id = ?", DataInfoReq.TaskId).Scan(&taskInfo)
+		err1 := g.DB().Model("youngee_local_task_info").Where("task_id = ?", DataInfoReq.TaskId).Scan(&taskInfo)
 		if err1 != nil {
-			return &TalentHttpResult{Code: -1, Msg: "YoungeeTaskInfo find failed"}
+			return &TalentHttpResult{Code: -1, Msg: "youngee_local_task_info find failed"}
 		}
 		if taskInfo.CurDefaultType == 7 || taskInfo.CurDefaultType == 9 {
 			// 若处于违约状态则解除并更新企业应支付金额
@@ -194,7 +192,7 @@ func AddTaskData(r *ghttp.Request) *TalentHttpResult {
 		}
 		_, err = g.DB().Model("younggee_local_task_log").Data(&taskLog).Insert()
 		if err != nil {
-			return &TalentHttpResult{Code: -5, Msg: "YounggeeTaskLog insert failed", Data: err.Error()}
+			return &TalentHttpResult{Code: -5, Msg: "youngee_local_task_info insert failed", Data: err.Error()}
 		}
 
 	}
@@ -295,6 +293,44 @@ func GetUnSubmitTaskData(r *ghttp.Request) *TalentHttpResult {
 	return &TalentHttpResult{Code: 0, Msg: "success", Data: res}
 }
 
+// 收藏种草项目
+func LocalCollection(r *ghttp.Request) *TalentHttpResult {
+	tId, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r)
+	localId := r.GetQueryString("local_id", "")
+	if localId == "" {
+		return &TalentHttpResult{Code: -1, Msg: "参数传递有误"}
+	}
+	record, err := g.DB().Model("younggee_local_collect_info").Where("talent_id = ? and local_id = ?", tId, localId).One()
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: err.Error()}
+	}
+	if record == nil {
+		collectionInfo := youngee_talent_model.LocalCollection{
+			TalentId:   tId,
+			LocalId:    localId,
+			CreateTime: gtime.Now(),
+			Deleted:    0,
+		}
+
+		_, err = g.DB().Model("younggee_local_collect_info").Data(collectionInfo).Insert()
+
+	} else {
+		// 如果记录存在,更新 Delete 字段的值 和 收藏时间
+		currentDeleteValue := gconv.Int(record["deleted"])
+		newDeleteValue := 1 - currentDeleteValue // 0 改成 1,1 改成 0
+		_, err = g.DB().Model("younggee_local_collect_info").
+			Where("talent_id = ? and local_id = ?", tId, localId).
+			Data(g.Map{
+				"deleted":     newDeleteValue,
+				"create_time": gtime.Now(),
+			}).Update()
+		if err != nil {
+			return &TalentHttpResult{Code: -2, Msg: err.Error()}
+		}
+	}
+	return &TalentHttpResult{Code: 0, Msg: "collection success"}
+}
+
 // 收藏种草项目
 func ProjectCollection(r *ghttp.Request) *TalentHttpResult {
 	tId, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r)
@@ -334,43 +370,6 @@ func ProjectCollection(r *ghttp.Request) *TalentHttpResult {
 	return &TalentHttpResult{Code: 0, Msg: "collection success"}
 }
 
-// 收藏带货项目
-//func SelectionCollection(r *ghttp.Request) *TalentHttpResult {
-//	tId, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r)
-//	selectionId := r.GetQueryString("selection_id")
-//	productionId := r.GetQueryString("production_id")
-//	record, err := g.DB().Model("younggee_selection_collect_info").Where("talent_id = ? and selection_id = ?", tId, selectionId).One()
-//	if err != nil {
-//		return &TalentHttpResult{Code: -1, Msg: err.Error()}
-//	}
-//	if record == nil {
-//		collectionInfo := youngee_talent_model.SelectionCollection{
-//			TalentId:    tId,
-//			SelectionId: selectionId,
-//			ProductId:   productionId,
-//			CreateTime:  gtime.Now(),
-//			Deleted:     0,
-//		}
-//		_, err = g.DB().Model("younggee_selection_collect_info").Data(collectionInfo).Insert()
-//
-//	} else {
-//		// 如果记录存在,更新 Delete 字段的值 和 收藏时间
-//		fmt.Println("*******", record)
-//		currentDeleteValue := gconv.Int(record["deleted"])
-//		newDeleteValue := 1 - currentDeleteValue // 0 改成 1,1 改成 0
-//		_, err = g.DB().Model("younggee_selection_collect_info").
-//			Where("talent_id = ? and selection_id = ?", tId, selectionId).
-//			Data(g.Map{
-//				"deleted":     newDeleteValue,
-//				"create_time": gtime.Now(),
-//			}).Update()
-//		if err != nil {
-//			return &TalentHttpResult{Code: -1, Msg: err.Error()}
-//		}
-//	}
-//	return &TalentHttpResult{Code: 0, Data: record["deleted"], Msg: "collection success"}
-//}
-
 func SelectionCollection(r *ghttp.Request) *TalentHttpResult {
 	tId, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r)
 	selectionId := r.GetQueryString("selection_id")

+ 33 - 46
app/service/youngee_task_service/task_info.go

@@ -3,7 +3,6 @@ package youngee_task_service
 import (
 	"context"
 	"fmt"
-	"strconv"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/model"
 	"youngmini_server/app/model/youngee_talent_model"
@@ -246,42 +245,28 @@ func GetTaskBriefList(r *ghttp.Request) *TalentHttpResult {
 	if err != nil {
 		return &TalentHttpResult{Code: -1, Msg: "Get talent info failed"}
 	}
-
-	// 构造查询条件
-	whereStr := fmt.Sprintf("talent_id = '%s'", tid)
+	taskType := r.GetInt("task_type", 0) //任务类型
+	if taskType == 0 {
+		return &TalentHttpResult{Code: -1, Msg: "task_type is nil"}
+	}
+	// 构造查询条件tid和taskType
+	whereStr := fmt.Sprintf("talent_id = %s and project_type = %d", tid, taskType)
 
 	// 获取任务列表
 	var taskList []*youngee_talent_model.YoungeeTaskInfo
 	//此达人下,所有账号的任务都展示
-	err = g.Model(dao.YoungeeTaskInfo.Table).Where(whereStr).Order("create_date desc").Scan(&taskList)
+	err = g.Model("youngee_task_info").Where(whereStr).Order("create_date desc").Scan(&taskList)
 	if err != nil {
 		return &TalentHttpResult{Code: -1, Msg: "Get task list failed", Data: err.Error()}
 	}
-
-	//后续根据 PlatformId 快速查找平台信息。platformMap的key是PlatformId,value是平台具体描述
-	platformMap := make(map[string]model.InfoThirdPlatform)
-	platformInfo := []*model.InfoThirdPlatform{}
-	if len(taskList) != 0 {
-		err := g.Model(dao.InfoThirdPlatform.Table).Scan(&platformInfo)
-		if err != nil {
-			return &TalentHttpResult{Code: -1, Msg: "Get platform failed"}
-		}
-
-		for i, _ := range platformInfo {
-			platformMap[strconv.Itoa(platformInfo[i].PlatformId)] = *platformInfo[i]
-		}
-	}
 	//为每个任务根据项目id查询项目名称和主图
 	//taskBriefList存了各个阶段的tasklist
 	taskBriefList := youngee_talent_model.TaskInfoBriefList{}
 	fmt.Println("taskList----的长度为:", len(taskList))
 	for _, v := range taskList { //taskList含所有任务
 		//获取具体的招募策略,taskInfo中
-		fmt.Println("遍历tasklist---", v)
 		var projectDetail *youngee_talent_model.ProjectDetail
-		fmt.Println("v.ProjectId:", v.ProjectId)
 		err := g.Model("project_info").WithAll().Where("project_id = ?", v.ProjectId).Scan(&projectDetail)
-		fmt.Println("projectDetail-----", projectDetail)
 		//各阶段扣款比例
 		one, err := g.DB().Model("info_auto_default_handle").Where("auto_default_id=?", projectDetail.AutoDefaultId).One()
 		if err != nil {
@@ -873,6 +858,18 @@ func SignUpTaskWithKsAccount(r *ghttp.Request) *TalentHttpResult {
 			if err != nil {
 				return err
 			}
+
+		}
+		// 记录任务日志-上传初稿
+		taskLog := model.YounggeeTaskLog{
+			TaskId:  newTaskId,
+			Content: "报名成功",
+			LogAt:   gtime.Now(),
+		}
+		//上传日志,用于详情页判断上一个状态是什么
+		_, err = g.DB().Model(dao.YounggeeTaskLog.Table).Data(&taskLog).Insert()
+		if err != nil {
+			return err
 		}
 
 		return nil
@@ -918,12 +915,6 @@ func SignUpTaskWithAccount(r *ghttp.Request) *TalentHttpResult {
 		return &TalentHttpResult{Code: -5, Msg: err.Error()}
 	}
 
-	//var accountInfo *youngee_talent_model.PlatformAccountInfo
-	//err = g.DB().Model("youngee_platform_account_info").WithAll().Where("talent_id = ? and platform_id = ?", tid, projectDetail.ProjectPlatform).Scan(&accountInfo)
-	//if err != nil {
-	//	return &TalentHttpResult{Code: -5, Msg: err.Error()}
-	//}
-
 	//project_form=1寄拍需要填写地址
 	var address *model.YoungeeTalentDeliveryAddress
 	if projectDetail.ProjectForm == 1 {
@@ -939,9 +930,6 @@ func SignUpTaskWithAccount(r *ghttp.Request) *TalentHttpResult {
 	newTaskId = utils.GetUuid.GetTaskId(projectDetail.ProjectId, projectDetail.EnterpriseId, tid)
 	//// 生成达人平台账号信息快照
 	accountSnap, err := gjson.Encode(accountInfo)
-	//if err != nil {
-	//	return &TalentHttpResult{Code: -7, Msg: "encode platform snap failed"}
-	//}
 
 	// 生成达人信息快照
 	talentSnap, err := gjson.Encode(talentInfo)
@@ -1009,6 +997,7 @@ func SignUpTaskWithAccount(r *ghttp.Request) *TalentHttpResult {
 				WxNum:                  signTaskInfo.WxNum,
 				TalentName:             talentInfo.TalentNickname,
 				PlatformId:             platform_id,
+				ProjectType:            projectDetail.ProjectType,
 			}
 
 		} else {
@@ -1063,16 +1052,13 @@ func SignUpTaskWithAccount(r *ghttp.Request) *TalentHttpResult {
 				WxNum:                  signTaskInfo.WxNum,
 				TalentName:             talentInfo.TalentNickname,
 				PlatformId:             platform_id,
+				ProjectType:            projectDetail.ProjectType,
 			}
 		}
 	} else if projectDetail.ProjectType == 2 { //定向任务
-		//经过服务商
-		if signTaskInfo.SProjectId != 0 {
-			////查找服务商定义的策略
-			//var strategy *youngee_talent_model.RecruitStrategy
-			//err = g.DB().Model("recruit_strategy").WithAll().Where("strategy_id = ? and s_project_id= ?", signTaskInfo.StrategyId, signTaskInfo.SProjectId).Scan(&strategy)
+		if signTaskInfo.SProjectId != 0 { //经过服务商
 			var strategy *youngee_talent_model.RecruitStrategy
-			err = g.DB().Model("recruit_strategy").WithAll().Where("strategy_id = ? and s_project_id= ?", signTaskInfo.StrategyId, signTaskInfo.ProjectId).Scan(&strategy)
+			err = g.DB().Model("recruit_strategy").WithAll().Where("strategy_id = ? and s_project_id= ?", signTaskInfo.StrategyId, signTaskInfo.SProjectId).Scan(&strategy)
 			var ServiceChargePrice = 0.0      //服务费
 			var SupporPricer = 0.0            //提报价
 			if signTaskInfo.StrategyId == 3 { //自报价
@@ -1115,14 +1101,10 @@ func SignUpTaskWithAccount(r *ghttp.Request) *TalentHttpResult {
 				WxNum:                  signTaskInfo.WxNum,
 				PlatformId:             platform_id,
 			}
-
 		} else {
 			//不经过服务商
-			////查找服务商定义的策略
-			//var strategy *youngee_talent_model.RecruitStrategy
-			//err = g.DB().Model("recruit_strategy").WithAll().Where("strategy_id = ? and s_project_id= ?", signTaskInfo.StrategyId, signTaskInfo.SProjectId).Scan(&strategy)
 			var strategy *youngee_talent_model.RecruitStrategy
-			err = g.DB().Model("recruit_strategy").WithAll().Where("strategy_id = ? and s_project_id= ?", signTaskInfo.StrategyId, signTaskInfo.ProjectId).Scan(&strategy)
+			err = g.DB().Model("recruit_strategy").WithAll().Where("strategy_id = ? and project_id= ?", signTaskInfo.StrategyId, signTaskInfo.ProjectId).Scan(&strategy)
 			var SupporPricer = 0.0            //提报价
 			if signTaskInfo.StrategyId == 3 { //自报价
 				SupporPricer = signTaskInfo.Offer * (1 + strategy.ServiceRate*0.01)
@@ -1160,11 +1142,11 @@ func SignUpTaskWithAccount(r *ghttp.Request) *TalentHttpResult {
 				DraftFee:               signTaskInfo.Offer,   //稿费价格,一口价
 				WxNum:                  signTaskInfo.WxNum,
 				PlatformId:             platform_id,
+				ProjectType:            projectDetail.ProjectType,
 			}
 
 		}
-
-		//定向任务,服务费在哪设置
+		//定向任务,服务费设置
 		taskInfo = youngee_talent_model.YoungeeTaskInfo{
 			TaskId:                 newTaskId,
 			ProjectId:              signTaskInfo.ProjectId,
@@ -1187,18 +1169,19 @@ func SignUpTaskWithAccount(r *ghttp.Request) *TalentHttpResult {
 			SupportFee:             signTaskInfo.Offer, //不经过服务商,  提报价格=一口价*(1+服务费率)
 			DraftFee:               signTaskInfo.Offer, //稿费价格,一口价
 			WxNum:                  signTaskInfo.WxNum,
+			ProjectType:            projectDetail.ProjectType,
 		}
 
 	}
 	err = g.DB().Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
 		// 在task_info表中插入任务
-		_, err = tx.Ctx(ctx).Model(dao.YoungeeTaskInfo.Table).Data(&taskInfo).Insert()
+		_, err = tx.Ctx(ctx).Model("youngee_task_info").Data(&taskInfo).Insert()
 		if err != nil {
 			return err
 		}
 
 		// 对应项目的报名人数自增
-		_, err = tx.Ctx(ctx).Model(dao.ProjectInfo.Table).Where(dao.ProjectInfo.Columns.ProjectId, projectDetail.ProjectId).Increment(dao.ProjectInfo.Columns.ApplyNum, 1)
+		_, err = tx.Ctx(ctx).Model("project_info").Where("project_id = ?", projectDetail.ProjectId).Increment("apply_num", 1)
 		if err != nil {
 			return err
 		}
@@ -1323,6 +1306,7 @@ func SignUpLocalWithKsAccount(r *ghttp.Request) *TalentHttpResult {
 				SettleAmount:   signTaskInfo.Offer,
 				SupplierStatus: 1,
 				WxNum:          signTaskInfo.WxNum,
+				LocalType:      projectDetail.LocalType,
 			}
 
 		} else {
@@ -1359,6 +1343,7 @@ func SignUpLocalWithKsAccount(r *ghttp.Request) *TalentHttpResult {
 				DraftFee:       signTaskInfo.Offer, //商家或者服务商可以看到的稿费价格,无非置换为空,一口价为策略表中的t_offer,自报价是达人添加的也是t_offer,
 				SettleAmount:   signTaskInfo.Offer,
 				WxNum:          signTaskInfo.WxNum,
+				LocalType:      projectDetail.LocalType,
 			}
 
 		}
@@ -1391,6 +1376,7 @@ func SignUpLocalWithKsAccount(r *ghttp.Request) *TalentHttpResult {
 				SupportFee:     signTaskInfo.Offer, //不经过服务商,  提报价格=一口价*(1+服务费率)
 				DraftFee:       signTaskInfo.Offer, //稿费价格,一口价
 				WxNum:          signTaskInfo.WxNum,
+				LocalType:      projectDetail.LocalType,
 			}
 
 		} else {
@@ -1422,6 +1408,7 @@ func SignUpLocalWithKsAccount(r *ghttp.Request) *TalentHttpResult {
 				SupportFee:     signTaskInfo.Offer, //不经过服务商,  提报价格=一口价*(1+服务费率)
 				DraftFee:       signTaskInfo.Offer, //稿费价格,一口价
 				WxNum:          signTaskInfo.WxNum,
+				LocalType:      projectDetail.LocalType,
 			}
 
 		}

+ 6 - 1
app/service/youngee_task_service/task_link.go

@@ -4,6 +4,7 @@ import (
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/net/ghttp"
 	"github.com/gogf/gf/os/gtime"
+	"strings"
 	"time"
 	"youngmini_server/app/dao"
 	"youngmini_server/app/model"
@@ -42,7 +43,7 @@ func AddTaskLink(r *ghttp.Request) *TalentHttpResult {
 			return &TalentHttpResult{Code: -2, Msg: "auto_task_id not found"}
 		}
 	} else if LinkInfoReq.TaskType == 2 {
-		err = g.DB().Model("youngee_local_task_info").WithAll().Where("task_id = ?", LinkInfoReq.TaskId).Scan(localTaskInfo)
+		err = g.DB().Model("youngee_local_task_info").WithAll().Where("task_id = ?", LinkInfoReq.TaskId).Scan(&localTaskInfo)
 		if err != nil {
 			return &TalentHttpResult{Code: -2, Msg: "YoungeeLocalTaskInfo find failed", Data: err.Error()}
 		}
@@ -67,6 +68,10 @@ func AddTaskLink(r *ghttp.Request) *TalentHttpResult {
 		AutoAgreeAt: autoAgreeAt,
 		TaskType:    LinkInfoReq.TaskType,
 	}
+	// 如果 LinkUrl 不以 http:// 或 https:// 开头,则拼接 https://
+	if !strings.HasPrefix(LinkInfoReq.LinkUrl, "http://") && !strings.HasPrefix(LinkInfoReq.LinkUrl, "https://") {
+		linkInfo.LinkUrl = "https://" + LinkInfoReq.LinkUrl
+	}
 
 	//上传过但是被拒了
 	var condition1 bool = len(taskLinkInfo) != 0 && taskLinkInfo[0].IsReview == 1 && taskLinkInfo[0].IsOk == 0

+ 211 - 57
app/service/youngee_task_service/task_logistics.go

@@ -1,57 +1,211 @@
-package youngee_task_service
-
-import (
-	"youngmini_server/app/dao"
-	"youngmini_server/app/model"
-	"youngmini_server/app/model/youngee_talent_model"
-	"youngmini_server/app/utils"
-
-	"github.com/gogf/gf/encoding/gjson"
-	"github.com/gogf/gf/frame/g"
-	"github.com/gogf/gf/net/ghttp"
-)
-
-// 修改达人收货地址
-func OnUpdateLogisticsAddress(r *ghttp.Request) *TalentHttpResult {
-	tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r)
-	if err != nil {
-		return &TalentHttpResult{Code: -1, Msg: "Update talent address failed"}
-	}
-
-	var modifyReq *youngee_talent_model.TaskLogisticsAddress
-	err = r.ParseForm(&modifyReq)
-	if err != nil {
-		return &TalentHttpResult{Code: -2, Msg: "params error"}
-	}
-	address := model.YoungeeTalentDeliveryAddress{
-		TalentId:     tid,
-		RegionCode:   modifyReq.RegionCode,
-		DetailAddr:   modifyReq.DetailAddr,
-		PhoneNumber:  modifyReq.PhoneNumber,
-		ReceiverName: modifyReq.ReceiverName,
-	}
-	// 生成收货地址快照
-	addrSnap, err := gjson.Encode(address)
-	if err != nil {
-		return &TalentHttpResult{Code: -3, Msg: "encode delivery address snap failed"}
-	}
-	_, err = g.DB().Model(dao.YoungeeTaskInfo.Table).Data("talent_post_addr_snap", addrSnap).Where("task_id = ?", modifyReq.TaskId).Update()
-	if err != nil {
-		return &TalentHttpResult{Code: -4, Msg: "update failed"}
-	}
-
-	return &TalentHttpResult{Code: 0, Msg: "success"}
-}
-
-// 获取物流信息
-func GetTaskLogisticsInfo(r *ghttp.Request) *TalentHttpResult {
-	taskId := r.GetQueryInt("task_id", -1)
-
-	var logistics *model.YoungeeTaskLogistics
-	err := g.Model(dao.YoungeeTaskLogistics.Table).Where("task_id = ?", taskId).Scan(&logistics)
-	if err != nil {
-		return &TalentHttpResult{Code: -1, Msg: "Get logistics info failed"}
-	}
-
-	return &TalentHttpResult{Code: 0, Msg: "success", Data: logistics}
-}
+package youngee_task_service
+
+import (
+	"github.com/gogf/gf/util/gconv"
+	"youngmini_server/app/dao"
+	"youngmini_server/app/model"
+	"youngmini_server/app/model/youngee_talent_model"
+	"youngmini_server/app/utils"
+
+	"github.com/gogf/gf/encoding/gjson"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/net/ghttp"
+)
+
+// 修改达人收货地址
+func OnUpdateLogisticsAddress(r *ghttp.Request) *TalentHttpResult {
+	tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r)
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: "Update talent address failed"}
+	}
+
+	var modifyReq *youngee_talent_model.TaskLogisticsAddress
+	err = r.ParseForm(&modifyReq)
+	if err != nil {
+		return &TalentHttpResult{Code: -2, Msg: "params error"}
+	}
+	address := model.YoungeeTalentDeliveryAddress{
+		TalentId:     tid,
+		RegionCode:   modifyReq.RegionCode,
+		DetailAddr:   modifyReq.DetailAddr,
+		PhoneNumber:  modifyReq.PhoneNumber,
+		ReceiverName: modifyReq.ReceiverName,
+	}
+	// 生成收货地址快照
+	addrSnap, err := gjson.Encode(address)
+	if err != nil {
+		return &TalentHttpResult{Code: -3, Msg: "encode delivery address snap failed"}
+	}
+	_, err = g.DB().Model(dao.YoungeeTaskInfo.Table).Data("talent_post_addr_snap", addrSnap).Where("task_id = ?", modifyReq.TaskId).Update()
+	if err != nil {
+		return &TalentHttpResult{Code: -4, Msg: "update failed"}
+	}
+
+	return &TalentHttpResult{Code: 0, Msg: "success"}
+}
+
+// 物流信息汇总
+func GetTaskLogisticsNumber(r *ghttp.Request) *TalentHttpResult {
+	tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r)
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: "获取用户信息失败"}
+	}
+
+	// 定义物流状态统计结果
+	type LogisticsStatusCount struct {
+		Pending   int `json:"pending"`   // 待发货
+		Shipped   int `json:"shipped"`   // 已发货
+		Delivered int `json:"delivered"` // 已签收
+	}
+
+	var result LogisticsStatusCount
+
+	// 定义需要查询的表
+	tables := []string{"younggee_sec_task_info", "youngee_task_info", "youngee_local_task_info"}
+
+	// 遍历每个表,查询三种状态的数量
+	for _, table := range tables {
+		var count int
+
+		// 查询待发货数量
+		count, err = g.DB().Model(table).
+			Where("talent_id = ? AND logistics_status = ?", tid, 1).
+			Count()
+		if err != nil {
+			return &TalentHttpResult{Code: -2, Msg: "查询待发货数量失败"}
+		}
+		result.Pending += count
+
+		// 查询已发货数量
+		count, err = g.DB().Model(table).
+			Where("talent_id = ? AND logistics_status = ?", tid, 2).
+			Count()
+		if err != nil {
+			return &TalentHttpResult{Code: -3, Msg: "查询已发货数量失败"}
+		}
+		result.Shipped += count
+
+		// 查询已签收数量
+		count, err = g.DB().Model(table).
+			Where("talent_id = ? AND logistics_status = ?", tid, 3).
+			Count()
+		if err != nil {
+			return &TalentHttpResult{Code: -4, Msg: "查询已签收数量失败"}
+		}
+		result.Delivered += count
+	}
+
+	// 返回统计结果
+	return &TalentHttpResult{Code: 0, Msg: "success", Data: result}
+}
+
+// 物流信息汇总
+func GetTaskLogisticsList(r *ghttp.Request) *TalentHttpResult {
+	tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r)
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: "获取用户信息失败"}
+	}
+
+	tabKey := r.GetQueryInt("tab_key", 0)
+
+	// 定义表与任务类型的映射
+	tableTaskTypeMap := map[string]int{
+		"younggee_sec_task_info":  1, // 带货任务
+		"youngee_task_info":       2, // 种草任务
+		"youngee_local_task_info": 3, // 本地生活任务
+	}
+
+	// 定义结果集
+	var taskList []*youngee_talent_model.YoungeeGeneralTaskInfo
+
+	// 遍历每个表
+	for table, taskType := range tableTaskTypeMap {
+		//var taskIds []*string
+
+		// 查询符合条件的 task_id
+		query := g.DB().Model(table).Where("talent_id = ?", tid)
+		switch tabKey {
+		case 1: // 待发货
+			query = query.Where("logistics_status = ?", 1)
+		case 2: // 已发货
+			query = query.Where("logistics_status = ?", 2)
+		case 3: // 已签收
+			query = query.Where("logistics_status = ?", 3)
+		}
+
+		all, err := query.Fields("task_id").All()
+		array := all.Array()
+		taskIds := gconv.Strings(array)
+		if err != nil {
+			return &TalentHttpResult{Code: -2, Msg: "查询任务ID失败", Data: err.Error()}
+		}
+
+		// 遍历 task_id 查询详情
+		for _, taskId := range taskIds {
+
+			//定义name、photo、price、accountInfo
+			var TaskName string
+			var TaskPhoto string
+			var TaskPrice float64
+			var AccountInfo *youngee_talent_model.KuaishouUserInfo
+			var SourceType int
+			// 根据任务类型查询对应的任务详情表
+			switch taskType {
+			case 1: // 带货任务
+				var taskDetail *youngee_talent_model.SecTaskInfoDetail
+				err = g.DB().Model("younggee_sec_task_info").WithAll().Where("task_id = ?", taskId).Scan(&taskDetail)
+				TaskName = taskDetail.SelectionInfo.SelectionName
+				TaskPhoto = taskDetail.YounggeeProductPhoto[0].PhotoUrl
+				TaskPrice = taskDetail.YounggeeProduct.ProductPrice
+				AccountInfo = taskDetail.KsUserInfo[0]
+				SourceType = 1 //只有公开
+			case 2: // 种草任务
+				var taskDetail *youngee_talent_model.YoungeeTaskInfo
+				err = g.DB().Model("youngee_task_info").WithAll().Where("task_id = ?", taskId).Scan(&taskDetail)
+				TaskName = taskDetail.ProjectDetail.ProjectName
+				TaskPhoto = taskDetail.ProjectDetail.YounggeeProductPhoto[0].PhotoUrl
+				TaskPrice = taskDetail.ProjectDetail.YounggeeProduct.ProductPrice
+				AccountInfo = taskDetail.KsUserInfo[0]
+				SourceType = taskDetail.ProjectType
+			case 3: // 本地生活任务
+				var taskDetail *youngee_talent_model.YoungeeLocalTaskInfo
+				err = g.DB().Model("youngee_local_task_info").WithAll().Where("task_id = ?", taskId).Scan(&taskDetail)
+				TaskName = taskDetail.LocalInfoDetail.LocalName
+				TaskPhoto = taskDetail.LocalInfoDetail.YounggeeProductPhoto[0].PhotoUrl
+				TaskPrice = taskDetail.LocalInfoDetail.YounggeeTeamBuying.TeamBuyingPrice
+				AccountInfo = taskDetail.KsUserInfo[0]
+				SourceType = taskDetail.LocalType
+			}
+			if err != nil {
+				return &TalentHttpResult{Code: -3, Msg: "获取任务详情失败"}
+			}
+			// 组装任务详情
+			task := &youngee_talent_model.YoungeeGeneralTaskInfo{
+				TalentId:    tid,
+				TaskName:    TaskName,    // 任务名称
+				TaskPhoto:   TaskPhoto,   // 任务图片
+				TaskPrice:   TaskPrice,   // 任务价格
+				AccountInfo: AccountInfo, // 账号信息
+				SourceType:  SourceType,  // 1公开,2种草
+				TaskType:    taskType,    //1.带货 2.种草 3.本地生活
+			}
+			taskList = append(taskList, task)
+		}
+	}
+
+	// 返回结果
+	return &TalentHttpResult{Code: 0, Msg: "success", Data: taskList}
+}
+
+// 获取物流信息
+func GetTaskLogisticsInfo(r *ghttp.Request) *TalentHttpResult {
+	taskId := r.GetQueryInt("task_id", -1)
+
+	var logistics *model.YoungeeTaskLogistics
+	err := g.Model("youngee_task_logistics").Where("task_id = ?", taskId).Scan(&logistics)
+	if err != nil {
+		return &TalentHttpResult{Code: -1, Msg: "Get logistics info failed"}
+	}
+
+	return &TalentHttpResult{Code: 0, Msg: "success", Data: logistics}
+}

+ 11 - 5
app/service/youngee_task_service/task_sketch.go

@@ -48,7 +48,7 @@ func AddTaskSketch(r *ghttp.Request) *TalentHttpResult {
 			return &TalentHttpResult{Code: -2, Msg: "auto_task_id not found"}
 		}
 	} else if sketchInfoReq.TaskType == 2 {
-		err = g.DB().Model("youngee_local_task_info").WithAll().Where("task_id = ?", sketchInfoReq.TaskId).Scan(localTaskInfo)
+		err = g.DB().Model("youngee_local_task_info").WithAll().Where("task_id = ?", sketchInfoReq.TaskId).Scan(&localTaskInfo)
 		if err != nil {
 			return &TalentHttpResult{Code: -2, Msg: "YoungeeLocalTaskInfo find failed", Data: err.Error()}
 		}
@@ -303,17 +303,17 @@ func GetTaskSketch(r *ghttp.Request) *TalentHttpResult {
 	return &TalentHttpResult{Code: 0, Msg: "success", Data: sketchInfoList}
 }
 
-// 还未被审核过的初稿,如果有的话,返回,没有
+// 返回最新的一条初稿记录
 func GetUnSubmitTaskSketch(r *ghttp.Request) *TalentHttpResult {
 	taskId := r.Get("task_id")
 	var unSubmitSketch []*youngee_talent_model.TaskSketchInfo
 	// 获取当前任务的最新,未审核的初稿
-	err := g.DB().Model(dao.YounggeeSketchInfo.Table).Where("is_review = 0 and is_ok = 0 and task_id = ?", taskId).OrderDesc("create_at").Scan(&unSubmitSketch)
+	err := g.DB().Model("younggee_sketch_info").Where("task_id = ?", taskId).OrderDesc("create_at").Scan(&unSubmitSketch)
 	if err != nil {
 		return &TalentHttpResult{Code: -1, Msg: err.Error()}
 	}
 	if len(unSubmitSketch) == 0 {
-		return &TalentHttpResult{Code: 0, Msg: "没有未审核的初稿", Data: nil}
+		return &TalentHttpResult{Code: 0, Msg: "从未提交过初稿", Data: nil}
 	} else {
 		var sketchPhotoList []*youngee_talent_model.YounggeeSketchPhoto
 		err = g.DB().Model(dao.YounggeeSketchPhoto.Table).Where("sketch_id = ?", unSubmitSketch[0].SketchId).Scan(&sketchPhotoList)
@@ -321,7 +321,13 @@ func GetUnSubmitTaskSketch(r *ghttp.Request) *TalentHttpResult {
 			return &TalentHttpResult{Code: -2, Msg: err.Error()}
 		}
 		unSubmitSketch[0].Photo = sketchPhotoList
-		return &TalentHttpResult{Code: 0, Msg: "存在未处理的初稿", Data: unSubmitSketch[0]}
+		// 如果是初稿已提交,且被驳回,则可以编辑
+		if unSubmitSketch[0].IsReview == 1 && unSubmitSketch[0].IsOk == 0 { //最新一条是提交但被驳回
+			unSubmitSketch[0].ISEditable = 1
+		} else {
+			unSubmitSketch[0].ISEditable = 0
+		}
+		return &TalentHttpResult{Code: 0, Msg: "返回最新一条初稿,", Data: unSubmitSketch[0]}
 	}
 
 }

+ 15 - 15
app/system/sectask/sectask_service.go

@@ -182,28 +182,28 @@ func (s *secTaskService) ShowLogisticsDetail(ctx context.Context, tid, taskId st
 		LogisticsContext: nil,
 	}
 	// 校验达人id是否一致,并查询达人收货地址快照
-	talentWhereCondition := g.Map{
-		dao.YounggeeSecTaskInfo.Columns.TaskId: taskId,
-	}
-	var secTask *model.YounggeeSecTaskInfo
-	err := dao.YounggeeSecTaskInfo.Ctx(ctx).Where(talentWhereCondition).Scan(&secTask)
-	if err != nil || secTask == nil {
-		g.Log().Error("任务表查询失败")
-		return nil, err
-	}
-	if secTask.TalentId != tid {
-		g.Log().Error("用户id不一致")
-		return nil, err
-	}
+	//talentWhereCondition := g.Map{
+	//	dao.YounggeeSecTaskInfo.Columns.TaskId: taskId,
+	//}
+	//var secTask *model.YounggeeSecTaskInfo
+	//err := dao.YounggeeSecTaskInfo.Ctx(ctx).Where(talentWhereCondition).Scan(&secTask)
+	//if err != nil || secTask == nil {
+	//	g.Log().Error("任务表查询失败")
+	//	return nil, err
+	//}
+	//if secTask.TalentId != tid {
+	//	g.Log().Error("用户id不一致")
+	//	return nil, err
+	//}
 	//报名成功时已有地址快照
-	resp.AddressSnap = secTask.TalentPostAddrSnap
+	//resp.AddressSnap = secTask.TalentPostAddrSnap
 
 	// 根据任务id查询物流快递公司和快递单号
 	whereCondition := g.Map{
 		dao.YoungeeTaskLogistics.Columns.TaskId: taskId,
 	}
 	var logisticsInfo *model.YoungeeTaskLogistics
-	err = dao.YoungeeTaskLogistics.Ctx(ctx).Where(whereCondition).Scan(&logisticsInfo)
+	err := dao.YoungeeTaskLogistics.Ctx(ctx).Where(whereCondition).Scan(&logisticsInfo)
 	if err != nil || logisticsInfo == nil {
 		g.Log().Error("物流信息表查询失败")
 		return nil, err

BIN
bin/main


BIN
bin/v4.1.8/.DS_Store


BIN
bin/v4.1.9/.DS_Store


BIN
bin/v4.1.9/linux_amd64/youngmini_server


+ 8 - 0
config/config.toml

@@ -60,3 +60,11 @@ mchid = "1615933939"
 mchCertificateSerialNumber = "33DDFEC51BF5412F663B9B56510FD567B625FC68"
 mchAPIv3Key = "V12345678910Younggee10987654321V"
 
+# xhs cookie pool
+[xhsCookiePool]
+cookiesList = [
+    "abRequestId=023e90e1-a95a-58db-830a-d66c0cc67f60; a1=19566f0f66eglh42hy8peqvpak3xqglp49289p8xb50000109075; webId=d189df044ca380c74b5b97bc300db5a1; gid=yj2KKiyyyY4Yyj2KKi8iKjUYKdk1x4JxvYUdJCDAhU0TqY28CAk1Uj888y8j8W288q4Jif4i; xsecappid=xhs-pc-web; webBuild=4.62.3; loadts=1745844315922; acw_tc=0a4ad62517458443171336139e75772e8309d4caf46a5bbe75d13ed1f39023; websectiga=2a3d3ea002e7d92b5c9743590ebd24010cf3710ff3af8029153751e41a6af4a3; sec_poison_id=618e82ac-335a-4cc7-a4da-61f4d2b9740d; web_session=0400698c340cec15e62b1a303a3a4b527fb28b; unread={%22ub%22:%2267f51cef000000001c0051d9%22%2C%22ue%22:%2268085423000000001b027fce%22%2C%22uc%22:26}",
+    "abRequestId=049c2b9f-ea02-5169-b7f9-225d43b6d656; a1=194e4756d31aw1znk9hskj7ljyjv5lxewjiy2aqj130000315258; webId=9512b53376b911dc1b63a4f0c767cfe8; gid=yj4d4W2WjYEjyj4d4W2KfV0Aqy0EyuITjxMT3VyVW1VvVvq8h21CdJ888qy2J2Y8YJf0WfqW; web_session=040069b7d36add244a1df74f92354bf79f6df4; xsecappid=xhs-pc-web; webBuild=4.62.3; acw_tc=0ad597da17458427276414556ec5a39ba2b9d29b33d353888e4c606fb151d4; loadts=1745843013640; unread={%22ub%22:%226806195b000000001c006397%22%2C%22ue%22:%22680ef5400000000009038ac4%22%2C%22uc%22:29}; websectiga=a9bdcaed0af874f3a1431e94fbea410e8f738542fbb02df1e8e30c29ef3d91ac; sec_poison_id=d179a6cc-e9be-4fef-be9a-f2ae8c492479",
+    "a1=193de37a35888r97avcdrb0iu9a41u8aq65lnvty400000261790; webId=507dc263893bbab4ff8a7242f998a970; gid=yjqfdqW02YADyjqfdqW0qKh92YYYFjW0hSfF2v4D837j01884y7Y0I888JKyWj88dD8K0Kfy; abRequestId=507dc263893bbab4ff8a7242f998a970; xsecappid=xhs-pc-web; webBuild=4.62.3; acw_tc=0a0bb0cb17458442305007719ea1eb6801d7c3ba2842965a9052839814f377; websectiga=8886be45f388a1ee7bf611a69f3e174cae48f1ea02c0f8ec3256031b8be9c7ee; sec_poison_id=1599be33-41ad-4e69-84c2-fea0165d4cba; loadts=1745844567039; web_session=040069b29a05c56f42780d313a3a4b9ed5f3f4; unread={%22ub%22:%22680ee49b000000002001c82b%22%2C%22ue%22:%22680c6af6000000001c031779%22%2C%22uc%22:33}"
+]
+

+ 2 - 0
main.go

@@ -20,6 +20,8 @@ func main() {
 	adapter := adapter.NewRedis(g.Redis())
 	g.DB().GetCache().SetAdapter(adapter)
 
+	//auto_task.Init()
+
 	//var resp = utils.GetKDDetails("圆通速递", "2163347472375261969")
 	//fmt.Printf("resp=%+v\n", resp)
 	//var resp = service.ShowLogisticsDetail("2508915060")

+ 18 - 18
router/router.go

@@ -95,46 +95,46 @@ func init() {
 			fmt.Println("****进入rounter中的/kuaishouauth*******")
 			ClientKey := "ks651333097154138217"
 			ClientSecret := "dBt0rVRhTpUqcrOYGGpv0A"
-			//SignSecret := "bf6393dce0a2b669ee348bebb837b0da"
 			code := r.GetString("code")
 			state := r.GetString("state")
 			//来自管理后台的用户,state是手机号码
 			if len(state) == 11 {
-				record, err := g.DB().Model("youngee_m_kuaishou_userinfo").Where("phone_num = ? ", state).One()
-				if record.IsEmpty() {
-					fmt.Println("未找到符合条件的记录")
-					return
-				}
-				if err != nil {
-					fmt.Println("查询youngee_m_kuaishou_userinfo表出错")
-				}
+				r.Response.WriteJson("进入商家端快手授权")
 				//发起请求,将数据存在record中
 				m_res_auth, _ := oauth.GetAccessToken(ClientKey, ClientSecret, code)
+				r.Response.WriteJson("m_res_auth")
+				r.Response.WriteJson(m_res_auth)
 				AccessToken := m_res_auth.AccessToken
 				//获取基本信息
 				m_res_info, _ := user.GetUserinfo(ClientKey, AccessToken)
-
-				//将值update到表中
-				// 将值更新到表中的记录中
-				_, err = g.DB().Model("youngee_m_kuaishou_userinfo").
+				r.Response.WriteJson("m_res_info")
+				r.Response.WriteJson(m_res_info)
+				//存在数据则更新
+				_, err := g.DB().Model("youngee_m_kuaishou_userinfo").
 					Where("phone_number = ?", state).
 					Data(g.Map{
-						"access_token": AccessToken,
-						// 假设 m_res_info 中有 fields 例如 nickname 和 avatar
+						"access_token":  AccessToken,
 						"nickname":      m_res_info.Data.Name,
 						"code":          code,
 						"refresh_token": m_res_auth.RefreshToken,
 						"open_id":       m_res_auth.OpenId,
 						"create_time":   gtime.Now(),
 						"update_time":   gtime.Now(),
-						"expired":       0, //是否到期   1.后台两个小时刷新一次  2.获取list的时候需要将这个字段更新到数据中
+						"expired":       0,
 						"is_delete":     0,
+						"phone_number":  state,
 					}).
-					Update()
+					Save() // 如果存在则更新,不存在则插入
+				if err != nil {
+					r.Response.WriteJson("youngee_m_kuaishou_userinfo save failed")
+				}
+
+				return
+
 			}
 			//来自达人授权,获取accesstoken
 			res_auth, _ := oauth.GetAccessToken(ClientKey, ClientSecret, code)
-			r.Response.WriteJson("输出用户授权信息")
+			r.Response.WriteJson("后端:快手电商:输出用户授权信息")
 			r.Response.WriteJson(res_auth)
 			//防止一个快手账号重复绑定
 			userInfo := youngee_talent_model.KuaishouUserInfo{}

+ 145 - 0
vendor/github.com/gogf/gf/os/gcron/gcron.go

@@ -0,0 +1,145 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gcron implements a cron pattern parser and job runner.
+package gcron
+
+import (
+	"github.com/gogf/gf/os/glog"
+	"time"
+
+	"github.com/gogf/gf/os/gtimer"
+)
+
+const (
+	StatusReady   = gtimer.StatusReady
+	StatusRunning = gtimer.StatusRunning
+	StatusStopped = gtimer.StatusStopped
+	StatusClosed  = gtimer.StatusClosed
+)
+
+var (
+	// Default cron object.
+	defaultCron = New()
+)
+
+// SetLogger sets the logger for cron.
+func SetLogger(logger *glog.Logger) {
+	defaultCron.SetLogger(logger)
+}
+
+// GetLogger returns the logger in the cron.
+func GetLogger() *glog.Logger {
+	return defaultCron.GetLogger()
+}
+
+// SetLogPath sets the logging folder path for default cron object.
+// Deprecated, use SetLogger instead.
+func SetLogPath(path string) {
+	defaultCron.SetLogPath(path)
+}
+
+// GetLogPath returns the logging folder path of default cron object.
+// Deprecated, use GetLogger instead.
+func GetLogPath() string {
+	return defaultCron.GetLogPath()
+}
+
+// SetLogLevel sets the logging level for default cron object.
+// Deprecated, use SetLogger instead.
+func SetLogLevel(level int) {
+	defaultCron.SetLogLevel(level)
+}
+
+// GetLogLevel returns the logging level for default cron object.
+// Deprecated, use GetLogger instead.
+func GetLogLevel() int {
+	return defaultCron.GetLogLevel()
+}
+
+// Add adds a timed task to default cron object.
+// A unique `name` can be bound with the timed task.
+// It returns and error if the `name` is already used.
+func Add(pattern string, job func(), name ...string) (*Entry, error) {
+	return defaultCron.Add(pattern, job, name...)
+}
+
+// AddSingleton adds a singleton timed task, to default cron object.
+// A singleton timed task is that can only be running one single instance at the same time.
+// A unique `name` can be bound with the timed task.
+// It returns and error if the `name` is already used.
+func AddSingleton(pattern string, job func(), name ...string) (*Entry, error) {
+	return defaultCron.AddSingleton(pattern, job, name...)
+}
+
+// AddOnce adds a timed task which can be run only once, to default cron object.
+// A unique `name` can be bound with the timed task.
+// It returns and error if the `name` is already used.
+func AddOnce(pattern string, job func(), name ...string) (*Entry, error) {
+	return defaultCron.AddOnce(pattern, job, name...)
+}
+
+// AddTimes adds a timed task which can be run specified times, to default cron object.
+// A unique `name` can be bound with the timed task.
+// It returns and error if the `name` is already used.
+func AddTimes(pattern string, times int, job func(), name ...string) (*Entry, error) {
+	return defaultCron.AddTimes(pattern, times, job, name...)
+}
+
+// DelayAdd adds a timed task to default cron object after `delay` time.
+func DelayAdd(delay time.Duration, pattern string, job func(), name ...string) {
+	defaultCron.DelayAdd(delay, pattern, job, name...)
+}
+
+// DelayAddSingleton adds a singleton timed task after `delay` time to default cron object.
+func DelayAddSingleton(delay time.Duration, pattern string, job func(), name ...string) {
+	defaultCron.DelayAddSingleton(delay, pattern, job, name...)
+}
+
+// DelayAddOnce adds a timed task after `delay` time to default cron object.
+// This timed task can be run only once.
+func DelayAddOnce(delay time.Duration, pattern string, job func(), name ...string) {
+	defaultCron.DelayAddOnce(delay, pattern, job, name...)
+}
+
+// DelayAddTimes adds a timed task after `delay` time to default cron object.
+// This timed task can be run specified times.
+func DelayAddTimes(delay time.Duration, pattern string, times int, job func(), name ...string) {
+	defaultCron.DelayAddTimes(delay, pattern, times, job, name...)
+}
+
+// Search returns a scheduled task with the specified `name`.
+// It returns nil if no found.
+func Search(name string) *Entry {
+	return defaultCron.Search(name)
+}
+
+// Remove deletes scheduled task which named `name`.
+func Remove(name string) {
+	defaultCron.Remove(name)
+}
+
+// Size returns the size of the timed tasks of default cron.
+func Size() int {
+	return defaultCron.Size()
+}
+
+// Entries return all timed tasks as slice.
+func Entries() []*Entry {
+	return defaultCron.Entries()
+}
+
+// Start starts running the specified timed task named `name`.
+// If no`name` specified, it starts the entire cron.
+func Start(name ...string) {
+	defaultCron.Start(name...)
+}
+
+// Stop stops running the specified timed task named `name`.
+// If no`name` specified, it stops the entire cron.
+func Stop(name ...string) {
+	defaultCron.Stop(name...)
+}

+ 253 - 0
vendor/github.com/gogf/gf/os/gcron/gcron_cron.go

@@ -0,0 +1,253 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcron
+
+import (
+	"time"
+
+	"github.com/gogf/gf/container/garray"
+	"github.com/gogf/gf/container/gmap"
+	"github.com/gogf/gf/container/gtype"
+	"github.com/gogf/gf/os/glog"
+	"github.com/gogf/gf/os/gtimer"
+)
+
+type Cron struct {
+	idGen   *gtype.Int64    // Used for unique name generation.
+	status  *gtype.Int      // Timed task status(0: Not Start; 1: Running; 2: Stopped; -1: Closed)
+	entries *gmap.StrAnyMap // All timed task entries.
+	logger  *glog.Logger    // Logger, it is nil in default.
+
+	// Logging path(folder).
+	// Deprecated, use logger instead.
+	logPath *gtype.String
+
+	// Logging level.
+	// Deprecated, use logger instead.
+	logLevel *gtype.Int
+}
+
+// New returns a new Cron object with default settings.
+func New() *Cron {
+	return &Cron{
+		idGen:    gtype.NewInt64(),
+		status:   gtype.NewInt(StatusRunning),
+		entries:  gmap.NewStrAnyMap(true),
+		logPath:  gtype.NewString(),
+		logLevel: gtype.NewInt(glog.LEVEL_PROD),
+	}
+}
+
+// SetLogger sets the logger for cron.
+func (c *Cron) SetLogger(logger *glog.Logger) {
+	c.logger = logger
+}
+
+// GetLogger returns the logger in the cron.
+func (c *Cron) GetLogger() *glog.Logger {
+	return c.logger
+}
+
+// SetLogPath sets the logging folder path.
+// Deprecated, use SetLogger instead.
+func (c *Cron) SetLogPath(path string) {
+	c.logPath.Set(path)
+}
+
+// GetLogPath return the logging folder path.
+// Deprecated, use GetLogger instead.
+func (c *Cron) GetLogPath() string {
+	return c.logPath.Val()
+}
+
+// SetLogLevel sets the logging level.
+// Deprecated, use SetLogger instead.
+func (c *Cron) SetLogLevel(level int) {
+	c.logLevel.Set(level)
+}
+
+// GetLogLevel returns the logging level.
+// Deprecated, use GetLogger instead.
+func (c *Cron) GetLogLevel() int {
+	return c.logLevel.Val()
+}
+
+// AddEntry creates and returns a new Entry object.
+func (c *Cron) AddEntry(pattern string, job func(), times int, singleton bool, name ...string) (*Entry, error) {
+	var (
+		entryName = ""
+		infinite  = false
+	)
+	if len(name) > 0 {
+		entryName = name[0]
+	}
+	if times <= 0 {
+		infinite = true
+	}
+	return c.doAddEntry(addEntryInput{
+		Name:      entryName,
+		Job:       job,
+		Times:     times,
+		Pattern:   pattern,
+		Singleton: singleton,
+		Infinite:  infinite,
+	})
+}
+
+// Add adds a timed task.
+// A unique `name` can be bound with the timed task.
+// It returns and error if the `name` is already used.
+func (c *Cron) Add(pattern string, job func(), name ...string) (*Entry, error) {
+	return c.AddEntry(pattern, job, -1, false, name...)
+}
+
+// AddSingleton adds a singleton timed task.
+// A singleton timed task is that can only be running one single instance at the same time.
+// A unique `name` can be bound with the timed task.
+// It returns and error if the `name` is already used.
+func (c *Cron) AddSingleton(pattern string, job func(), name ...string) (*Entry, error) {
+	return c.AddEntry(pattern, job, -1, true, name...)
+}
+
+// AddTimes adds a timed task which can be run specified times.
+// A unique `name` can be bound with the timed task.
+// It returns and error if the `name` is already used.
+func (c *Cron) AddTimes(pattern string, times int, job func(), name ...string) (*Entry, error) {
+	return c.AddEntry(pattern, job, times, false, name...)
+}
+
+// AddOnce adds a timed task which can be run only once.
+// A unique `name` can be bound with the timed task.
+// It returns and error if the `name` is already used.
+func (c *Cron) AddOnce(pattern string, job func(), name ...string) (*Entry, error) {
+	return c.AddEntry(pattern, job, 1, false, name...)
+}
+
+// DelayAddEntry adds a timed task after `delay` time.
+func (c *Cron) DelayAddEntry(delay time.Duration, pattern string, job func(), times int, singleton bool, name ...string) {
+	gtimer.AddOnce(delay, func() {
+		if _, err := c.AddEntry(pattern, job, times, singleton, name...); err != nil {
+			panic(err)
+		}
+	})
+}
+
+// DelayAdd adds a timed task after `delay` time.
+func (c *Cron) DelayAdd(delay time.Duration, pattern string, job func(), name ...string) {
+	gtimer.AddOnce(delay, func() {
+		if _, err := c.Add(pattern, job, name...); err != nil {
+			panic(err)
+		}
+	})
+}
+
+// DelayAddSingleton adds a singleton timed task after `delay` time.
+func (c *Cron) DelayAddSingleton(delay time.Duration, pattern string, job func(), name ...string) {
+	gtimer.AddOnce(delay, func() {
+		if _, err := c.AddSingleton(pattern, job, name...); err != nil {
+			panic(err)
+		}
+	})
+}
+
+// DelayAddOnce adds a timed task after `delay` time.
+// This timed task can be run only once.
+func (c *Cron) DelayAddOnce(delay time.Duration, pattern string, job func(), name ...string) {
+	gtimer.AddOnce(delay, func() {
+		if _, err := c.AddOnce(pattern, job, name...); err != nil {
+			panic(err)
+		}
+	})
+}
+
+// DelayAddTimes adds a timed task after `delay` time.
+// This timed task can be run specified times.
+func (c *Cron) DelayAddTimes(delay time.Duration, pattern string, times int, job func(), name ...string) {
+	gtimer.AddOnce(delay, func() {
+		if _, err := c.AddTimes(pattern, times, job, name...); err != nil {
+			panic(err)
+		}
+	})
+}
+
+// Search returns a scheduled task with the specified `name`.
+// It returns nil if not found.
+func (c *Cron) Search(name string) *Entry {
+	if v := c.entries.Get(name); v != nil {
+		return v.(*Entry)
+	}
+	return nil
+}
+
+// Start starts running the specified timed task named `name`.
+// If no`name` specified, it starts the entire cron.
+func (c *Cron) Start(name ...string) {
+	if len(name) > 0 {
+		for _, v := range name {
+			if entry := c.Search(v); entry != nil {
+				entry.Start()
+			}
+		}
+	} else {
+		c.status.Set(StatusReady)
+	}
+}
+
+// Stop stops running the specified timed task named `name`.
+// If no`name` specified, it stops the entire cron.
+func (c *Cron) Stop(name ...string) {
+	if len(name) > 0 {
+		for _, v := range name {
+			if entry := c.Search(v); entry != nil {
+				entry.Stop()
+			}
+		}
+	} else {
+		c.status.Set(StatusStopped)
+	}
+}
+
+// Remove deletes scheduled task which named `name`.
+func (c *Cron) Remove(name string) {
+	if v := c.entries.Get(name); v != nil {
+		v.(*Entry).Close()
+	}
+}
+
+// Close stops and closes current cron.
+func (c *Cron) Close() {
+	c.status.Set(StatusClosed)
+}
+
+// Size returns the size of the timed tasks.
+func (c *Cron) Size() int {
+	return c.entries.Size()
+}
+
+// Entries return all timed tasks as slice(order by registered time asc).
+func (c *Cron) Entries() []*Entry {
+	array := garray.NewSortedArraySize(c.entries.Size(), func(v1, v2 interface{}) int {
+		entry1 := v1.(*Entry)
+		entry2 := v2.(*Entry)
+		if entry1.Time.Nanosecond() > entry2.Time.Nanosecond() {
+			return 1
+		}
+		return -1
+	}, true)
+	c.entries.RLockFunc(func(m map[string]interface{}) {
+		for _, v := range m {
+			array.Add(v.(*Entry))
+		}
+	})
+	entries := make([]*Entry, array.Len())
+	array.RLockFunc(func(array []interface{}) {
+		for k, v := range array {
+			entries[k] = v.(*Entry)
+		}
+	})
+	return entries
+}

+ 175 - 0
vendor/github.com/gogf/gf/os/gcron/gcron_entry.go

@@ -0,0 +1,175 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcron
+
+import (
+	"github.com/gogf/gf/errors/gcode"
+	"github.com/gogf/gf/errors/gerror"
+	"reflect"
+	"runtime"
+	"time"
+
+	"github.com/gogf/gf/container/gtype"
+	"github.com/gogf/gf/os/gtimer"
+	"github.com/gogf/gf/util/gconv"
+)
+
+// Entry is timing task entry.
+type Entry struct {
+	cron       *Cron         // Cron object belonged to.
+	timerEntry *gtimer.Entry // Associated timer Entry.
+	schedule   *cronSchedule // Timed schedule object.
+	jobName    string        // Callback function name(address info).
+	times      *gtype.Int    // Running times limit.
+	infinite   *gtype.Bool   // No times limit.
+	Name       string        // Entry name.
+	Job        func()        `json:"-"` // Callback function.
+	Time       time.Time     // Registered time.
+}
+
+type addEntryInput struct {
+	Name      string // Name names this entry for manual control.
+	Job       func() // Job is the callback function for timed task execution.
+	Times     int    // Times specifies the running limit times for the entry.
+	Pattern   string // Pattern is the crontab style string for scheduler.
+	Singleton bool   // Singleton specifies whether timed task executing in singleton mode.
+	Infinite  bool   // Infinite specifies whether this entry is running with no times limit.
+}
+
+// doAddEntry creates and returns a new Entry object.
+func (c *Cron) doAddEntry(in addEntryInput) (*Entry, error) {
+	if in.Name != "" {
+		if c.Search(in.Name) != nil {
+			return nil, gerror.NewCodef(gcode.CodeInvalidOperation, `cron job "%s" already exists`, in.Name)
+		}
+	}
+
+	schedule, err := newSchedule(in.Pattern)
+	if err != nil {
+		return nil, err
+	}
+	// No limit for `times`, for timer checking scheduling every second.
+	entry := &Entry{
+		cron:     c,
+		schedule: schedule,
+		jobName:  runtime.FuncForPC(reflect.ValueOf(in.Job).Pointer()).Name(),
+		times:    gtype.NewInt(in.Times),
+		infinite: gtype.NewBool(in.Infinite),
+		Job:      in.Job,
+		Time:     time.Now(),
+	}
+	if in.Name != "" {
+		entry.Name = in.Name
+	} else {
+		entry.Name = "cron-" + gconv.String(c.idGen.Add(1))
+	}
+	// When you add a scheduled task, you cannot allow it to run.
+	// It cannot start running when added to timer.
+	// It should start running after the entry is added to the Cron entries map, to avoid the task
+	// from running during adding where the entries do not have the entry information, which might cause panic.
+	entry.timerEntry = gtimer.AddEntry(time.Second, entry.check, in.Singleton, -1, gtimer.StatusStopped)
+	c.entries.Set(entry.Name, entry)
+	entry.timerEntry.Start()
+	return entry, nil
+}
+
+// IsSingleton return whether this entry is a singleton timed task.
+func (entry *Entry) IsSingleton() bool {
+	return entry.timerEntry.IsSingleton()
+}
+
+// SetSingleton sets the entry running in singleton mode.
+func (entry *Entry) SetSingleton(enabled bool) {
+	entry.timerEntry.SetSingleton(enabled)
+}
+
+// SetTimes sets the times which the entry can run.
+func (entry *Entry) SetTimes(times int) {
+	entry.times.Set(times)
+	entry.infinite.Set(false)
+}
+
+// Status returns the status of entry.
+func (entry *Entry) Status() int {
+	return entry.timerEntry.Status()
+}
+
+// SetStatus sets the status of the entry.
+func (entry *Entry) SetStatus(status int) int {
+	return entry.timerEntry.SetStatus(status)
+}
+
+// Start starts running the entry.
+func (entry *Entry) Start() {
+	entry.timerEntry.Start()
+}
+
+// Stop stops running the entry.
+func (entry *Entry) Stop() {
+	entry.timerEntry.Stop()
+}
+
+// Close stops and removes the entry from cron.
+func (entry *Entry) Close() {
+	entry.cron.entries.Remove(entry.Name)
+	entry.timerEntry.Close()
+}
+
+// check is the core timing task check logic.
+// The running times limits feature is implemented by gcron.Entry and cannot be implemented by gtimer.Entry.
+// gcron.Entry relies on gtimer to implement a scheduled task check for gcron.Entry per second.
+func (entry *Entry) check() {
+	if entry.schedule.meet(time.Now()) {
+		switch entry.cron.status.Val() {
+		case StatusStopped:
+			return
+
+		case StatusClosed:
+			entry.logDebugf("[gcron] %s %s removed", entry.schedule.pattern, entry.jobName)
+			entry.Close()
+
+		case StatusReady:
+			fallthrough
+		case StatusRunning:
+			defer func() {
+				if err := recover(); err != nil {
+					entry.logErrorf("[gcron] %s %s end with error: %+v", entry.schedule.pattern, entry.jobName, err)
+				} else {
+					entry.logDebugf("[gcron] %s %s end", entry.schedule.pattern, entry.jobName)
+				}
+
+				if entry.timerEntry.Status() == StatusClosed {
+					entry.Close()
+				}
+			}()
+
+			// Running times check.
+			if !entry.infinite.Val() {
+				times := entry.times.Add(-1)
+				if times <= 0 {
+					if entry.timerEntry.SetStatus(StatusClosed) == StatusClosed || times < 0 {
+						return
+					}
+				}
+			}
+			entry.logDebugf("[gcron] %s %s start", entry.schedule.pattern, entry.jobName)
+
+			entry.Job()
+		}
+	}
+}
+func (entry *Entry) logDebugf(format string, v ...interface{}) {
+	if logger := entry.cron.GetLogger(); logger != nil {
+		logger.Debugf(format, v...)
+	}
+}
+
+func (entry *Entry) logErrorf(format string, v ...interface{}) {
+	if logger := entry.cron.GetLogger(); logger != nil {
+		logger.Errorf(format, v...)
+	}
+}

+ 265 - 0
vendor/github.com/gogf/gf/os/gcron/gcron_schedule.go

@@ -0,0 +1,265 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcron
+
+import (
+	"github.com/gogf/gf/errors/gcode"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/os/gtime"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/gogf/gf/text/gregex"
+)
+
+// cronSchedule is the schedule for cron job.
+type cronSchedule struct {
+	create  int64            // Created timestamp.
+	every   int64            // Running interval in seconds.
+	pattern string           // The raw cron pattern string.
+	second  map[int]struct{} // Job can run in these second numbers.
+	minute  map[int]struct{} // Job can run in these minute numbers.
+	hour    map[int]struct{} // Job can run in these hour numbers.
+	day     map[int]struct{} // Job can run in these day numbers.
+	week    map[int]struct{} // Job can run in these week numbers.
+	month   map[int]struct{} // Job can run in these moth numbers.
+}
+
+const (
+	// regular expression for cron pattern, which contains 6 parts of time units.
+	regexForCron = `^([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,]+)\s+([\-/\d\*\?,A-Za-z]+)\s+([\-/\d\*\?,A-Za-z]+)$`
+
+	patternItemTypeUnknown = iota
+	patternItemTypeWeek
+	patternItemTypeMonth
+)
+
+var (
+	// Predefined pattern map.
+	predefinedPatternMap = map[string]string{
+		"@yearly":   "0 0 0 1 1 *",
+		"@annually": "0 0 0 1 1 *",
+		"@monthly":  "0 0 0 1 * *",
+		"@weekly":   "0 0 0 * * 0",
+		"@daily":    "0 0 0 * * *",
+		"@midnight": "0 0 0 * * *",
+		"@hourly":   "0 0 * * * *",
+	}
+	// Short month name to its number.
+	monthMap = map[string]int{
+		"jan": 1,
+		"feb": 2,
+		"mar": 3,
+		"apr": 4,
+		"may": 5,
+		"jun": 6,
+		"jul": 7,
+		"aug": 8,
+		"sep": 9,
+		"oct": 10,
+		"nov": 11,
+		"dec": 12,
+	}
+	// Short week name to its number.
+	weekMap = map[string]int{
+		"sun": 0,
+		"mon": 1,
+		"tue": 2,
+		"wed": 3,
+		"thu": 4,
+		"fri": 5,
+		"sat": 6,
+	}
+)
+
+// newSchedule creates and returns a schedule object for given cron pattern.
+func newSchedule(pattern string) (*cronSchedule, error) {
+	// Check if the predefined patterns.
+	if match, _ := gregex.MatchString(`(@\w+)\s*(\w*)\s*`, pattern); len(match) > 0 {
+		key := strings.ToLower(match[1])
+		if v, ok := predefinedPatternMap[key]; ok {
+			pattern = v
+		} else if strings.Compare(key, "@every") == 0 {
+			if d, err := gtime.ParseDuration(match[2]); err != nil {
+				return nil, err
+			} else {
+				return &cronSchedule{
+					create:  time.Now().Unix(),
+					every:   int64(d.Seconds()),
+					pattern: pattern,
+				}, nil
+			}
+		} else {
+			return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid pattern: "%s"`, pattern)
+		}
+	}
+	// Handle the common cron pattern, like:
+	// 0 0 0 1 1 2
+	if match, _ := gregex.MatchString(regexForCron, pattern); len(match) == 7 {
+		schedule := &cronSchedule{
+			create:  time.Now().Unix(),
+			every:   0,
+			pattern: pattern,
+		}
+		// Second.
+		if m, err := parsePatternItem(match[1], 0, 59, false); err != nil {
+			return nil, err
+		} else {
+			schedule.second = m
+		}
+		// Minute.
+		if m, err := parsePatternItem(match[2], 0, 59, false); err != nil {
+			return nil, err
+		} else {
+			schedule.minute = m
+		}
+		// Hour.
+		if m, err := parsePatternItem(match[3], 0, 23, false); err != nil {
+			return nil, err
+		} else {
+			schedule.hour = m
+		}
+		// Day.
+		if m, err := parsePatternItem(match[4], 1, 31, true); err != nil {
+			return nil, err
+		} else {
+			schedule.day = m
+		}
+		// Month.
+		if m, err := parsePatternItem(match[5], 1, 12, false); err != nil {
+			return nil, err
+		} else {
+			schedule.month = m
+		}
+		// Week.
+		if m, err := parsePatternItem(match[6], 0, 6, true); err != nil {
+			return nil, err
+		} else {
+			schedule.week = m
+		}
+		return schedule, nil
+	} else {
+		return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid pattern: "%s"`, pattern)
+	}
+}
+
+// parsePatternItem parses every item in the pattern and returns the result as map, which is used for indexing.
+func parsePatternItem(item string, min int, max int, allowQuestionMark bool) (map[int]struct{}, error) {
+	m := make(map[int]struct{}, max-min+1)
+	if item == "*" || (allowQuestionMark && item == "?") {
+		for i := min; i <= max; i++ {
+			m[i] = struct{}{}
+		}
+	} else {
+		// Like: MON,FRI
+		for _, item := range strings.Split(item, ",") {
+			var (
+				interval      = 1
+				intervalArray = strings.Split(item, "/")
+			)
+			if len(intervalArray) == 2 {
+				if number, err := strconv.Atoi(intervalArray[1]); err != nil {
+					return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid pattern item: "%s"`, item)
+				} else {
+					interval = number
+				}
+			}
+			var (
+				rangeMin   = min
+				rangeMax   = max
+				itemType   = patternItemTypeUnknown
+				rangeArray = strings.Split(intervalArray[0], "-") // Like: 1-30, JAN-DEC
+			)
+			switch max {
+			case 6:
+				// It's checking week field.
+				itemType = patternItemTypeWeek
+			case 12:
+				// It's checking month field.
+				itemType = patternItemTypeMonth
+			}
+			// Eg: */5
+			if rangeArray[0] != "*" {
+				if number, err := parsePatternItemValue(rangeArray[0], itemType); err != nil {
+					return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid pattern item: "%s"`, item)
+				} else {
+					rangeMin = number
+					rangeMax = number
+				}
+			}
+			if len(rangeArray) == 2 {
+				if number, err := parsePatternItemValue(rangeArray[1], itemType); err != nil {
+					return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid pattern item: "%s"`, item)
+				} else {
+					rangeMax = number
+				}
+			}
+			for i := rangeMin; i <= rangeMax; i += interval {
+				m[i] = struct{}{}
+			}
+		}
+	}
+	return m, nil
+}
+
+// parsePatternItemValue parses the field value to a number according to its field type.
+func parsePatternItemValue(value string, itemType int) (int, error) {
+	if gregex.IsMatchString(`^\d+$`, value) {
+		// It is pure number.
+		if number, err := strconv.Atoi(value); err == nil {
+			return number, nil
+		}
+	} else {
+		// Check if it contains letter,
+		// it converts the value to number according to predefined map.
+		switch itemType {
+		case patternItemTypeWeek:
+			if number, ok := monthMap[strings.ToLower(value)]; ok {
+				return number, nil
+			}
+		case patternItemTypeMonth:
+			if number, ok := weekMap[strings.ToLower(value)]; ok {
+				return number, nil
+			}
+		}
+	}
+	return 0, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid pattern value: "%s"`, value)
+}
+
+// meet checks if the given time `t` meets the runnable point for the job.
+func (s *cronSchedule) meet(t time.Time) bool {
+	if s.every != 0 {
+		// It checks using interval.
+		diff := t.Unix() - s.create
+		if diff > 0 {
+			return diff%s.every == 0
+		}
+		return false
+	} else {
+		// It checks using normal cron pattern.
+		if _, ok := s.second[t.Second()]; !ok {
+			return false
+		}
+		if _, ok := s.minute[t.Minute()]; !ok {
+			return false
+		}
+		if _, ok := s.hour[t.Hour()]; !ok {
+			return false
+		}
+		if _, ok := s.day[t.Day()]; !ok {
+			return false
+		}
+		if _, ok := s.month[int(t.Month())]; !ok {
+			return false
+		}
+		if _, ok := s.week[int(t.Weekday())]; !ok {
+			return false
+		}
+		return true
+	}
+}

+ 1 - 0
vendor/modules.txt

@@ -185,6 +185,7 @@ github.com/gogf/gf/net/gudp
 github.com/gogf/gf/os/gcache
 github.com/gogf/gf/os/gcfg
 github.com/gogf/gf/os/gcmd
+github.com/gogf/gf/os/gcron
 github.com/gogf/gf/os/gctx
 github.com/gogf/gf/os/genv
 github.com/gogf/gf/os/gfile