feat(imTenant): 新增商户管理员账号查看与密码修改功能

1.  新增编辑页管理员账号展示与密码修改字段,仅编辑态可见
2.  新增商户管理员密码重置逻辑,完善编辑场景密码校验
3.  补充超管可见控制:业务库、连接串、管理员信息非超管脱敏
4.  修复schema未使用响应式值的问题
This commit is contained in:
Austin
2026-09-21 18:44:37 +08:00
parent c9673ca871
commit 40ac52923e
5 changed files with 89 additions and 6 deletions
+65 -3
View File
@@ -165,6 +165,7 @@ func (s *sSysImTenant) fillListConfig(ctx context.Context, list []*sysin.ImTenan
dsnMap[item.Id] = item.DbDsn
}
super := isSuperTenantAdmin(ctx)
for _, item := range list {
if conf, ok := configMap[item.Id]; ok {
item.MaxUsers = conf.MaxUsers
@@ -175,7 +176,7 @@ func (s *sSysImTenant) fillListConfig(ctx context.Context, list []*sysin.ImTenan
item.MessageEncryptionEnabled = conf.MessageEncryptionEnabled
item.RealnameReviewPolicy = conf.RealnameReviewPolicy
}
item.DbDsnConfigured = dsnMap[item.Id] != ""
item.DbDsnConfigured = super && dsnMap[item.Id] != ""
}
return
}
@@ -276,6 +277,11 @@ func (s *sSysImTenant) saveTenant(ctx context.Context, in *sysin.ImTenantEditInp
s.rollbackTenantCreation(ctx, tenantID)
return err
}
} else if in.AdminPassword != "" {
// 编辑商户时填写了新密码则重置管理员密码,留空不修改
if err = s.resetTenantAdminPassword(ctx, tenantID, in.AdminPassword); err != nil {
return err
}
}
_ = publishImPolicyEvent(ctx, tenantID, in.Code, "tenant.features.updated", "moderation", 0)
@@ -348,6 +354,41 @@ func (s *sSysImTenant) createTenantAdminMember(ctx context.Context, super bool,
})
}
// resetTenantAdminPassword 重置商户管理员账号的密码(编辑弹窗填写新密码时调用)
func (s *sSysImTenant) resetTenantAdminPassword(ctx context.Context, tenantId int64, password string) (err error) {
roleVal, err := dao.AdminRole.Ctx(ctx).
Fields(dao.AdminRole.Columns().Id).
Where(dao.AdminRole.Columns().Key, imManageRoleKey).
Where(dao.AdminRole.Columns().Status, consts.StatusEnabled).
Limit(1).
Value()
if err != nil {
return gerror.Wrap(err, "查询IM管理员角色失败,请稍后重试!")
}
if roleVal.IsEmpty() {
return gerror.New("IM管理员角色(imManage)未配置,请联系运维")
}
memberId, err := dao.AdminMember.Ctx(ctx).
Fields(dao.AdminMember.Columns().Id).
Where(dao.AdminMember.Columns().TenantId, tenantId).
Where(dao.AdminMember.Columns().RoleId, roleVal.Int64()).
OrderAsc(dao.AdminMember.Columns().Id).
Limit(1).
Value()
if err != nil {
return gerror.Wrap(err, "查询商户管理员账号失败,请稍后重试!")
}
if memberId.IsEmpty() {
return gerror.New("该商户暂无管理员账号,无法重置密码")
}
return service.AdminMember().ResetPwd(ctx, &adminin.MemberResetPwdInp{
Id: memberId.Int64(),
Password: password,
})
}
// rollbackTenantCreation 商户创建补偿:删除已写入的商户及配置记录
func (s *sSysImTenant) rollbackTenantCreation(ctx context.Context, tenantId int64) {
_ = imtenant.RegistryDB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
@@ -476,10 +517,30 @@ func (s *sSysImTenant) View(ctx context.Context, in *sysin.ImTenantViewInp) (res
res.RealnameReviewPolicy = conf.RealnameReviewPolicy
}
res.DbDsnConfigured = res.DbDsn != ""
// 业务库名与独立连接串仅超管可见,非超管脱敏返回(保留是否已配置标记)
// 查询商户自动创建的管理员账号(编辑弹窗展示)
roleVal, roleErr := dao.AdminRole.Ctx(ctx).
Fields(dao.AdminRole.Columns().Id).
Where(dao.AdminRole.Columns().Key, imManageRoleKey).
Where(dao.AdminRole.Columns().Status, consts.StatusEnabled).
Limit(1).
Value()
if roleErr == nil && !roleVal.IsEmpty() {
userVal, userErr := dao.AdminMember.Ctx(ctx).
Fields(dao.AdminMember.Columns().Username).
Where(dao.AdminMember.Columns().TenantId, in.Id).
Where(dao.AdminMember.Columns().RoleId, roleVal.Int64()).
OrderAsc(dao.AdminMember.Columns().Id).
Limit(1).
Value()
if userErr == nil && !userVal.IsEmpty() {
res.AdminUsername = userVal.String()
}
}
// 业务库名与独立连接串仅超管可见,非超管全部脱敏
if !isSuperTenantAdmin(ctx) {
res.DbName = ""
res.DbDsn = ""
res.DbDsnConfigured = false
}
return
}
@@ -520,9 +581,10 @@ func (s *sSysImTenant) Usage(ctx context.Context, in *sysin.ImTenantUsageInp) (r
DbDsnConfigured: tenant.DbDsn != "",
Warnings: []string{},
}
// 业务库名仅超管可见,非超管脱敏返回
// 业务库名与连接串信息仅超管可见,非超管全部脱敏
if !isSuperTenantAdmin(ctx) {
res.DbName = ""
res.DbDsnConfigured = false
}
db, _, dbErr := imtenant.DB(ctx, tenant.Id)
@@ -94,6 +94,11 @@ func (in *ImTenantEditInp) Filter(ctx context.Context) (err error) {
if e := g.Validator().Rules("required|length:6,32").Data(in.AdminPassword).Messages("管理员密码不能为空|管理员密码长度应为6到32位").Run(ctx); e != nil {
return e.Current()
}
} else if in.AdminPassword != "" {
// 编辑时填写了新密码则重置,留空表示不修改
if e := g.Validator().Rules("length:6,32").Data(in.AdminPassword).Messages("管理员密码长度应为6到32位").Run(ctx); e != nil {
return e.Current()
}
}
return
}
@@ -113,6 +118,7 @@ func (in *ImTenantViewInp) Filter(ctx context.Context) (err error) {
type ImTenantViewModel struct {
entity.ImTenant
AdminUsername string `json:"adminUsername" dc:"商户管理员账号"`
MaxUsers uint64 `json:"maxUsers" dc:"最大用户数"`
MaxGroups uint64 `json:"maxGroups" dc:"最大群组数"`
MaxGroupMembers uint `json:"maxGroupMembers" dc:"最大群成员数"`