批量优化
This commit is contained in:
1 parent
438145cae7
commit
c925b198d1
50 files changed
+5716
-291
No files matched your search
@@ -2,6 +2,7 @@ package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
|
||||
"server/models"
|
||||
"server/services"
|
||||
authsvc "server/services/auth"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
@@ -21,27 +23,27 @@ type PlatformTenantController struct {
|
||||
}
|
||||
|
||||
type tenantDTO struct {
|
||||
ID uint64 `json:"id"`
|
||||
TenantCode string `json:"tenant_code"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
ContactPerson string `json:"contact_person"`
|
||||
ContactPhone string `json:"contact_phone"`
|
||||
ContactEmail string `json:"contact_email"`
|
||||
Address string `json:"address"`
|
||||
Worktime string `json:"worktime"`
|
||||
Status int8 `json:"status"`
|
||||
ID uint64 `json:"id"`
|
||||
TenantCode string `json:"tenant_code"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
ContactPerson string `json:"contact_person"`
|
||||
ContactPhone string `json:"contact_phone"`
|
||||
ContactEmail string `json:"contact_email"`
|
||||
Address string `json:"address"`
|
||||
Worktime string `json:"worktime"`
|
||||
Status int8 `json:"status"`
|
||||
// 套餐与用户数配额
|
||||
PackageID uint64 `json:"package_id"`
|
||||
PackageName string `json:"package_name"`
|
||||
// PackageExpireTime 套餐计费到期时间(NULL-永久有效);DaysRemaining 剩余天数
|
||||
PackageExpireTime *time.Time `json:"package_expire_time"`
|
||||
DaysRemaining int `json:"days_remaining"`
|
||||
UserQuota int `json:"user_quota"`
|
||||
UserUsed int `json:"user_used"`
|
||||
Remark string `json:"remark"`
|
||||
CreateTime *time.Time `json:"create_time,omitempty"`
|
||||
UpdateTime *time.Time `json:"update_time,omitempty"`
|
||||
DeleteTime *time.Time `json:"delete_time,omitempty"`
|
||||
UserQuota int `json:"user_quota"`
|
||||
UserUsed int `json:"user_used"`
|
||||
Remark string `json:"remark"`
|
||||
CreateTime *time.Time `json:"create_time,omitempty"`
|
||||
UpdateTime *time.Time `json:"update_time,omitempty"`
|
||||
DeleteTime *time.Time `json:"delete_time,omitempty"`
|
||||
}
|
||||
|
||||
// tenantPackageNameMap 套餐ID -> 套餐名称
|
||||
@@ -94,23 +96,23 @@ func toTenantDTO(t models.SystemTenant) tenantDTO {
|
||||
}
|
||||
}
|
||||
return tenantDTO{
|
||||
ID: t.ID,
|
||||
TenantCode: t.TenantCode,
|
||||
TenantName: t.TenantName,
|
||||
ContactPerson: stringValue(t.ContactPerson),
|
||||
ContactPhone: stringValue(t.ContactPhone),
|
||||
ContactEmail: stringValue(t.ContactEmail),
|
||||
Address: stringValue(t.Address),
|
||||
Worktime: stringValue(t.Worktime),
|
||||
Status: t.Status,
|
||||
PackageID: t.PackageID,
|
||||
ID: t.ID,
|
||||
TenantCode: t.TenantCode,
|
||||
TenantName: t.TenantName,
|
||||
ContactPerson: stringValue(t.ContactPerson),
|
||||
ContactPhone: stringValue(t.ContactPhone),
|
||||
ContactEmail: stringValue(t.ContactEmail),
|
||||
Address: stringValue(t.Address),
|
||||
Worktime: stringValue(t.Worktime),
|
||||
Status: t.Status,
|
||||
PackageID: t.PackageID,
|
||||
PackageExpireTime: t.PackageExpireTime,
|
||||
DaysRemaining: daysRemaining,
|
||||
UserQuota: t.UserQuota,
|
||||
Remark: stringValue(t.Remark),
|
||||
CreateTime: &ct,
|
||||
UpdateTime: &ut,
|
||||
DeleteTime: t.DeleteTime,
|
||||
UserQuota: t.UserQuota,
|
||||
Remark: stringValue(t.Remark),
|
||||
CreateTime: &ct,
|
||||
UpdateTime: &ut,
|
||||
DeleteTime: t.DeleteTime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +236,14 @@ type tenantPayload struct {
|
||||
PackageID *uint64 `json:"package_id"`
|
||||
UserQuota *int `json:"user_quota"`
|
||||
Remark string `json:"remark"`
|
||||
|
||||
// 指定租户管理员(可选):把已有认证身份绑定为该租户管理员。
|
||||
// AdminIdentityID 直接指定身份;也可只传 AdminAccount/AdminPhone/AdminEmail 按归并键定位。
|
||||
// 统一认证原则:不新建账号、不覆盖原密码,只建「身份-企业」绑定并授予租户管理员角色。
|
||||
AdminIdentityID uint64 `json:"admin_identity_id"`
|
||||
AdminAccount string `json:"admin_account"`
|
||||
AdminPhone string `json:"admin_phone"`
|
||||
AdminEmail string `json:"admin_email"`
|
||||
}
|
||||
|
||||
func (c *PlatformTenantController) parseTenantPayload() (tenantPayload, error) {
|
||||
@@ -264,6 +274,14 @@ func (c *PlatformTenantController) parseTenantPayload() (tenantPayload, error) {
|
||||
p.UserQuota = &v
|
||||
}
|
||||
}
|
||||
if s := strings.TrimSpace(c.GetString("admin_identity_id")); s != "" {
|
||||
if v, err := strconv.ParseUint(s, 10, 64); err == nil {
|
||||
p.AdminIdentityID = v
|
||||
}
|
||||
}
|
||||
p.AdminAccount = strings.TrimSpace(c.GetString("admin_account"))
|
||||
p.AdminPhone = strings.TrimSpace(c.GetString("admin_phone"))
|
||||
p.AdminEmail = strings.TrimSpace(c.GetString("admin_email"))
|
||||
|
||||
// ĺŚćĺ
łéŽĺ掾为犺ďźĺ°čŻäť JSON body č§ŁćďźeditTenant éťčޤ JSONďź?
|
||||
if p.TenantName == "" && p.TenantCode == "" {
|
||||
@@ -275,6 +293,72 @@ func (c *PlatformTenantController) parseTenantPayload() (tenantPayload, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// bindTenantAdminFromPayload 把已有认证身份绑定为新租户的管理员(不新建账号、不覆盖密码)。
|
||||
// 优先 AdminIdentityID;否则按 AdminAccount/AdminPhone/AdminEmail 归并键(手机>邮箱>账号)定位。
|
||||
// 返回 (是否绑定, 错误);未指定管理员时返回 (false, nil)。
|
||||
func bindTenantAdminFromPayload(tid uint64, p tenantPayload) (bool, error) {
|
||||
identityID := p.AdminIdentityID
|
||||
if identityID == 0 && (p.AdminAccount != "" || p.AdminPhone != "" || p.AdminEmail != "") {
|
||||
existed, hit := authsvc.LocateIdentityByKey(p.AdminAccount, p.AdminPhone, p.AdminEmail)
|
||||
if !hit {
|
||||
return false, errors.New("未找到该账号对应的认证身份")
|
||||
}
|
||||
identityID = existed.ID
|
||||
}
|
||||
if identityID == 0 {
|
||||
return false, nil // 未指定管理员,跳过
|
||||
}
|
||||
|
||||
identity, err := authsvc.GetIdentityByID(identityID)
|
||||
if err != nil || identity == nil {
|
||||
return false, errors.New("认证身份不存在")
|
||||
}
|
||||
|
||||
// 企业内账号:显式指定 > 身份手机号 > user{id};姓名取身份昵称
|
||||
account := p.AdminAccount
|
||||
if account == "" && identity.Mobile != nil {
|
||||
account = strings.TrimSpace(*identity.Mobile)
|
||||
}
|
||||
if account == "" {
|
||||
account = fmt.Sprintf("user%d", identity.ID)
|
||||
}
|
||||
name := "租户管理员"
|
||||
if identity.Nickname != nil && strings.TrimSpace(*identity.Nickname) != "" {
|
||||
name = strings.TrimSpace(*identity.Nickname)
|
||||
}
|
||||
|
||||
// 老表镜像身份层现有密码哈希(登录仍以认证中心为准,不在建租户时改密)
|
||||
var pwd *string
|
||||
if identity.PasswordHash != nil {
|
||||
h := *identity.PasswordHash
|
||||
pwd = &h
|
||||
}
|
||||
|
||||
// isDefault=0:不改变该用户当前的默认企业
|
||||
if _, err := services.BindTenantUser(tid, identity.ID, &account, &name, identity.Mobile, identity.Email, nil, nil, pwd, 0, 1, nil); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 绑定全局「租户管理员」角色(拥有 backend 全权限)
|
||||
if adminRoleID, err := models.GetTenantAdminRole(); err == nil && adminRoleID > 0 {
|
||||
_, _ = models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("tid", tid).
|
||||
Filter("uid", identity.ID).
|
||||
Update(map[string]interface{}{"group_id": adminRoleID})
|
||||
}
|
||||
|
||||
// 双写:同步到统一认证中心(建 yz_auth_tenant_user 绑定)
|
||||
var row models.SystemTenantUser
|
||||
if e := models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("tid", tid).
|
||||
Filter("uid", identity.ID).
|
||||
One(&row); e == nil {
|
||||
syncTenantUserToAuth(&row, false)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// CreateTenant ĺĺťşç§ćˇ
|
||||
// POST /platform/tenant/createTenant
|
||||
func (c *PlatformTenantController) CreateTenant() {
|
||||
@@ -369,10 +453,25 @@ func (c *PlatformTenantController) CreateTenant() {
|
||||
return
|
||||
}
|
||||
|
||||
// 指定已有身份为租户管理员(可选):只建绑定,不新建账号、不改密码。
|
||||
// 绑定失败不影响租户创建结果,仅返回警告信息。
|
||||
adminBound := false
|
||||
adminWarn := ""
|
||||
if bound, bErr := bindTenantAdminFromPayload(uint64(id), p); bErr != nil {
|
||||
adminWarn = bErr.Error()
|
||||
} else {
|
||||
adminBound = bound
|
||||
}
|
||||
|
||||
msg := "success"
|
||||
if adminWarn != "" {
|
||||
msg = "租户已创建,但指定管理员绑定失败: " + adminWarn
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{"id": id},
|
||||
"msg": msg,
|
||||
"data": map[string]interface{}{"id": id, "admin_bound": adminBound},
|
||||
}
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user