tenant: move admin member queries into service
This commit is contained in:
@@ -1,8 +1,11 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"quyun/v2/app/requests"
|
"quyun/v2/app/requests"
|
||||||
"quyun/v2/database/models"
|
"quyun/v2/database/models"
|
||||||
|
"quyun/v2/pkg/consts"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AdminTenantUserJoinResponse 返回租户管理员添加成员后的结果。
|
// AdminTenantUserJoinResponse 返回租户管理员添加成员后的结果。
|
||||||
@@ -23,4 +26,25 @@ type AdminTenantUserListFilter struct {
|
|||||||
requests.Pagination `json:",inline" query:",inline"`
|
requests.Pagination `json:",inline" query:",inline"`
|
||||||
// UserID 按用户ID过滤(可选)。
|
// UserID 按用户ID过滤(可选)。
|
||||||
UserID *int64 `json:"user_id,omitempty" query:"user_id"`
|
UserID *int64 `json:"user_id,omitempty" query:"user_id"`
|
||||||
|
// Role 按角色过滤(可选):member/tenant_admin。
|
||||||
|
Role *consts.TenantUserRole `json:"role,omitempty" query:"role"`
|
||||||
|
// Status 按成员状态过滤(可选):pending_verify/verified/banned。
|
||||||
|
Status *consts.UserStatus `json:"status,omitempty" query:"status"`
|
||||||
|
// Username 按用户名模糊查询(可选,支持包含匹配)。
|
||||||
|
Username *string `json:"username,omitempty" query:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdminTenantUserItem 为租户成员列表项(包含成员关系与用户基础信息)。
|
||||||
|
type AdminTenantUserItem struct {
|
||||||
|
// TenantUser 租户成员关系记录。
|
||||||
|
TenantUser *models.TenantUser `json:"tenant_user,omitempty"`
|
||||||
|
// User 用户基础信息(用于展示 username 等)。
|
||||||
|
User *models.User `json:"user,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *AdminTenantUserListFilter) UsernameTrimmed() string {
|
||||||
|
if f == nil || f.Username == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(*f.Username)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,6 +186,13 @@ func (r *Routes) Register(router fiber.Router) {
|
|||||||
PathParam[int64]("orderID"),
|
PathParam[int64]("orderID"),
|
||||||
))
|
))
|
||||||
// Register routes for controller: tenantUserAdmin
|
// Register routes for controller: tenantUserAdmin
|
||||||
|
r.log.Debugf("Registering route: Delete /t/:tenantCode/v1/admin/users/:userID -> tenantUserAdmin.adminRemoveUser")
|
||||||
|
router.Delete("/t/:tenantCode/v1/admin/users/:userID"[len(r.Path()):], Func3(
|
||||||
|
r.tenantUserAdmin.adminRemoveUser,
|
||||||
|
Local[*models.Tenant]("tenant"),
|
||||||
|
Local[*models.TenantUser]("tenant_user"),
|
||||||
|
PathParam[int64]("userID"),
|
||||||
|
))
|
||||||
r.log.Debugf("Registering route: Get /t/:tenantCode/v1/admin/users -> tenantUserAdmin.adminTenantUsers")
|
r.log.Debugf("Registering route: Get /t/:tenantCode/v1/admin/users -> tenantUserAdmin.adminTenantUsers")
|
||||||
router.Get("/t/:tenantCode/v1/admin/users"[len(r.Path()):], DataFunc3(
|
router.Get("/t/:tenantCode/v1/admin/users"[len(r.Path()):], DataFunc3(
|
||||||
r.tenantUserAdmin.adminTenantUsers,
|
r.tenantUserAdmin.adminTenantUsers,
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"go.ipao.vip/gen"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// tenantUserAdmin provides tenant-admin member management endpoints.
|
// tenantUserAdmin provides tenant-admin member management endpoints.
|
||||||
@@ -20,6 +19,44 @@ import (
|
|||||||
// @provider
|
// @provider
|
||||||
type tenantUserAdmin struct{}
|
type tenantUserAdmin struct{}
|
||||||
|
|
||||||
|
// adminRemoveUser
|
||||||
|
//
|
||||||
|
// @Summary 移除租户成员(租户管理)
|
||||||
|
// @Tags Tenant
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param tenantCode path string true "Tenant Code"
|
||||||
|
// @Param userID path int64 true "UserID"
|
||||||
|
// @Success 200 {object} requests.Pager
|
||||||
|
//
|
||||||
|
// @Router /t/:tenantCode/v1/admin/users/:userID [delete]
|
||||||
|
// @Bind tenant local key(tenant)
|
||||||
|
// @Bind tenantUser local key(tenant_user)
|
||||||
|
// @Bind userID path
|
||||||
|
func (*tenantUserAdmin) adminRemoveUser(
|
||||||
|
ctx fiber.Ctx,
|
||||||
|
tenant *models.Tenant,
|
||||||
|
tenantUser *models.TenantUser,
|
||||||
|
userID int64,
|
||||||
|
) error {
|
||||||
|
if err := requireTenantAdmin(tenantUser); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if userID <= 0 {
|
||||||
|
return errorx.ErrInvalidParameter.WithMsg("user_id must be > 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"tenant_id": tenant.ID,
|
||||||
|
"operator_user_id": tenantUser.UserID,
|
||||||
|
"target_user_id": userID,
|
||||||
|
"operator_is_admin": true,
|
||||||
|
}).Info("tenant.admin.users.remove")
|
||||||
|
|
||||||
|
// 关键语义:删除成员接口幂等化;目标用户不属于租户时也返回成功,便于后台重试与批量操作。
|
||||||
|
return services.Tenant.RemoveUser(ctx.Context(), tenant.ID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
// adminJoinUser
|
// adminJoinUser
|
||||||
//
|
//
|
||||||
// @Summary 添加租户成员(租户管理)
|
// @Summary 添加租户成员(租户管理)
|
||||||
@@ -137,7 +174,7 @@ func (*tenantUserAdmin) adminSetUserRole(
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param tenantCode path string true "Tenant Code"
|
// @Param tenantCode path string true "Tenant Code"
|
||||||
// @Param filter query dto.AdminTenantUserListFilter true "Filter"
|
// @Param filter query dto.AdminTenantUserListFilter true "Filter"
|
||||||
// @Success 200 {object} requests.Pager{items=models.TenantUser}
|
// @Success 200 {object} requests.Pager{items=dto.AdminTenantUserItem}
|
||||||
//
|
//
|
||||||
// @Router /t/:tenantCode/v1/admin/users [get]
|
// @Router /t/:tenantCode/v1/admin/users [get]
|
||||||
// @Bind tenant local key(tenant)
|
// @Bind tenant local key(tenant)
|
||||||
@@ -152,32 +189,16 @@ func (*tenantUserAdmin) adminTenantUsers(
|
|||||||
if err := requireTenantAdmin(tenantUser); err != nil {
|
if err := requireTenantAdmin(tenantUser); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if filter == nil {
|
|
||||||
filter = &dto.AdminTenantUserListFilter{}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"tenant_id": tenant.ID,
|
"tenant_id": tenant.ID,
|
||||||
"user_id": tenantUser.UserID,
|
"user_id": tenantUser.UserID,
|
||||||
"query_uid": filter.UserID,
|
"query_uid": filter.UserID,
|
||||||
|
"role": filter.Role,
|
||||||
|
"status": filter.Status,
|
||||||
|
"username": filter.UsernameTrimmed(),
|
||||||
}).Info("tenant.admin.users.list")
|
}).Info("tenant.admin.users.list")
|
||||||
|
|
||||||
filter.Pagination.Format()
|
// 按 llm.txt 约束:HTTP 层不允许直接查询数据库,全部交由 services 层处理。
|
||||||
|
return services.Tenant.AdminTenantUsersPage(ctx.Context(), tenant.ID, filter)
|
||||||
tbl, query := models.TenantUserQuery.QueryContext(ctx.Context())
|
|
||||||
conds := []gen.Condition{tbl.TenantID.Eq(tenant.ID)}
|
|
||||||
if filter.UserID != nil && *filter.UserID > 0 {
|
|
||||||
conds = append(conds, tbl.UserID.Eq(*filter.UserID))
|
|
||||||
}
|
|
||||||
|
|
||||||
items, total, err := query.Where(conds...).Order(tbl.ID.Desc()).FindByPage(int(filter.Offset()), int(filter.Limit))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &requests.Pager{
|
|
||||||
Pagination: filter.Pagination,
|
|
||||||
Total: total,
|
|
||||||
Items: items,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"quyun/v2/app/http/super/dto"
|
"quyun/v2/app/http/super/dto"
|
||||||
|
tenantdto "quyun/v2/app/http/tenant/dto"
|
||||||
"quyun/v2/app/requests"
|
"quyun/v2/app/requests"
|
||||||
"quyun/v2/database"
|
"quyun/v2/database"
|
||||||
"quyun/v2/database/models"
|
"quyun/v2/database/models"
|
||||||
@@ -24,6 +25,81 @@ import (
|
|||||||
// @provider
|
// @provider
|
||||||
type tenant struct{}
|
type tenant struct{}
|
||||||
|
|
||||||
|
// AdminTenantUsersPage 租户管理员分页查询成员列表(包含用户基础信息)。
|
||||||
|
func (t *tenant) AdminTenantUsersPage(ctx context.Context, tenantID int64, filter *tenantdto.AdminTenantUserListFilter) (*requests.Pager, error) {
|
||||||
|
if tenantID <= 0 {
|
||||||
|
return nil, errors.New("tenant_id must be > 0")
|
||||||
|
}
|
||||||
|
if filter == nil {
|
||||||
|
filter = &tenantdto.AdminTenantUserListFilter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
filter.Pagination.Format()
|
||||||
|
|
||||||
|
tbl, query := models.TenantUserQuery.QueryContext(ctx)
|
||||||
|
conds := []gen.Condition{tbl.TenantID.Eq(tenantID)}
|
||||||
|
if filter.UserID != nil && *filter.UserID > 0 {
|
||||||
|
conds = append(conds, tbl.UserID.Eq(*filter.UserID))
|
||||||
|
}
|
||||||
|
if filter.Role != nil && *filter.Role != "" {
|
||||||
|
conds = append(conds, tbl.Role.Contains(string(*filter.Role)))
|
||||||
|
}
|
||||||
|
if filter.Status != nil && *filter.Status != "" {
|
||||||
|
conds = append(conds, tbl.Status.Eq(*filter.Status))
|
||||||
|
}
|
||||||
|
if username := filter.UsernameTrimmed(); username != "" {
|
||||||
|
uTbl, _ := models.UserQuery.QueryContext(ctx)
|
||||||
|
query = query.LeftJoin(uTbl, uTbl.ID.EqCol(tbl.UserID))
|
||||||
|
conds = append(conds, uTbl.Username.Like(database.WrapLike(username)))
|
||||||
|
}
|
||||||
|
|
||||||
|
items, total, err := query.Where(conds...).Order(tbl.ID.Desc()).FindByPage(int(filter.Offset()), int(filter.Limit))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userIDs := make([]int64, 0, len(items))
|
||||||
|
for _, tu := range items {
|
||||||
|
if tu == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
userIDs = append(userIDs, tu.UserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var users []*models.User
|
||||||
|
if len(userIDs) > 0 {
|
||||||
|
uTbl, uQuery := models.UserQuery.QueryContext(ctx)
|
||||||
|
users, err = uQuery.Where(uTbl.ID.In(userIDs...)).Find()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userMap := make(map[int64]*models.User, len(users))
|
||||||
|
for _, u := range users {
|
||||||
|
if u == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
userMap[u.ID] = u
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]*tenantdto.AdminTenantUserItem, 0, len(items))
|
||||||
|
for _, tu := range items {
|
||||||
|
if tu == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, &tenantdto.AdminTenantUserItem{
|
||||||
|
TenantUser: tu,
|
||||||
|
User: userMap[tu.UserID],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &requests.Pager{
|
||||||
|
Pagination: filter.Pagination,
|
||||||
|
Total: total,
|
||||||
|
Items: out,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *tenant) ContainsUserID(ctx context.Context, tenantID, userID int64) (*models.User, error) {
|
func (t *tenant) ContainsUserID(ctx context.Context, tenantID, userID int64) (*models.User, error) {
|
||||||
tbl, query := models.TenantUserQuery.QueryContext(ctx)
|
tbl, query := models.TenantUserQuery.QueryContext(ctx)
|
||||||
|
|
||||||
@@ -71,6 +147,10 @@ func (t *tenant) RemoveUser(ctx context.Context, tenantID, userID int64) error {
|
|||||||
tbl, query := models.TenantUserQuery.QueryContext(ctx)
|
tbl, query := models.TenantUserQuery.QueryContext(ctx)
|
||||||
tenantUser, err := query.Where(tbl.TenantID.Eq(tenantID), tbl.UserID.Eq(userID)).First()
|
tenantUser, err := query.Where(tbl.TenantID.Eq(tenantID), tbl.UserID.Eq(userID)).First()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// 幂等:成员不存在时也返回成功,便于后台重试/批量移除。
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return errors.Wrapf(err, "RemoveUser failed to find, tenantID: %d, userID: %d", tenantID, userID)
|
return errors.Wrapf(err, "RemoveUser failed to find, tenantID: %d, userID: %d", tenantID, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"quyun/v2/app/commands/testx"
|
"quyun/v2/app/commands/testx"
|
||||||
|
tenantdto "quyun/v2/app/http/tenant/dto"
|
||||||
"quyun/v2/database"
|
"quyun/v2/database"
|
||||||
"quyun/v2/database/models"
|
"quyun/v2/database/models"
|
||||||
"quyun/v2/pkg/consts"
|
"quyun/v2/pkg/consts"
|
||||||
@@ -15,6 +16,7 @@ import (
|
|||||||
|
|
||||||
_ "go.ipao.vip/atom"
|
_ "go.ipao.vip/atom"
|
||||||
"go.ipao.vip/atom/contracts"
|
"go.ipao.vip/atom/contracts"
|
||||||
|
"go.ipao.vip/gen/types"
|
||||||
"go.uber.org/dig"
|
"go.uber.org/dig"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -96,5 +98,85 @@ func (t *TenantTestSuite) Test_SetUserRole() {
|
|||||||
So(len(m.Role), ShouldEqual, 1)
|
So(len(m.Role), ShouldEqual, 1)
|
||||||
So(m.Role[0], ShouldEqual, consts.TenantUserRoleTenantAdmin)
|
So(m.Role[0], ShouldEqual, consts.TenantUserRoleTenantAdmin)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Convey("设置为 member 成功", func() {
|
||||||
|
err := Tenant.SetUserRole(ctx, tenantID, userID, consts.TenantUserRoleMember)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
m, err := Tenant.FindTenantUser(ctx, tenantID, userID)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(m, ShouldNotBeNil)
|
||||||
|
So(len(m.Role), ShouldEqual, 1)
|
||||||
|
So(m.Role[0], ShouldEqual, consts.TenantUserRoleMember)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TenantTestSuite) Test_RemoveUser() {
|
||||||
|
Convey("Tenant.RemoveUser", t.T(), func() {
|
||||||
|
ctx := t.T().Context()
|
||||||
|
tenantID := int64(1)
|
||||||
|
userID := int64(2)
|
||||||
|
|
||||||
|
database.Truncate(ctx, t.DB, models.TableNameTenantUser)
|
||||||
|
|
||||||
|
Convey("移除不存在成员应幂等返回成功", func() {
|
||||||
|
So(Tenant.RemoveUser(ctx, tenantID, userID), ShouldBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("移除已存在成员成功", func() {
|
||||||
|
So(Tenant.AddUser(ctx, tenantID, userID), ShouldBeNil)
|
||||||
|
So(Tenant.RemoveUser(ctx, tenantID, userID), ShouldBeNil)
|
||||||
|
|
||||||
|
_, err := Tenant.FindTenantUser(ctx, tenantID, userID)
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TenantTestSuite) Test_AdminTenantUsersPage() {
|
||||||
|
Convey("Tenant.AdminTenantUsersPage", t.T(), func() {
|
||||||
|
ctx := t.T().Context()
|
||||||
|
tenantID := int64(1)
|
||||||
|
|
||||||
|
database.Truncate(ctx, t.DB, models.TableNameTenantUser, models.TableNameUser)
|
||||||
|
|
||||||
|
u1 := &models.User{
|
||||||
|
Username: "u1",
|
||||||
|
Password: "pw",
|
||||||
|
Roles: types.NewArray([]consts.Role{consts.RoleUser}),
|
||||||
|
Status: consts.UserStatusVerified,
|
||||||
|
}
|
||||||
|
So(u1.Create(ctx), ShouldBeNil)
|
||||||
|
|
||||||
|
u2 := &models.User{
|
||||||
|
Username: "u2",
|
||||||
|
Password: "pw",
|
||||||
|
Roles: types.NewArray([]consts.Role{consts.RoleUser}),
|
||||||
|
Status: consts.UserStatusVerified,
|
||||||
|
}
|
||||||
|
So(u2.Create(ctx), ShouldBeNil)
|
||||||
|
|
||||||
|
So(Tenant.AddUser(ctx, tenantID, u1.ID), ShouldBeNil)
|
||||||
|
So(Tenant.AddUser(ctx, tenantID, u2.ID), ShouldBeNil)
|
||||||
|
So(Tenant.SetUserRole(ctx, tenantID, u2.ID, consts.TenantUserRoleTenantAdmin), ShouldBeNil)
|
||||||
|
|
||||||
|
Convey("不加过滤应返回用户信息", func() {
|
||||||
|
pager, err := Tenant.AdminTenantUsersPage(ctx, tenantID, &tenantdto.AdminTenantUserListFilter{})
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(pager.Total, ShouldEqual, 2)
|
||||||
|
|
||||||
|
items, ok := pager.Items.([]*tenantdto.AdminTenantUserItem)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
So(len(items), ShouldEqual, 2)
|
||||||
|
So(items[0].User, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("按 role=tenant_admin 过滤", func() {
|
||||||
|
role := consts.TenantUserRoleTenantAdmin
|
||||||
|
pager, err := Tenant.AdminTenantUsersPage(ctx, tenantID, &tenantdto.AdminTenantUserListFilter{Role: &role})
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(pager.Total, ShouldEqual, 1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -835,6 +835,20 @@ const docTemplate = `{
|
|||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"enum": [
|
||||||
|
"member",
|
||||||
|
"tenant_admin"
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
"x-enum-varnames": [
|
||||||
|
"TenantUserRoleMember",
|
||||||
|
"TenantUserRoleTenantAdmin"
|
||||||
|
],
|
||||||
|
"description": "Role 按角色过滤(可选):member/tenant_admin。",
|
||||||
|
"name": "role",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "UserID 按用户ID过滤(可选)。",
|
"description": "UserID 按用户ID过滤(可选)。",
|
||||||
@@ -854,7 +868,7 @@ const docTemplate = `{
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/models.TenantUser"
|
"$ref": "#/definitions/dto.AdminTenantUserItem"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1701,6 +1715,27 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.AdminTenantUserItem": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tenant_user": {
|
||||||
|
"description": "TenantUser 租户成员关系记录。",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/models.TenantUser"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"description": "User 用户基础信息(用于展示 username 等)。",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/models.User"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dto.AdminTenantUserJoinResponse": {
|
"dto.AdminTenantUserJoinResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -829,6 +829,20 @@
|
|||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"enum": [
|
||||||
|
"member",
|
||||||
|
"tenant_admin"
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
"x-enum-varnames": [
|
||||||
|
"TenantUserRoleMember",
|
||||||
|
"TenantUserRoleTenantAdmin"
|
||||||
|
],
|
||||||
|
"description": "Role 按角色过滤(可选):member/tenant_admin。",
|
||||||
|
"name": "role",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "UserID 按用户ID过滤(可选)。",
|
"description": "UserID 按用户ID过滤(可选)。",
|
||||||
@@ -848,7 +862,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/models.TenantUser"
|
"$ref": "#/definitions/dto.AdminTenantUserItem"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1695,6 +1709,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.AdminTenantUserItem": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tenant_user": {
|
||||||
|
"description": "TenantUser 租户成员关系记录。",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/models.TenantUser"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"description": "User 用户基础信息(用于展示 username 等)。",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/models.User"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dto.AdminTenantUserJoinResponse": {
|
"dto.AdminTenantUserJoinResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -185,6 +185,17 @@ definitions:
|
|||||||
退款原因:建议必填(由业务侧校验);用于审计与追责。
|
退款原因:建议必填(由业务侧校验);用于审计与追责。
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
dto.AdminTenantUserItem:
|
||||||
|
properties:
|
||||||
|
tenant_user:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/definitions/models.TenantUser'
|
||||||
|
description: TenantUser 租户成员关系记录。
|
||||||
|
user:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/definitions/models.User'
|
||||||
|
description: User 用户基础信息(用于展示 username 等)。
|
||||||
|
type: object
|
||||||
dto.AdminTenantUserJoinResponse:
|
dto.AdminTenantUserJoinResponse:
|
||||||
properties:
|
properties:
|
||||||
tenant_user:
|
tenant_user:
|
||||||
@@ -1543,6 +1554,16 @@ paths:
|
|||||||
in: query
|
in: query
|
||||||
name: page
|
name: page
|
||||||
type: integer
|
type: integer
|
||||||
|
- description: Role 按角色过滤(可选):member/tenant_admin。
|
||||||
|
enum:
|
||||||
|
- member
|
||||||
|
- tenant_admin
|
||||||
|
in: query
|
||||||
|
name: role
|
||||||
|
type: string
|
||||||
|
x-enum-varnames:
|
||||||
|
- TenantUserRoleMember
|
||||||
|
- TenantUserRoleTenantAdmin
|
||||||
- description: UserID 按用户ID过滤(可选)。
|
- description: UserID 按用户ID过滤(可选)。
|
||||||
in: query
|
in: query
|
||||||
name: user_id
|
name: user_id
|
||||||
@@ -1557,7 +1578,7 @@ paths:
|
|||||||
- $ref: '#/definitions/requests.Pager'
|
- $ref: '#/definitions/requests.Pager'
|
||||||
- properties:
|
- properties:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/models.TenantUser'
|
$ref: '#/definitions/dto.AdminTenantUserItem'
|
||||||
type: object
|
type: object
|
||||||
summary: 成员列表(租户管理)
|
summary: 成员列表(租户管理)
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
Reference in New Issue
Block a user