Files
kra-new/internal/data/business/team.go
T

173 lines
6.0 KiB
Go

package business
import (
"context"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"kra/internal/biz/business"
)
type teamRepo struct{ data Provider }
func NewTeamRepo(data Provider) business.TeamRepo { return &teamRepo{data: data} }
func (r *teamRepo) Members(ctx context.Context, scope business.UserScope) ([]*business.BusinessMember, error) {
db := r.data.DB().WithContext(ctx)
var rows []struct {
Account accountPO `gorm:"embedded"`
HireDate, Employment string
GroupID uint64
}
q := applyUserScope(db.Table("sys_users u").Where("u.deleted_at IS NULL AND u.level BETWEEN 1 AND 3"), scope, "u.")
if err := q.Select("u.*,p.username AS parent_user_name,mp.hire_date,mp.employment,gm.group_id").Joins("LEFT JOIN sys_users p ON p.id=u.parent_id AND p.deleted_at IS NULL").Joins("LEFT JOIN sys_business_member_profiles mp ON mp.user_id=u.id").Joins("LEFT JOIN sys_business_group_members gm ON gm.user_id=u.id").Order("u.id").Scan(&rows).Error; err != nil {
return nil, business.ErrStorage
}
ids := make([]uint, 0, len(rows))
for _, row := range rows {
ids = append(ids, row.Account.ID)
}
counts, err := (&accountRepo{data: r.data}).DirectCounts(ctx, ids)
if err != nil {
return nil, err
}
out := make([]*business.BusinessMember, 0, len(rows))
for _, row := range rows {
a := toBizAccount(row.Account)
a.Password = ""
a.PromoteCount = counts[a.ID].PromoteCount
a.BindCount = counts[a.ID].BindCount
employment := row.Employment
if employment == "" {
employment = "employed"
if a.Status != 0 {
employment = "departed"
}
}
a.HireDate, a.Employment = row.HireDate, employment
out = append(out, &business.BusinessMember{Account: *a, GroupID: row.GroupID})
}
return out, nil
}
func readTeamCatalog(db *gorm.DB) (*business.TeamCatalog, error) {
var state businessGroupStatePO
if err := db.First(&state, "id=1").Error; err != nil {
return nil, business.ErrStorage
}
var groups []businessGroupPO
if err := db.Order("sort,id").Find(&groups).Error; err != nil {
return nil, business.ErrStorage
}
var members []businessGroupMemberPO
if err := db.Order("user_id").Find(&members).Error; err != nil {
return nil, business.ErrStorage
}
byGroup := map[uint64][]uint{}
for _, m := range members {
byGroup[m.GroupID] = append(byGroup[m.GroupID], m.UserID)
}
out := &business.TeamCatalog{Revision: state.Revision, Groups: []*business.BusinessGroup{}}
for _, g := range groups {
out.Groups = append(out.Groups, &business.BusinessGroup{ID: g.ID, Name: g.Name, OwnerID: g.OwnerID, Sort: g.Sort, MemberIDs: append([]uint{}, byGroup[g.ID]...)})
}
return out, nil
}
func (r *teamRepo) Catalog(ctx context.Context) (*business.TeamCatalog, error) {
var value *business.TeamCatalog
err := r.data.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error { var err error; value, err = readTeamCatalog(tx); return err })
return value, storageError(err)
}
func (r *teamRepo) SaveCatalog(ctx context.Context, revision uint64, groups []*business.BusinessGroup) (*business.TeamCatalog, error) {
db := r.data.DB().WithContext(ctx)
err := db.Transaction(func(tx *gorm.DB) error {
updated := tx.Model(&businessGroupStatePO{}).Where("id=1 AND revision=?", revision).Update("revision", gorm.Expr("revision+1"))
if updated.Error != nil {
return updated.Error
}
if updated.RowsAffected != 1 {
return business.ErrTeamConflict
}
var current []businessGroupPO
if err := tx.Find(&current).Error; err != nil {
return err
}
byID := map[uint64]businessGroupPO{}
for _, g := range current {
byID[g.ID] = g
}
ids := []uint64{}
members := []businessGroupMemberPO{}
for _, g := range groups {
po := businessGroupPO{ID: g.ID, Name: g.Name, OwnerID: g.OwnerID, Sort: g.Sort}
if g.ID == 0 {
if err := tx.Create(&po).Error; err != nil {
return err
}
} else {
old, exists := byID[g.ID]
if !exists {
return business.ErrTeamConflict
}
if old.Name != g.Name || old.Sort != g.Sort {
if err := tx.Model(&businessGroupPO{}).Where("id=?", g.ID).Updates(map[string]any{"name": g.Name, "sort": g.Sort, "updated_at": time.Now()}).Error; err != nil {
return err
}
}
}
ids = append(ids, po.ID)
for _, id := range g.MemberIDs {
members = append(members, businessGroupMemberPO{UserID: id, GroupID: po.ID})
}
}
deleted := tx.Model(&businessGroupPO{})
if len(ids) > 0 {
deleted = deleted.Where("id NOT IN ?", ids)
} else {
deleted = deleted.Where("1=1")
}
if err := deleted.Delete(&businessGroupPO{}).Error; err != nil {
return err
}
if err := tx.Where("1=1").Delete(&businessGroupMemberPO{}).Error; err != nil {
return err
}
if len(members) > 0 {
if err := tx.CreateInBatches(&members, 300).Error; err != nil {
return err
}
}
return nil
})
if err != nil {
return nil, storageError(err)
}
return r.Catalog(ctx)
}
func (r *teamRepo) UpdateProfile(ctx context.Context, p business.MemberProfile) error {
return storageError(r.data.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var account accountPO
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&account, p.ID).Error; err != nil {
return err
}
domain := toBizAccount(account)
domain.Phone = p.Phone
if err := checkAccountUnique(tx, domain); err != nil {
return err
}
status, enable := 0, 1
if p.Employment == "departed" {
status, enable = 1, 0
}
values := map[string]any{"real_name": p.RealName, "phone": p.Phone, "business_status": status, "enable": enable, "updated_at": time.Now()}
if p.Password != "" {
values["password"] = p.Password
values["password_updated_at"] = time.Now()
}
if err := tx.Model(&accountPO{}).Where("id=?", p.ID).Updates(values).Error; err != nil {
return err
}
return tx.Clauses(clause.OnConflict{Columns: []clause.Column{{Name: "user_id"}}, DoUpdates: clause.AssignmentColumns([]string{"hire_date", "employment", "updated_at"})}).Create(&businessMemberProfilePO{UserID: p.ID, HireDate: p.HireDate, Employment: p.Employment, UpdatedAt: time.Now()}).Error
}))
}