173 lines
6.0 KiB
Go
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(¤t).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
|
|
}))
|
|
}
|