package agent import ( "context" "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/event" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/rolepolicy" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/do" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "strconv" "strings" ) func syncTemplateRoles(ctx context.Context, template *entity.SysRole, actorID int64) error { queue := []int64{template.DeptId} seen := make(map[int64]bool) failed := 0 var firstErr error for len(queue) > 0 { parentID := queue[0] queue = queue[1:] if seen[parentID] { return gerror.New("机构上下级存在循环") } seen[parentID] = true var children []*entity.SysDept if err := dao.SysDept.Ctx(ctx).Where("tenant_id", template.TenantId).Where("parent_id", parentID).Where("dept_type", 1).Scan(&children); err != nil { return err } for _, child := range children { if child.DeptRole <= 0 { g.Log().Warningf(ctx, "agent template sync skipped missing default role, deptId:%d", child.DeptId) continue } err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { lock := tx.Ctx(ctx).Model(dao.SysDept.Table()).Where("dept_id", child.DeptId).Where("tenant_id", template.TenantId) if !strings.EqualFold(g.DB().GetConfig().Type, "sqlite") { lock = lock.LockUpdate() } var locked *entity.SysDept if err := lock.Scan(&locked); err != nil { return err } if locked == nil || locked.DeptRole != child.DeptRole { return gerror.New("下级机构角色绑定已变化") } var current *entity.SysRole if err := tx.Ctx(ctx).Model(dao.SysRole.Table()).Where("role_id", child.DeptRole).Where("tenant_id", template.TenantId).Where("dept_id", child.DeptId).Scan(¤t); err != nil { return err } if current == nil { g.Log().Warningf(ctx, "agent template sync skipped missing or deleted role, deptId:%d, roleId:%d", child.DeptId, child.DeptRole) return nil } configLock := tx.Ctx(ctx).Model(dao.SysConfig.Table()).Where("tenant_id", template.TenantId).Where("config_key", rolepolicy.TemplateConfigKey) if !strings.EqualFold(g.DB().GetConfig().Type, "sqlite") { configLock = configLock.LockUpdate() } var config *entity.SysConfig if err := configLock.Scan(&config); err != nil { return err } if config == nil || strings.TrimSpace(config.ConfigValue) != strconv.FormatInt(template.RoleId, 10) { return gerror.New("模板已切换,请重新同步") } templateLock := tx.Ctx(ctx).Model(dao.SysRole.Table()).Where("role_id", template.RoleId) if !strings.EqualFold(g.DB().GetConfig().Type, "sqlite") { templateLock = templateLock.LockUpdate() } var latest *entity.SysRole if err := templateLock.Scan(&latest); err != nil { return err } if latest == nil || latest.Status != "0" { return gerror.New("模板不可用") } var menus []*entity.SysRoleMenu if err := tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()).Where("tenant_id", template.TenantId).Where("role_id", template.RoleId).Scan(&menus); err != nil { return err } if _, err := tx.Ctx(ctx).Model(dao.SysRole.Table()).Where("role_id", current.RoleId).Data(do.SysRole{CreatedDept: template.DeptId, DataScope: consts.SysRoleDataScopeDeptAndBelow, UpdatedBy: actorID}).Update(); err != nil { return err } if _, err := tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()).Where("role_id", current.RoleId).Delete(); err != nil { return err } for _, menu := range menus { if _, err := tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()).Data(do.SysRoleMenu{TenantId: template.TenantId, RoleId: current.RoleId, MenuId: menu.MenuId, DataScope: consts.SysRoleMenuDataScopeRole}).Insert(); err != nil { return err } } return nil }) if err != nil { failed++ if firstErr == nil { firstErr = err } g.Log().Errorf(ctx, "agent template sync child failed, deptId:%d, err:%v", child.DeptId, err) continue } event.EventsInstance().Emit(ctx, consts.EventKeyDBSysRoleUpdate, child.DeptRole) } } if firstErr != nil { return gerror.Wrapf(firstErr, "代理模板同步失败企业数:%d", failed) } return nil }