package sys import ( "context" "fmt" "hotgo/internal/consts" "hotgo/internal/dao" "hotgo/internal/library/contexts" "hotgo/internal/library/hgorm/handler" "hotgo/internal/library/hgorm/hook" "hotgo/internal/model/entity" "hotgo/internal/model/input/sysin" "hotgo/internal/service" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/grand" ) type sSysTask struct{} func NewSysTask() *sSysTask { return &sSysTask{} } func init() { service.RegisterSysTask(NewSysTask()) } func (s *sSysTask) Model(ctx context.Context) *gdb.Model { return handler.Model(dao.Task.Ctx(ctx), &handler.Option{FilterTenant: true}) } func (s *sSysTask) relationModel(ctx context.Context) *gdb.Model { return handler.Model(dao.TaskLevel.Ctx(ctx), &handler.Option{FilterTenant: true}) } func (s *sSysTask) listModel(ctx context.Context) *gdb.Model { tc, hc, pc := dao.Task.Columns(), dao.TaskHall.Columns(), dao.Product.Columns() return s.Model(ctx).As("t"). LeftJoin(dao.TaskHall.Table()+" h", col("h", hc.Id)+"="+col("t", tc.HallId)). LeftJoin(dao.Product.Table()+" p", col("p", pc.Id)+"="+col("t", tc.ProductId)). Fields("t.*", fmt.Sprintf("COALESCE(%s,'') hall_name", col("h", hc.Name)), fmt.Sprintf("COALESCE(%s,'') product_name", col("p", pc.Name))) } func (s *sSysTask) List(ctx context.Context, in *sysin.TaskListInp) (list []*sysin.TaskListModel, total int, err error) { tc := dao.Task.Columns() mod := s.listModel(ctx) if in.Title != "" { mod = mod.WhereLike(col("t", tc.Title), "%"+in.Title+"%") } if in.HallId > 0 { mod = mod.Where(col("t", tc.HallId), in.HallId) } if in.PublishStatus > 0 { mod = mod.Where(col("t", tc.PublishStatus), in.PublishStatus) } if in.LevelId > 0 { mod = mod.WhereExists(s.relationModel(ctx).As("tl").Fields("1").Where(col("tl", dao.TaskLevel.Columns().TaskId)+"="+col("t", tc.Id)).Where(col("tl", dao.TaskLevel.Columns().LevelId), in.LevelId)) } if err = mod.Page(in.Page, in.PerPage).OrderAsc(col("t", tc.Sort)).OrderDesc(col("t", tc.Id)).ScanAndCount(&list, &total, false); err != nil { return nil, 0, gerror.Wrap(err, "获取任务列表失败") } for _, row := range list { if err = s.loadLevels(ctx, row); err != nil { return nil, 0, err } count, e := handler.Model(dao.TradeOrder.Ctx(ctx), &handler.Option{FilterTenant: true}).Where(dao.TradeOrder.Columns().TaskId, row.Id).Count() if e != nil { return nil, 0, e } row.Referenced = count > 0 } return } func (s *sSysTask) View(ctx context.Context, in *sysin.TaskViewInp) (res *sysin.TaskListModel, err error) { if err = s.listModel(ctx).Where(col("t", dao.Task.Columns().Id), in.Id).Scan(&res); err != nil { return nil, gerror.Wrap(err, "获取任务详情失败") } if res == nil { return nil, gerror.New("任务不存在") } err = s.loadLevels(ctx, res) return } func (s *sSysTask) loadLevels(ctx context.Context, row *sysin.TaskListModel) error { rc, lc := dao.TaskLevel.Columns(), dao.AppMemberLevel.Columns() type item struct { Id uint64 `json:"id"` Name string `json:"name"` } var rows []*item if err := s.relationModel(ctx).As("r").LeftJoin(dao.AppMemberLevel.Table()+" l", col("l", lc.Id)+"="+col("r", rc.LevelId)).Fields(col("l", lc.Id), col("l", lc.Name)).Where(col("r", rc.TaskId), row.Id).OrderAsc(col("l", lc.Sort)).Scan(&rows); err != nil { return gerror.Wrap(err, "获取任务等级失败") } row.LevelIds = []uint64{} row.LevelNames = []string{} for _, v := range rows { row.LevelIds = append(row.LevelIds, v.Id) row.LevelNames = append(row.LevelNames, v.Name) } return nil } func (s *sSysTask) Edit(ctx context.Context, in *sysin.TaskEditInp) (id uint64, err error) { amount, err := parseCents(in.Commission) if err != nil { return 0, err } in.CommissionAmount = amount hc := dao.TaskHall.Columns() hallCount, err := handler.Model(dao.TaskHall.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(in.HallId).WhereIn(hc.PublishStatus, []int{consts.BizPublishPublished, consts.BizPublishOffline, consts.BizPublishDraft}).Count() if err != nil { return 0, err } if hallCount == 0 { return 0, gerror.New("任务大厅不存在") } pc := dao.Product.Columns() productCount, err := handler.Model(dao.Product.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(in.ProductId).WhereIn(pc.PublishStatus, []int{consts.BizPublishPublished, consts.BizPublishOffline, consts.BizPublishDraft}).Count() if err != nil { return 0, err } if productCount == 0 { return 0, gerror.New("关联商品不存在") } lc := dao.AppMemberLevel.Columns() levelCount, err := handler.Model(dao.AppMemberLevel.Ctx(ctx), &handler.Option{FilterTenant: true}).WhereIn(lc.Id, in.LevelIds).Where(lc.Status, consts.StatusEnabled).Count() if err != nil { return 0, err } if levelCount != len(in.LevelIds) { return 0, gerror.New("所选会员等级不存在或已停用") } err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { c := dao.Task.Columns() uid := contexts.GetUserId(ctx) var before *entity.Task if in.Id > 0 { if e := s.Model(ctx).WherePri(in.Id).LockUpdate().Scan(&before); e != nil { return e } if before == nil { return gerror.New("任务不存在") } result, e := s.Model(ctx).WherePri(in.Id).Where(c.Version, in.Version).Fields(sysin.TaskUpdateFields{}).Data(g.Map{c.HallId: in.HallId, c.ProductId: in.ProductId, c.Title: in.Title, c.Description: in.Description, c.DetailHtml: in.DetailHtml, c.CoverAttachmentId: in.CoverAttachmentId, c.CoverUrl: in.CoverUrl, c.CommissionAmount: in.CommissionAmount, c.CommissionRate: in.CommissionRate, c.DailyLimit: in.DailyLimit, c.PerMemberLimit: in.PerMemberLimit, c.StartAt: in.StartAt, c.EndAt: in.EndAt, c.Sort: in.Sort, c.Remark: in.Remark, c.UpdatedBy: uid, c.Version: gdb.Raw(c.Version + "+1")}).Update() if e != nil { return gerror.Wrap(e, "更新任务失败") } rows, _ := result.RowsAffected() if rows != 1 { return gerror.New("任务数据已更新,请刷新后重试") } id = in.Id } else { taskNo := "TK" + gtime.Now().Format("YmdHis") + grand.S(5) result, e := s.Model(ctx).Fields(c.TaskNo, c.HallId, c.ProductId, c.Title, c.Description, c.DetailHtml, c.CoverAttachmentId, c.CoverUrl, c.CommissionAmount, c.CommissionRate, c.DailyLimit, c.PerMemberLimit, c.StartAt, c.EndAt, c.PublishStatus, c.Sort, c.Remark, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(g.Map{c.TaskNo: taskNo, c.HallId: in.HallId, c.ProductId: in.ProductId, c.Title: in.Title, c.Description: in.Description, c.DetailHtml: in.DetailHtml, c.CoverAttachmentId: in.CoverAttachmentId, c.CoverUrl: in.CoverUrl, c.CommissionAmount: in.CommissionAmount, c.CommissionRate: in.CommissionRate, c.DailyLimit: in.DailyLimit, c.PerMemberLimit: in.PerMemberLimit, c.StartAt: in.StartAt, c.EndAt: in.EndAt, c.PublishStatus: consts.BizPublishDraft, c.Sort: in.Sort, c.Remark: in.Remark, c.CreatedBy: uid, c.UpdatedBy: uid}).Insert() if e != nil { return gerror.Wrap(e, "创建任务失败") } last, _ := result.LastInsertId() id = uint64(last) } rc := dao.TaskLevel.Columns() if _, e := s.relationModel(ctx).Where(rc.TaskId, id).Delete(); e != nil { return e } for _, levelId := range in.LevelIds { if _, e := dao.TaskLevel.Ctx(ctx).Fields(rc.TaskId, rc.LevelId).Hook(hook.SaveTenant).Data(g.Map{rc.TaskId: id, rc.LevelId: levelId}).Insert(); e != nil { return gerror.Wrap(e, "保存任务等级失败") } } return service.SysBizAudit().Record(ctx, &sysin.BizAuditRecordInp{Module: "task", Action: "task.edit", TargetType: "task", TargetId: id, Before: before, After: g.Map{"title": in.Title, "productId": in.ProductId, "commissionAmount": in.CommissionAmount, "levelIds": in.LevelIds}}) }) return } func (s *sSysTask) Status(ctx context.Context, in *sysin.TaskStatusInp) error { c := dao.Task.Columns() if in.PublishStatus == consts.BizPublishPublished { count, err := s.relationModel(ctx).Where(dao.TaskLevel.Columns().TaskId, in.Id).Count() if err != nil { return err } if count == 0 { return gerror.New("任务至少绑定一个会员等级后才能发布") } } result, err := s.Model(ctx).WherePri(in.Id).Where(c.Version, in.Version).Data(g.Map{c.PublishStatus: in.PublishStatus, c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update() if err != nil { return gerror.Wrap(err, "更新任务状态失败") } rows, _ := result.RowsAffected() if rows != 1 { return gerror.New("任务数据已更新,请刷新后重试") } return service.SysBizAudit().Record(ctx, &sysin.BizAuditRecordInp{Module: "task", Action: "task.status", TargetType: "task", TargetId: in.Id, After: g.Map{"publishStatus": in.PublishStatus}}) } func (s *sSysTask) Delete(ctx context.Context, in *sysin.TaskDeleteInp) error { c := dao.Task.Columns() var row *entity.Task if err := s.Model(ctx).WherePri(in.Id).Scan(&row); err != nil { return err } if row == nil { return gerror.New("任务不存在") } count, err := handler.Model(dao.TradeOrder.Ctx(ctx), &handler.Option{FilterTenant: true}).Where(dao.TradeOrder.Columns().TaskId, in.Id).Count() if err != nil { return err } if count > 0 { return gerror.New("任务已被订单引用,只允许下线,不能删除") } if row.PublishStatus == consts.BizPublishPublished { _, err = s.Model(ctx).WherePri(in.Id).Data(g.Map{c.PublishStatus: consts.BizPublishOffline, c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update() return err } return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { if _, e := s.relationModel(ctx).Where(dao.TaskLevel.Columns().TaskId, in.Id).Delete(); e != nil { return e } _, e := s.Model(ctx).WherePri(in.Id).Data(g.Map{c.DeletedAt: gtime.Now(), c.DeletedBy: contexts.GetUserId(ctx), c.UpdatedBy: contexts.GetUserId(ctx)}).Update() return gerror.Wrap(e, "删除任务失败") }) }