feat(imTenant): 新增商户管理员账号查看与密码修改功能
1. 新增编辑页管理员账号展示与密码修改字段,仅编辑态可见 2. 新增商户管理员密码重置逻辑,完善编辑场景密码校验 3. 补充超管可见控制:业务库、连接串、管理员信息非超管脱敏 4. 修复schema未使用响应式值的问题
This commit is contained in:
@@ -165,6 +165,7 @@ func (s *sSysImTenant) fillListConfig(ctx context.Context, list []*sysin.ImTenan
|
|||||||
dsnMap[item.Id] = item.DbDsn
|
dsnMap[item.Id] = item.DbDsn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
super := isSuperTenantAdmin(ctx)
|
||||||
for _, item := range list {
|
for _, item := range list {
|
||||||
if conf, ok := configMap[item.Id]; ok {
|
if conf, ok := configMap[item.Id]; ok {
|
||||||
item.MaxUsers = conf.MaxUsers
|
item.MaxUsers = conf.MaxUsers
|
||||||
@@ -175,7 +176,7 @@ func (s *sSysImTenant) fillListConfig(ctx context.Context, list []*sysin.ImTenan
|
|||||||
item.MessageEncryptionEnabled = conf.MessageEncryptionEnabled
|
item.MessageEncryptionEnabled = conf.MessageEncryptionEnabled
|
||||||
item.RealnameReviewPolicy = conf.RealnameReviewPolicy
|
item.RealnameReviewPolicy = conf.RealnameReviewPolicy
|
||||||
}
|
}
|
||||||
item.DbDsnConfigured = dsnMap[item.Id] != ""
|
item.DbDsnConfigured = super && dsnMap[item.Id] != ""
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -276,6 +277,11 @@ func (s *sSysImTenant) saveTenant(ctx context.Context, in *sysin.ImTenantEditInp
|
|||||||
s.rollbackTenantCreation(ctx, tenantID)
|
s.rollbackTenantCreation(ctx, tenantID)
|
||||||
return err
|
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)
|
_ = 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 商户创建补偿:删除已写入的商户及配置记录
|
// rollbackTenantCreation 商户创建补偿:删除已写入的商户及配置记录
|
||||||
func (s *sSysImTenant) rollbackTenantCreation(ctx context.Context, tenantId int64) {
|
func (s *sSysImTenant) rollbackTenantCreation(ctx context.Context, tenantId int64) {
|
||||||
_ = imtenant.RegistryDB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
|
_ = 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.RealnameReviewPolicy = conf.RealnameReviewPolicy
|
||||||
}
|
}
|
||||||
res.DbDsnConfigured = res.DbDsn != ""
|
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) {
|
if !isSuperTenantAdmin(ctx) {
|
||||||
res.DbName = ""
|
res.DbName = ""
|
||||||
res.DbDsn = ""
|
res.DbDsn = ""
|
||||||
|
res.DbDsnConfigured = false
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -520,9 +581,10 @@ func (s *sSysImTenant) Usage(ctx context.Context, in *sysin.ImTenantUsageInp) (r
|
|||||||
DbDsnConfigured: tenant.DbDsn != "",
|
DbDsnConfigured: tenant.DbDsn != "",
|
||||||
Warnings: []string{},
|
Warnings: []string{},
|
||||||
}
|
}
|
||||||
// 业务库名仅超管可见,非超管脱敏返回
|
// 业务库名与连接串信息仅超管可见,非超管全部脱敏
|
||||||
if !isSuperTenantAdmin(ctx) {
|
if !isSuperTenantAdmin(ctx) {
|
||||||
res.DbName = ""
|
res.DbName = ""
|
||||||
|
res.DbDsnConfigured = false
|
||||||
}
|
}
|
||||||
|
|
||||||
db, _, dbErr := imtenant.DB(ctx, tenant.Id)
|
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 {
|
if e := g.Validator().Rules("required|length:6,32").Data(in.AdminPassword).Messages("管理员密码不能为空|管理员密码长度应为6到32位").Run(ctx); e != nil {
|
||||||
return e.Current()
|
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
|
return
|
||||||
}
|
}
|
||||||
@@ -113,6 +118,7 @@ func (in *ImTenantViewInp) Filter(ctx context.Context) (err error) {
|
|||||||
|
|
||||||
type ImTenantViewModel struct {
|
type ImTenantViewModel struct {
|
||||||
entity.ImTenant
|
entity.ImTenant
|
||||||
|
AdminUsername string `json:"adminUsername" dc:"商户管理员账号"`
|
||||||
MaxUsers uint64 `json:"maxUsers" dc:"最大用户数"`
|
MaxUsers uint64 `json:"maxUsers" dc:"最大用户数"`
|
||||||
MaxGroups uint64 `json:"maxGroups" dc:"最大群组数"`
|
MaxGroups uint64 `json:"maxGroups" dc:"最大群组数"`
|
||||||
MaxGroupMembers uint `json:"maxGroupMembers" dc:"最大群成员数"`
|
MaxGroupMembers uint `json:"maxGroupMembers" dc:"最大群成员数"`
|
||||||
|
|||||||
@@ -56,6 +56,21 @@
|
|||||||
/>
|
/>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
|
<n-gi span="1" v-if="formValue.id > 0">
|
||||||
|
<n-form-item label="管理员账号">
|
||||||
|
<n-input :value="formValue.adminUsername" disabled placeholder="未创建" />
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
<n-gi span="1" v-if="formValue.id > 0">
|
||||||
|
<n-form-item label="管理员密码">
|
||||||
|
<n-input
|
||||||
|
type="password"
|
||||||
|
show-password-on="click"
|
||||||
|
placeholder="留空则不修改密码"
|
||||||
|
v-model:value="formValue.adminPassword"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
<n-gi span="1" v-if="formValue.id === 0">
|
<n-gi span="1" v-if="formValue.id === 0">
|
||||||
<n-form-item label="管理员账号" path="adminUsername">
|
<n-form-item label="管理员账号" path="adminUsername">
|
||||||
<n-input
|
<n-input
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||||
labelWidth: 90,
|
labelWidth: 90,
|
||||||
// 业务库名搜索项仅admin超管可见
|
// 业务库名搜索项仅admin超管可见
|
||||||
schemas: schemas.filter((item) => item.field !== 'dbName' || isAdminSuper.value),
|
schemas: schemas.value.filter((item) => item.field !== 'dbName' || isAdminSuper.value),
|
||||||
});
|
});
|
||||||
|
|
||||||
// 加载表格数据
|
// 加载表格数据
|
||||||
|
|||||||
@@ -297,12 +297,12 @@ const baseColumns = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// 业务库名列仅admin超管可见
|
// 业务库名与独立连接串列仅admin超管可见
|
||||||
export function buildColumns(isAdmin: boolean) {
|
export function buildColumns(isAdmin: boolean) {
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
return baseColumns;
|
return baseColumns;
|
||||||
}
|
}
|
||||||
return baseColumns.filter((item) => item.key !== 'dbName');
|
return baseColumns.filter((item) => item.key !== 'dbName' && item.key !== 'dbDsnConfigured');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载字典数据选项
|
// 加载字典数据选项
|
||||||
|
|||||||
Reference in New Issue
Block a user