refactor: separate backend domains and storage adapters
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kra/internal/biz"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type departmentPO struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
Name string `gorm:"index"`
|
||||
ParentID uint
|
||||
Ancestors string
|
||||
Sort int
|
||||
LeaderID uint
|
||||
Status bool `gorm:"default:true"`
|
||||
}
|
||||
|
||||
func (departmentPO) TableName() string { return "sys_departments" }
|
||||
|
||||
type userDepartmentPO struct {
|
||||
UserID uint `gorm:"primaryKey;column:sys_user_id"`
|
||||
DepartmentID uint `gorm:"primaryKey;column:sys_department_id"`
|
||||
}
|
||||
|
||||
func (userDepartmentPO) TableName() string { return "sys_user_departments" }
|
||||
|
||||
type authorityDepartmentPO struct {
|
||||
AuthorityID uint `gorm:"primaryKey;column:authority_id"`
|
||||
DepartmentID uint `gorm:"primaryKey;column:department_id"`
|
||||
}
|
||||
|
||||
func (authorityDepartmentPO) TableName() string { return "sys_authority_departments" }
|
||||
|
||||
func deptFromPO(po departmentPO) *biz.Department {
|
||||
return &biz.Department{ID: po.ID, CreatedAt: po.CreatedAt, UpdatedAt: po.UpdatedAt, Name: po.Name, ParentID: po.ParentID, Ancestors: po.Ancestors, Sort: po.Sort, LeaderID: po.LeaderID, Status: po.Status}
|
||||
}
|
||||
func (r *organizationRepo) CreateDepartment(ctx context.Context, v *biz.Department) error {
|
||||
v.Ancestors = "0"
|
||||
if v.ParentID != 0 {
|
||||
var parent departmentPO
|
||||
if err := r.data.gormDB.WithContext(ctx).First(&parent, v.ParentID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
v.Ancestors = strings.Trim(parent.Ancestors+","+strconv.FormatUint(uint64(parent.ID), 10), ",")
|
||||
}
|
||||
return r.data.gormDB.WithContext(ctx).Create(&departmentPO{Name: v.Name, ParentID: v.ParentID, Ancestors: v.Ancestors, Sort: v.Sort, LeaderID: v.LeaderID, Status: v.Status}).Error
|
||||
}
|
||||
func (r *organizationRepo) UpdateDepartment(ctx context.Context, v *biz.Department) error {
|
||||
if v.ParentID == v.ID {
|
||||
return errors.New("父部门不能是自己")
|
||||
}
|
||||
v.Ancestors = "0"
|
||||
if v.ParentID != 0 {
|
||||
var parent departmentPO
|
||||
if err := r.data.gormDB.WithContext(ctx).First(&parent, v.ParentID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
v.Ancestors = strings.Trim(parent.Ancestors+","+strconv.FormatUint(uint64(parent.ID), 10), ",")
|
||||
}
|
||||
return r.data.gormDB.WithContext(ctx).Model(&departmentPO{}).Where("id = ?", v.ID).Updates(map[string]any{"name": v.Name, "parent_id": v.ParentID, "ancestors": v.Ancestors, "sort": v.Sort, "leader_id": v.LeaderID, "status": v.Status}).Error
|
||||
}
|
||||
func (r *organizationRepo) DeleteDepartment(ctx context.Context, id uint) error {
|
||||
if id == 0 {
|
||||
return errors.New("部门ID不能为空")
|
||||
}
|
||||
var count int64
|
||||
if err := r.data.gormDB.WithContext(ctx).Model(&departmentPO{}).Where("parent_id = ?", id).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("存在子部门,不允许删除")
|
||||
}
|
||||
if err := r.data.gormDB.WithContext(ctx).Model(&userPO{}).Where("dept_id = ?", id).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("该部门下存在用户,不允许删除")
|
||||
}
|
||||
if err := r.data.gormDB.WithContext(ctx).Model(&userDepartmentPO{}).Where("sys_department_id = ?", id).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("该部门下存在用户,不允许删除")
|
||||
}
|
||||
return r.data.gormDB.WithContext(ctx).Delete(&departmentPO{}, id).Error
|
||||
}
|
||||
func (r *organizationRepo) FindDepartment(ctx context.Context, id uint) (*biz.Department, error) {
|
||||
var po departmentPO
|
||||
if err := r.data.gormDB.WithContext(ctx).First(&po, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return deptFromPO(po), nil
|
||||
}
|
||||
func (r *organizationRepo) ListDepartments(ctx context.Context, name string) ([]*biz.Department, error) {
|
||||
var pos []departmentPO
|
||||
db := r.data.gormDB.WithContext(ctx).Order("sort,id")
|
||||
if name != "" {
|
||||
db = db.Where("name LIKE ?", "%"+name+"%")
|
||||
}
|
||||
if err := db.Find(&pos).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodes := map[uint]*biz.Department{}
|
||||
for _, po := range pos {
|
||||
nodes[po.ID] = deptFromPO(po)
|
||||
}
|
||||
var roots []*biz.Department
|
||||
for _, po := range pos {
|
||||
n := nodes[po.ID]
|
||||
if p := nodes[po.ParentID]; p != nil {
|
||||
p.Children = append(p.Children, n)
|
||||
} else {
|
||||
roots = append(roots, n)
|
||||
}
|
||||
}
|
||||
return roots, nil
|
||||
}
|
||||
func (r *organizationRepo) DepartmentUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
var ids []uint
|
||||
err := r.data.gormDB.WithContext(ctx).Model(&userDepartmentPO{}).Where("sys_department_id = ?", id).Pluck("sys_user_id", &ids).Error
|
||||
return ids, err
|
||||
}
|
||||
func (r *organizationRepo) SetDepartmentUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
return r.replaceUserDepartments(ctx, id, ids)
|
||||
}
|
||||
func (r *organizationRepo) replaceUserDepartments(ctx context.Context, id uint, ids []uint) error {
|
||||
if id == 0 {
|
||||
return errors.New("部门ID不能为空")
|
||||
}
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var current []uint
|
||||
if err := tx.Model(&userDepartmentPO{}).Where("sys_department_id = ?", id).Pluck("sys_user_id", ¤t).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_department_id = ?", id).Delete(&userDepartmentPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
links := make([]userDepartmentPO, 0, len(ids))
|
||||
for _, uid := range ids {
|
||||
links = append(links, userDepartmentPO{UserID: uid, DepartmentID: id})
|
||||
}
|
||||
if len(links) > 0 {
|
||||
if err := tx.Create(&links).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
target := make(map[uint]struct{}, len(ids))
|
||||
for _, uid := range ids {
|
||||
target[uid] = struct{}{}
|
||||
}
|
||||
removed := make([]uint, 0)
|
||||
for _, uid := range current {
|
||||
if _, ok := target[uid]; !ok {
|
||||
removed = append(removed, uid)
|
||||
}
|
||||
}
|
||||
if len(removed) > 0 {
|
||||
if err := tx.Model(&userPO{}).Where("dept_id = ? AND id IN ?", id, removed).Update("dept_id", 0).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
if err := tx.Model(&userPO{}).Where("dept_id = ? AND id IN ?", 0, ids).Update("dept_id", id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
func (r *organizationRepo) SetUserDepartments(ctx context.Context, uid uint, ids []uint, primary uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var user userPO
|
||||
if err := tx.First(&user, uid).Error; err != nil {
|
||||
return errors.New("查询用户数据失败")
|
||||
}
|
||||
if err := tx.Where("sys_user_id = ?", uid).Delete(&userDepartmentPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
links := make([]userDepartmentPO, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
links = append(links, userDepartmentPO{UserID: uid, DepartmentID: id})
|
||||
}
|
||||
if len(links) > 0 {
|
||||
if err := tx.Create(&links).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if primary == 0 && len(ids) > 0 {
|
||||
primary = ids[0]
|
||||
}
|
||||
if primary != 0 {
|
||||
inSet := false
|
||||
for _, id := range ids {
|
||||
if id == primary {
|
||||
inSet = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !inSet {
|
||||
return errors.New("主部门必须在归属部门范围内")
|
||||
}
|
||||
}
|
||||
return tx.Model(&userPO{}).Where("id = ?", uid).Update("dept_id", primary).Error
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user