package agent import ( "context" "errors" "fmt" "strconv" "strings" "time" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/event" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/rolepolicy" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/do" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility" "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" ) type sAgentDept struct { *sAgentMenu } func NewAgentDept() *sAgentDept { return &sAgentDept{ sAgentMenu: &sAgentMenu{ agentBase: newAgentBase(), }, } } func init() { service.RegisterAgentDept(NewAgentDept()) } func (s *sAgentDept) DeptList(ctx context.Context, in *model.AgentDeptListParam) (list []*model.AgentEnterpriseCustomerModel, total int, err error) { currentDeptId := contexts.GetDeptId(ctx) if currentDeptId == 0 { return nil, 0, gerror.New("当前用户未绑定组织") } m := s.deptModel(ctx). Where(dao.SysDept.Columns().ParentId, currentDeptId). Where(dao.SysDept.Columns().DeptType, 1) if in.DeptName != "" { m = m.WhereLike(dao.SysDept.Columns().DeptName, "%"+in.DeptName+"%") } if in.Status != "" { m = m.Where(dao.SysDept.Columns().Status, in.Status) } err = m.Order(dao.SysDept.Columns().DeptId, "ASC"). Scan(&list) if err != nil { return nil, 0, err } if err = s.fillEnterpriseDefaultUsers(ctx, list); err != nil { return nil, 0, err } return list, len(list), nil } func (s *sAgentDept) DeptView(ctx context.Context, deptId int64) (res *model.AgentEnterpriseCustomerModel, err error) { if err = s.ensureEnterpriseDept(ctx, deptId); err != nil { return nil, err } err = s.deptModel(ctx).Where(dao.SysDept.Columns().DeptId, deptId).Scan(&res) if err != nil { return nil, err } if res == nil || res.DeptId == 0 { return nil, gerror.New("企业客户不存在") } if err = s.fillEnterpriseDefaultUsers(ctx, []*model.AgentEnterpriseCustomerModel{res}); err != nil { return nil, err } return res, nil } func (s *sAgentDept) DeptSave(ctx context.Context, in *model.AgentDeptSaveParam) (deptId int64, err error) { user := contexts.GetUser(ctx) if user == nil { return 0, gerror.New("登录已过期") } if user.DeptId == 0 { return 0, gerror.New("当前用户未绑定组织") } if err = s.validateEnterpriseSave(ctx, user.TenantId, in); err != nil { return 0, err } var roleId, userId int64 isAdd := in.DeptId == 0 err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { if isAdd { deptId, roleId, userId, err = s.addEnterpriseDept(ctx, tx, user, in) return err } deptId = in.DeptId roleId, userId, err = s.editEnterpriseDept(ctx, tx, user, in) return err }) if err != nil { return 0, err } if err = service.SysDept().RefreshDeptAncestors(ctx); err != nil { return 0, err } if isAdd { event.EventsInstance().Emit(ctx, consts.EventKeyDBSysDeptCreate, deptId) event.EventsInstance().Emit(ctx, consts.EventKeyDBSysRoleCreate, roleId) event.EventsInstance().Emit(ctx, consts.EventKeyUserCreate, userId) } else { event.EventsInstance().Emit(ctx, consts.EventKeyDBSysDeptUpdate, deptId) event.EventsInstance().Emit(ctx, consts.EventKeyDBSysRoleUpdate, roleId) event.EventsInstance().Emit(ctx, consts.EventKeyUserUpdate, userId) } return deptId, nil } // EnsureCurrentDeptDefaultRole upgrades legacy child enterprises that did not // receive an inherited administrator role when they were created. func (s *sAgentDept) EnsureCurrentDeptDefaultRole(ctx context.Context) error { user := contexts.GetUser(ctx) if user == nil { return gerror.New("登录已过期") } deptId := contexts.GetDeptId(ctx) if deptId == 0 { return gerror.New("当前用户未绑定组织") } var dept *entity.SysDept if err := s.deptModel(ctx). Where(dao.SysDept.Columns().DeptId, deptId). Scan(&dept); err != nil { return err } if dept == nil || dept.DeptId == 0 { return gerror.New("组织不存在") } if dept.DeptType != 1 || dept.DeptRole != 0 { return nil } sourceRole, menuIds, err := s.passRoleByDept(ctx, dept.ParentId) if err != nil { return err } return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { var current *entity.SysDept if err := tx.Ctx(ctx).Model(dao.SysDept.Table()). Where(dao.SysDept.Columns().DeptId, deptId). Scan(¤t); err != nil { return err } if current == nil || current.DeptId == 0 { return gerror.New("组织不存在") } if current.DeptRole != 0 { return nil } roleId, err := s.createEnterpriseRole(ctx, tx, user, deptId, sourceRole, menuIds) if err != nil { return err } if err := s.updateDeptRole(ctx, tx, deptId, roleId, user.ID); err != nil { return err } // Keep the legacy role for the active session. After re-login, this role // becomes the department's selected default administrator role. _, err = tx.Ctx(ctx).Model(dao.SysUserRole.Table()). Data(do.SysUserRole{UserId: user.ID, RoleId: roleId}). OmitNil().Insert() return err }) } func (s *sAgentDept) validateEnterpriseSave(ctx context.Context, tenantId string, in *model.AgentDeptSaveParam) error { in.DeptName = strings.TrimSpace(in.DeptName) in.UserName = strings.TrimSpace(in.UserName) in.Password = strings.TrimSpace(in.Password) in.Phone = strings.TrimSpace(in.Phone) in.Email = strings.TrimSpace(in.Email) in.AreaCode = strings.TrimSpace(in.AreaCode) in.Address = strings.TrimSpace(in.Address) in.CreditCode = strings.TrimSpace(in.CreditCode) if in.DeptName == "" { return gerror.New("企业名称不能为空") } if in.UserName == "" { return gerror.New("登录账号不能为空") } if in.DeptId == 0 && in.Password == "" { return gerror.New("密码不能为空") } var excludeUserId int64 if in.DeptId > 0 { if err := s.ensureEnterpriseDept(ctx, in.DeptId); err != nil { return err } defaultUser, err := s.defaultUserByDept(ctx, in.DeptId, 0) if err != nil { return err } if defaultUser != nil { excludeUserId = defaultUser.UserId } } return s.ensureUserNameUnique(ctx, tenantId, in.UserName, excludeUserId) } func (s *sAgentDept) addEnterpriseDept(ctx context.Context, tx gdb.TX, user *model.Identity, in *model.AgentDeptSaveParam) (deptId, roleId, userId int64, err error) { now := gtime.Now() deptKey, err := s.nextCustomerDeptKey(ctx) if err != nil { return 0, 0, 0, err } ancestors, err := s.childDeptAncestors(ctx, user.DeptId) if err != nil { return 0, 0, 0, err } deptId, err = tx.Ctx(ctx).Model(dao.SysDept.Table()).Data(do.SysDept{ TenantId: user.TenantId, ParentId: user.DeptId, Ancestors: ancestors, DeptKey: deptKey, DeptName: in.DeptName, DeptType: 1, DeptCategory: in.DeptCategory, OrderNum: in.OrderNum, Phone: in.Phone, Email: in.Email, Status: consts.SysDeptStatusNormal, CreditCode: in.CreditCode, AreaCode: in.AreaCode, Address: in.Address, CreatedDept: user.DeptId, CreatedBy: user.ID, CreatedAt: now, UpdatedBy: user.ID, UpdatedAt: now, }).OmitNil().InsertAndGetId() if err != nil { return 0, 0, 0, err } passRole, menuIds, err := s.currentDeptPassRole(ctx) if err != nil { return 0, 0, 0, err } roleId, err = s.createEnterpriseRole(ctx, tx, user, deptId, passRole, menuIds) if err != nil { return 0, 0, 0, err } if err = s.updateDeptRole(ctx, tx, deptId, roleId, user.ID); err != nil { return 0, 0, 0, err } userId, err = s.createEnterpriseUser(ctx, tx, user, deptId, roleId, in) if err != nil { return 0, 0, 0, err } if err = s.updateDeptLeader(ctx, tx, deptId, userId, user.ID); err != nil { return 0, 0, 0, err } return deptId, roleId, userId, nil } func (s *sAgentDept) editEnterpriseDept(ctx context.Context, tx gdb.TX, user *model.Identity, in *model.AgentDeptSaveParam) (roleId, userId int64, err error) { var dept *entity.SysDept if err = s.deptModel(ctx).Where(dao.SysDept.Columns().DeptId, in.DeptId).Scan(&dept); err != nil { return 0, 0, err } if dept == nil || dept.DeptId == 0 { return 0, 0, gerror.New("企业客户不存在") } ancestors, err := s.childDeptAncestors(ctx, user.DeptId) if err != nil { return 0, 0, err } _, err = tx.Ctx(ctx).Model(dao.SysDept.Table()). Where(dao.SysDept.Columns().DeptId, in.DeptId). Data(do.SysDept{ DeptName: in.DeptName, DeptType: 1, ParentId: user.DeptId, Ancestors: ancestors, Phone: in.Phone, Email: in.Email, Status: consts.SysDeptStatusNormal, CreditCode: in.CreditCode, AreaCode: in.AreaCode, Address: in.Address, UpdatedBy: user.ID, UpdatedAt: gtime.Now(), }).OmitNil().Update() if err != nil { return 0, 0, err } roleId = dept.DeptRole if roleId == 0 { passRole, menuIds, err := s.currentDeptPassRole(ctx) if err != nil { return 0, 0, err } roleId, err = s.createEnterpriseRole(ctx, tx, user, in.DeptId, passRole, menuIds) if err != nil { return 0, 0, err } if err = s.updateDeptRole(ctx, tx, in.DeptId, roleId, user.ID); err != nil { return 0, 0, err } } else if err = s.updateEnterpriseRole(ctx, tx, user, in.DeptId, roleId); err != nil { return 0, 0, err } defaultUser, err := s.defaultUserByDept(ctx, in.DeptId, roleId) if err != nil { return 0, 0, err } if defaultUser == nil { userId, err = s.createEnterpriseUser(ctx, tx, user, in.DeptId, roleId, in) if err != nil { return 0, 0, err } } else { userId = defaultUser.UserId if err = s.updateEnterpriseUser(ctx, tx, user, userId, in.DeptId, roleId, in); err != nil { return 0, 0, err } } if err = s.updateDeptLeader(ctx, tx, in.DeptId, userId, user.ID); err != nil { return 0, 0, err } return roleId, userId, nil } func (s *sAgentDept) createEnterpriseRole(ctx context.Context, tx gdb.TX, user *model.Identity, deptId int64, sourceRole *entity.SysRole, roleMenus []*entity.SysRoleMenu) (roleId int64, err error) { now := gtime.Now() roleId, err = tx.Ctx(ctx).Model(dao.SysRole.Table()).Data(do.SysRole{ TenantId: user.TenantId, DeptId: deptId, RoleName: strings.TrimSpace(sourceRole.RoleName), RoleKey: sourceRole.RoleKey, RoleSort: 0, DataScope: consts.SysRoleDataScopeDeptAndBelow, MenuCheckStrictly: 1, DeptCheckStrictly: 1, IsPass: 0, Status: "0", CreatedDept: user.DeptId, CreatedBy: user.ID, CreatedAt: now, UpdatedBy: user.ID, UpdatedAt: now, }).OmitNil().InsertAndGetId() if err != nil { return 0, err } if err = s.copyRoleMenus(ctx, tx, roleId, roleMenus); err != nil { return 0, err } if err = s.replaceRoleDepts(ctx, tx, roleId, deptId); err != nil { return 0, err } return roleId, nil } func inheritedRoleName(name string) string { // Inherited roles keep the source role name; source fields identify the inheritance. return strings.TrimSpace(name) } func (s *sAgentDept) updateEnterpriseRole(ctx context.Context, tx gdb.TX, user *model.Identity, deptId, roleId int64) error { _, err := tx.Ctx(ctx).Model(dao.SysRole.Table()). Where(dao.SysRole.Columns().RoleId, roleId). Where(dao.SysRole.Columns().DeptId, deptId). Data(do.SysRole{ DataScope: consts.SysRoleDataScopeDeptAndBelow, MenuCheckStrictly: 1, DeptCheckStrictly: 1, Status: "0", UpdatedBy: user.ID, UpdatedAt: gtime.Now(), }).OmitNil().Update() if err != nil { return err } return s.replaceRoleDepts(ctx, tx, roleId, deptId) } func (s *sAgentDept) createEnterpriseUser(ctx context.Context, tx gdb.TX, user *model.Identity, deptId, roleId int64, in *model.AgentDeptSaveParam) (userId int64, err error) { now := gtime.Now() salt := utility.RandomString(5) password := utility.PasswordEncrypt(in.Password, salt) userId, err = tx.Ctx(ctx).Model(dao.SysUser.Table()).Data(do.SysUser{ TenantId: user.TenantId, DeptId: deptId, UserName: in.UserName, NickName: in.DeptName, UserType: consts.SysUserTypeSys, Email: in.Email, Phonenumber: in.Phone, Sex: consts.SysUserSexUnknown, Salt: salt, Password: password, IsInitPassword: 1, // 管理员设置的初始密码,登录后引导修改(与用户管理处新增保持一致) Status: consts.SysUserStatusNormal, CreatedDept: user.DeptId, CreatedBy: user.ID, CreatedAt: now, UpdatedBy: user.ID, UpdatedAt: now, }).OmitNil().InsertAndGetId() if err != nil { return 0, err } return userId, s.replaceUserRole(ctx, tx, userId, roleId) } func (s *sAgentDept) updateEnterpriseUser(ctx context.Context, tx gdb.TX, user *model.Identity, userId, deptId, roleId int64, in *model.AgentDeptSaveParam) error { userData := do.SysUser{ DeptId: deptId, UserName: in.UserName, UserType: consts.SysUserTypeSys, Email: in.Email, Phonenumber: in.Phone, Sex: consts.SysUserSexUnknown, Status: consts.SysUserStatusNormal, UpdatedBy: user.ID, UpdatedAt: gtime.Now(), } if nickName := strings.TrimSpace(in.NickName); nickName != "" { userData.NickName = nickName } _, err := tx.Ctx(ctx).Model(dao.SysUser.Table()). Where(dao.SysUser.Columns().UserId, userId). Data(userData).OmitNil().Update() if err != nil { return err } return s.replaceUserRole(ctx, tx, userId, roleId) } func (s *sAgentDept) updateDeptRole(ctx context.Context, tx gdb.TX, deptId, roleId, userId int64) error { _, err := tx.Ctx(ctx).Model(dao.SysDept.Table()). Where(dao.SysDept.Columns().DeptId, deptId). Data(do.SysDept{DeptRole: roleId, UpdatedBy: userId, UpdatedAt: gtime.Now()}). OmitNil().Update() return err } func (s *sAgentDept) updateDeptLeader(ctx context.Context, tx gdb.TX, deptId, leader, userId int64) error { _, err := tx.Ctx(ctx).Model(dao.SysDept.Table()). Where(dao.SysDept.Columns().DeptId, deptId). Data(do.SysDept{Leader: leader, UpdatedBy: userId, UpdatedAt: gtime.Now()}). OmitNil().Update() return err } // copyRoleMenus copies the already-authorized menu set of the creator's effective role. func (s *sAgentDept) copyRoleMenus(ctx context.Context, tx gdb.TX, roleId int64, roleMenus []*entity.SysRoleMenu) error { if _, err := tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()). Where(dao.SysRoleMenu.Columns().RoleId, roleId).Delete(); err != nil { return err } if len(roleMenus) == 0 { return nil } data := make([]do.SysRoleMenu, 0, len(roleMenus)) for _, roleMenu := range roleMenus { data = append(data, do.SysRoleMenu{ TenantId: contexts.GetTenantId(ctx), RoleId: roleId, MenuId: roleMenu.MenuId, DataScope: roleMenu.DataScope, }) } _, err := tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()).Data(data).OmitNil().Insert() return err } func (s *sAgentDept) currentDeptPassRole(ctx context.Context) (*entity.SysRole, []*entity.SysRoleMenu, error) { return s.passRoleByDept(ctx, contexts.GetDeptId(ctx)) } func (s *sAgentDept) passRoleByDept(ctx context.Context, deptId int64) (*entity.SysRole, []*entity.SysRoleMenu, error) { template, err := rolepolicy.Template(ctx) if err != nil { return nil, nil, err } if template != nil && contexts.GetTenantId(ctx) == template.TenantId { // 配置了平台模板后,下发来源不再依赖 is_pass=1: // 一级代理由平台模板推出,其默认角色是复制来的 is_pass=0 角色; // 各级代理再创建下级时,必须能从本机构默认角色(sys_dept.dept_role)继续传递, // 否则二级及以下代理永远建不了下级。 source := template if deptId != template.DeptId { var dept *entity.SysDept if err := s.deptModel(ctx).Where(dao.SysDept.Columns().DeptId, deptId). Where(dao.SysDept.Columns().Status, consts.SysDeptStatusNormal). Scan(&dept); err != nil { return nil, nil, err } if dept == nil || dept.DeptId == 0 { return nil, nil, gerror.New("当前机构不存在或已停用") } if dept.DeptRole <= 0 { return nil, nil, gerror.Newf("机构%d未关联默认角色,请联系平台管理员核对机构角色绑定", deptId) } source, err = s.defaultRoleForPass(ctx, deptId, dept.DeptRole) if err != nil { return nil, nil, err } } var menus []*entity.SysRoleMenu if err := dao.SysRoleMenu.Ctx(ctx).Where("role_id", source.RoleId).Scan(&menus); err != nil { return nil, nil, err } ids := make([]int64, 0, len(menus)) for _, menu := range menus { ids = append(ids, menu.MenuId) } allowed, err := rolepolicy.RestrictMenus(ctx, template.TenantId, deptId, ids) if err != nil { return nil, nil, err } selected := make(map[int64]bool) for _, id := range allowed { selected[id] = true } result := make([]*entity.SysRoleMenu, 0, len(menus)) for _, menu := range menus { if selected[menu.MenuId] { copy := *menu copy.DataScope = consts.SysRoleMenuDataScopeRole result = append(result, ©) } } return source, result, nil } var roles []*entity.SysRole if err := s.roleModel(ctx). Where(dao.SysRole.Columns().DeptId, deptId). Where(dao.SysRole.Columns().Status, "0"). Where("is_pass", 1). Scan(&roles); err != nil { return nil, nil, err } if len(roles) != 1 { return nil, nil, gerror.New("请先在角色管理配置唯一的下级管理员角色") } var roleMenus []*entity.SysRoleMenu if err := dao.SysRoleMenu.Ctx(ctx). Where(dao.SysRoleMenu.Columns().RoleId, roles[0].RoleId). OrderAsc(dao.SysRoleMenu.Columns().MenuId). Scan(&roleMenus); err != nil { return nil, nil, err } return roles[0], roleMenus, nil } // defaultRoleForPass resolves the org's bound default role (sys_dept.dept_role) as // the distribution source. Configured platform template owners keep using the // template role itself; everyone else must have a live default role bound. func (s *sAgentDept) defaultRoleForPass(ctx context.Context, deptId, deptRoleId int64) (*entity.SysRole, error) { var role *entity.SysRole if err := s.roleModel(ctx). Where(dao.SysRole.Columns().RoleId, deptRoleId). Where(dao.SysRole.Columns().DeptId, deptId). Where(dao.SysRole.Columns().Status, "0"). Scan(&role); err != nil { return nil, err } if role == nil || role.RoleId == 0 { return nil, gerror.Newf("机构%d默认角色不存在、已停用或归属不匹配,请联系平台管理员核对", deptId) } return role, nil } // currentUserEffectiveRoleMenuIds returns the menu set of the role that authorized // the current request. The child administrator receives a copy, never the parent role. func (s *sAgentDept) currentUserEffectiveRoleMenuIds(ctx context.Context, user *model.Identity) ([]int64, error) { roleId, err := s.currentUserEffectiveRoleId(ctx, user) if err != nil { return nil, err } var roleMenus []*entity.SysRoleMenu if err = dao.SysRoleMenu.Ctx(ctx). Where(dao.SysRoleMenu.Columns().RoleId, roleId). OrderAsc(dao.SysRoleMenu.Columns().MenuId). Scan(&roleMenus); err != nil { return nil, err } menuIds := make([]int64, 0, len(roleMenus)) for _, roleMenu := range roleMenus { menuIds = append(menuIds, roleMenu.MenuId) } return menuIds, nil } func (s *sAgentDept) currentUserEffectiveRoleId(ctx context.Context, user *model.Identity) (int64, error) { if user == nil { return 0, gerror.New("登录已过期") } roleId := int64(0) if currentRoleId := contexts.GetDataValue(ctx, "currentRoleId"); currentRoleId != nil { roleIdStr, ok := currentRoleId.(string) if !ok { return 0, gerror.New("当前生效角色异常") } parsedRoleId, err := strconv.ParseInt(roleIdStr, 10, 64) if err != nil || parsedRoleId <= 0 { return 0, gerror.New("当前生效角色异常") } roleId = parsedRoleId } else { defaultRoleId, err := s.currentDeptDefaultRoleId(ctx) if err != nil { return 0, err } for _, role := range user.Roles { if role.RoleId == defaultRoleId { roleId = role.RoleId break } } if roleId == 0 && len(user.Roles) == 1 { roleId = user.Roles[0].RoleId } } if roleId <= 0 { return 0, gerror.New("无法确定当前用户的有效角色") } count, err := dao.SysUserRole.Ctx(ctx). Where(dao.SysUserRole.Columns().UserId, user.ID). Where(dao.SysUserRole.Columns().RoleId, roleId). Count() if err != nil { return 0, err } if count == 0 { return 0, gerror.New("当前生效角色未绑定登录用户") } return roleId, nil } func (s *sAgentDept) replaceRoleDepts(ctx context.Context, tx gdb.TX, roleId, deptId int64) error { if _, err := tx.Ctx(ctx).Model(dao.SysRoleDept.Table()). Where(dao.SysRoleDept.Columns().RoleId, roleId).Delete(); err != nil { return err } _, err := tx.Ctx(ctx).Model(dao.SysRoleDept.Table()). Data(do.SysRoleDept{RoleId: roleId, DeptId: deptId}).OmitNil().Insert() return err } func (s *sAgentDept) replaceUserRole(ctx context.Context, tx gdb.TX, userId, roleId int64) error { if _, err := tx.Ctx(ctx).Model(dao.SysUserRole.Table()). Where(dao.SysUserRole.Columns().UserId, userId).Delete(); err != nil { return err } _, err := tx.Ctx(ctx).Model(dao.SysUserRole.Table()). Data(do.SysUserRole{UserId: userId, RoleId: roleId}).OmitNil().Insert() return err } func (s *sAgentDept) childDeptAncestors(ctx context.Context, parentId int64) (string, error) { var parent *entity.SysDept if err := s.deptModel(ctx). Where(dao.SysDept.Columns().DeptId, parentId). Scan(&parent); err != nil { return "", err } if parent == nil || parent.DeptId == 0 { return "", gerror.New("父级组织不存在") } ancestors := strings.Trim(parent.Ancestors, ",") if ancestors == "" { ancestors = "0" } return fmt.Sprintf("%s,%d", ancestors, parent.DeptId), nil } func (s *sAgentDept) nextCustomerDeptKey(ctx context.Context) (string, error) { prefix := "CUS-" + time.Now().Format("200601") seq := 1 var latest *entity.SysDept err := dao.SysDept.Ctx(ctx). WhereLike(dao.SysDept.Columns().DeptKey, prefix+"-%"). OrderDesc(dao.SysDept.Columns().DeptKey). Limit(1). Scan(&latest) if err != nil { return "", err } if latest != nil && latest.DeptKey != "" { parts := strings.Split(latest.DeptKey, "-") if len(parts) == 3 { if latestSeq, parseErr := strconv.Atoi(parts[2]); parseErr == nil { seq = latestSeq + 1 } } } for { deptKey := fmt.Sprintf("%s-%04d", prefix, seq) count, err := dao.SysDept.Ctx(ctx).Where(dao.SysDept.Columns().DeptKey, deptKey).Count() if err != nil { return "", err } if count == 0 { return deptKey, nil } seq++ } } func (s *sAgentDept) ensureUserNameUnique(ctx context.Context, tenantId, userName string, excludeUserId int64) error { m := dao.SysUser.Ctx(ctx). Where(dao.SysUser.Columns().TenantId, tenantId). Where(dao.SysUser.Columns().UserName, userName) if excludeUserId > 0 { m = m.WhereNot(dao.SysUser.Columns().UserId, excludeUserId) } count, err := m.Count() if err != nil { return err } if count > 0 { return gerror.New("登录账号已存在") } return nil } func (s *sAgentDept) fillEnterpriseDefaultUsers(ctx context.Context, list []*model.AgentEnterpriseCustomerModel) error { for _, dept := range list { user, err := s.defaultUserByDept(ctx, dept.DeptId, dept.DeptRole) if err != nil { return err } if user == nil { continue } dept.DefaultUserId = user.UserId dept.UserName = user.UserName dept.NickName = user.NickName } return nil } func (s *sAgentDept) defaultUserByDept(ctx context.Context, deptId, roleId int64) (*entity.SysUser, error) { if roleId == 0 { var dept *entity.SysDept if err := s.deptModel(ctx).Where(dao.SysDept.Columns().DeptId, deptId).Scan(&dept); err != nil { return nil, err } if dept != nil { roleId = dept.DeptRole } } if roleId > 0 { var userRole *entity.SysUserRole if err := dao.SysUserRole.Ctx(ctx). Where(dao.SysUserRole.Columns().RoleId, roleId). OrderAsc(dao.SysUserRole.Columns().UserId). Scan(&userRole); err != nil { return nil, err } if userRole != nil { var user *entity.SysUser if err := s.userModel(ctx). Where(dao.SysUser.Columns().UserId, userRole.UserId). Where(dao.SysUser.Columns().DeptId, deptId). Scan(&user); err != nil { return nil, err } if user != nil && user.UserId > 0 { return user, nil } } } var user *entity.SysUser err := s.userModel(ctx). Where(dao.SysUser.Columns().DeptId, deptId). OrderAsc(dao.SysUser.Columns().UserId). Scan(&user) return user, err } func (s *sAgentDept) ensureEnterpriseDept(ctx context.Context, deptId int64) error { currentDeptId := contexts.GetDeptId(ctx) if currentDeptId == 0 { return gerror.New("当前用户未绑定组织") } count, err := s.deptModel(ctx). Where(dao.SysDept.Columns().DeptId, deptId). Where(dao.SysDept.Columns().ParentId, currentDeptId). Where(dao.SysDept.Columns().DeptType, 1). Count() if err != nil { return err } if count == 0 { return gerror.New("只能操作下一级企业客户") } return nil } // DeptDelete 删除企业客户 func (s *sAgentDept) DeptDelete(ctx context.Context, deptId int64) (err error) { if err = s.ensureEnterpriseDept(ctx, deptId); err != nil { return err } user := contexts.GetUser(ctx) if user == nil { return gerror.New("登录已过期") } var dept *entity.SysDept if err = s.deptModel(ctx).Where(dao.SysDept.Columns().DeptId, deptId).Scan(&dept); err != nil { return err } if dept == nil || dept.DeptId == 0 { return gerror.New("企业客户不存在") } children, err := s.deptModel(ctx).Where(dao.SysDept.Columns().ParentId, deptId).Count() if err != nil { return err } if children > 0 { return gerror.New("该企业客户下有子组织,不能删除") } defaultUser, err := s.defaultUserByDept(ctx, deptId, dept.DeptRole) if err != nil { return err } users, err := s.userModel(ctx).Where(dao.SysUser.Columns().DeptId, deptId).Count() if err != nil { return err } if defaultUser == nil && users > 0 { return gerror.New("该企业客户下有用户,不能删除") } if defaultUser != nil && users > 1 { return gerror.New("该企业客户下有其他用户,不能删除") } err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { if _, err := tx.Ctx(ctx).Model(dao.TAgentEnterprise.Table()). Where(dao.TAgentEnterprise.Columns().DeptId, deptId).Unscoped().Delete(); err != nil { return gerror.Wrap(err, "删除企业客户单位信息失败,请稍后重试") } if defaultUser != nil { if _, err := tx.Ctx(ctx).Model(dao.SysUserRole.Table()). Where(dao.SysUserRole.Columns().UserId, defaultUser.UserId).Delete(); err != nil { return err } if _, err := tx.Ctx(ctx).Model(dao.SysUser.Table()). Where(dao.SysUser.Columns().UserId, defaultUser.UserId). Data(do.SysUser{DeletedBy: user.ID, DeletedAt: gtime.Now()}). OmitNil().Update(); err != nil { return err } } if dept.DeptRole > 0 { if _, err := tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()). Where(dao.SysRoleMenu.Columns().RoleId, dept.DeptRole).Delete(); err != nil { return err } if _, err := tx.Ctx(ctx).Model(dao.SysRoleDept.Table()). Where(dao.SysRoleDept.Columns().RoleId, dept.DeptRole).Delete(); err != nil { return err } if _, err := tx.Ctx(ctx).Model(dao.SysRole.Table()). Where(dao.SysRole.Columns().RoleId, dept.DeptRole). Data(do.SysRole{DeletedBy: user.ID, DeletedAt: gtime.Now()}). OmitNil().Update(); err != nil { return err } } _, err := tx.Ctx(ctx).Model(dao.SysDept.Table()). Where(dao.SysDept.Columns().DeptId, deptId). Data(do.SysDept{DeletedBy: user.ID, DeletedAt: gtime.Now()}). OmitNil().Update() return err }) if err != nil { return err } event.EventsInstance().Emit(ctx, consts.EventKeyDBSysDeptDelete, deptId) if dept.DeptRole > 0 { event.EventsInstance().Emit(ctx, consts.EventKeyDBSysRoleDelete, []int64{dept.DeptRole}) } if defaultUser != nil { event.EventsInstance().Emit(ctx, consts.EventKeyUserDelete, []int64{defaultUser.UserId}) } return nil } func (s *sAgentDept) DeptResetPassword(ctx context.Context, deptId int64, password string) (err error) { if strings.TrimSpace(password) == "" { return gerror.New("密码不能为空") } if err = s.ensureEnterpriseDept(ctx, deptId); err != nil { return err } user, err := s.defaultUserByDept(ctx, deptId, 0) if err != nil { return err } if user == nil || user.UserId == 0 { return gerror.New("企业客户默认用户不存在") } return service.SysUser().ResetPassword(ctx, user.UserId, password) } // GetDeptApiInfo 获取当前代理商组织的 API 集成信息 func (s *sAgentDept) GetDeptApiInfo(ctx context.Context) (res *model.AgentDeptApiModel, err error) { var api model.AgentDeptApiModel mod := service.SysDept().Model(ctx) deptId := contexts.GetDeptId(ctx) sysDept := dao.SysDept.Table() tApi := dao.TApi.Table() mod = mod.Where(sysDept+"."+dao.SysDept.Columns().DeptId, deptId) mod = mod.LeftJoin(tApi, tApi+"."+dao.TApi.Columns().DeptId+"="+sysDept+"."+dao.SysDept.Columns().DeptId) mod = mod.Fields(sysDept + "." + dao.SysDept.Columns().DeptKey + " as deptKey") mod = mod.Fields(sysDept + "." + dao.SysDept.Columns().DeptName + " as deptName") mod = mod.Fields(tApi + "." + dao.TApi.Columns().AppKey + " as appKey") mod = mod.Fields(tApi + "." + dao.TApi.Columns().AppSecret + " as appSecret") err = mod.Scan(&api) if err != nil { return nil, err } if api.AppKey == "" || api.AppSecret == "" { return nil, errors.New("您未开通api功能,请联系管理员开通") } return &api, nil } // SubCompany 获取当前代理商组织的子组织列表 func (s *sAgentDept) SubCompany(ctx context.Context) (list []*model.SysDeptTreeModel, err error) { deptId := contexts.GetDeptId(ctx) currentDept, err := service.SysDept().GetDeptById(ctx, deptId) if err != nil { return nil, err } if currentDept == nil { return []*model.SysDeptTreeModel{}, nil } root := &model.SysDeptTreeModel{ DeptId: currentDept.DeptId, ParentId: currentDept.ParentId, Key: fmt.Sprintf("%d", currentDept.DeptId), DeptName: currentDept.DeptName, Children: make([]*model.SysDeptTreeModel, 0), Ancestors: currentDept.Ancestors, DeptType: currentDept.DeptType, } deptType := 1 depts, _, err := service.SysDept().GetDeptList(ctx, model.SysDeptListParam{ DeptType: &deptType, }) if err != nil { return nil, err } for _, dept := range depts { if dept.ParentId == deptId { root.Children = append(root.Children, &model.SysDeptTreeModel{ DeptId: dept.DeptId, ParentId: dept.ParentId, Key: fmt.Sprintf("%d", dept.DeptId), DeptName: dept.DeptName, Children: make([]*model.SysDeptTreeModel, 0), Ancestors: dept.Ancestors, DeptType: dept.DeptType, }) } } return []*model.SysDeptTreeModel{root}, nil } // IsTopDept 判断当前组织是否为顶级组织 func (s *sAgentDept) IsTopDept(ctx context.Context) (isTop bool, dept *entity.SysDept, err error) { currentDeptId := contexts.GetDeptId(ctx) if currentDeptId == 0 { return false, nil, gerror.New("当前用户未绑定组织") } err = s.deptModel(ctx). Where(dao.SysDept.Columns().DeptId, currentDeptId). Scan(&dept) if err != nil { return false, nil, err } if dept == nil || dept.DeptId == 0 { return false, nil, gerror.New("组织不存在") } isTop = dept.ParentId == 0 || strings.Trim(dept.Ancestors, ",") == "0" return isTop, dept, nil }