From 31fc86e878262176bc4c77cd9344c44f60edf763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=AB=E5=9C=B0=E5=83=A7?= <357099073@qq.com> Date: Mon, 1 Jun 2026 22:35:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controllers/backend_admin_user.go | 583 ++++++++++++++++++++++++++-- controllers/platform_tenant_user.go | 2 +- controllers/platform_user.go | 2 +- models/system_tenant_user.go | 2 + routers/backend/backend.go | 14 +- services/tenant_user.go | 28 +- 6 files changed, 583 insertions(+), 48 deletions(-) diff --git a/controllers/backend_admin_user.go b/controllers/backend_admin_user.go index ab9afc5..179a645 100644 --- a/controllers/backend_admin_user.go +++ b/controllers/backend_admin_user.go @@ -1,11 +1,16 @@ package controllers import ( + "encoding/json" + "io" "strconv" + "strings" "server/models" + "server/pkg/passwordutil" "server/services" + "github.com/beego/beego/v2/client/orm" beego "github.com/beego/beego/v2/server/web" ) @@ -21,76 +26,580 @@ type backendUserInfoDTO struct { Name *string `json:"name"` Phone *string `json:"phone"` Email *string `json:"email"` + Sex uint8 `json:"sex"` + Birth *string `json:"birth"` + IsDefault int8 `json:"is_default"` Status int8 `json:"status"` + Remark *string `json:"remark"` CreateTime string `json:"create_time"` + UpdateTime *string `json:"update_time"` TenantName string `json:"tenant_name"` TenantCode string `json:"tenant_code"` } -// GetUserInfo 获取当前登录租户用户的详情 -// GET /backend/getUserInfo -func (c *BackendAdminUserController) GetUserInfo() { +type backendTenantUserPayload struct { + Tid uint64 `json:"tid"` + Uid uint64 `json:"uid"` + Account *string `json:"account"` + Name *string `json:"name"` + Phone *string `json:"phone"` + Email *string `json:"email"` + Sex *uint8 `json:"sex"` + Birth *string `json:"birth"` + Password *string `json:"password"` + IsDefault *int8 `json:"is_default"` + Status *int8 `json:"status"` + Remark *string `json:"remark"` +} + +type backendChangePasswordPayload struct { + ID uint64 `json:"id"` + Password string `json:"password"` +} + +func formatBackendBirth(birth *string) *string { + if birth == nil { + return nil + } + + s := strings.TrimSpace(*birth) + if s == "" { + return nil + } + + if len(s) >= 10 { + date := s[:10] + return &date + } + + return &s +} + +func toBackendUserInfoDTO(u models.SystemTenantUser) backendUserInfoDTO { + var updateTime *string + if u.UpdateTime != nil { + s := u.UpdateTime.Format("2006-01-02 15:04:05") + updateTime = &s + } + + tenantName := "未知租户" + tenantCode := "" + + tenant, err := services.GetTenantByID(u.Tid) + if err == nil && tenant != nil { + tenantName = tenant.TenantName + tenantCode = tenant.TenantCode + } + + return backendUserInfoDTO{ + ID: u.ID, + Tid: u.Tid, + Uid: u.Uid, + Account: u.Account, + Name: u.Name, + Phone: u.Phone, + Email: u.Email, + Sex: u.Sex, + Birth: formatBackendBirth(u.Birth), + IsDefault: u.IsDefault, + Status: u.Status, + Remark: u.Remark, + CreateTime: u.CreateTime.Format("2006-01-02 15:04:05"), + UpdateTime: updateTime, + TenantName: tenantName, + TenantCode: tenantCode, + } +} + +func (c *BackendAdminUserController) getJWTUidTid() (uint64, uint64) { var uid uint64 var tid uint64 data := c.Ctx.Input.Data() + if jwtUid := data["uid"]; jwtUid != nil { - uid = jwtUid.(uint64) + if v, ok := jwtUid.(uint64); ok { + uid = v + } } + if jwtTid := data["tid"]; jwtTid != nil { - tid = jwtTid.(uint64) + if v, ok := jwtTid.(uint64); ok { + tid = v + } } - if uid == 0 { - idStr := c.Ctx.Input.Param(":id") - uid, _ = strconv.ParseUint(idStr, 10, 64) + return uid, tid +} + +func (c *BackendAdminUserController) parseTenantUserPayload() (backendTenantUserPayload, bool) { + var p backendTenantUserPayload + + raw, _ := io.ReadAll(c.Ctx.Request.Body) + if err := json.Unmarshal(raw, &p); err != nil { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "参数错误"} + _ = c.ServeJSON() + return backendTenantUserPayload{}, false } - if uid == 0 { + return p, true +} + +func findBackendTenantUser(idOrUid uint64, jwtTid uint64) (*models.SystemTenantUser, error) { + var row models.SystemTenantUser + + qs := models.Orm.QueryTable(new(models.SystemTenantUser)). + Filter("delete_time__isnull", true) + + if jwtTid > 0 { + qs = qs.Filter("tid", jwtTid) + } + + err := qs.Filter("id", idOrUid).One(&row) + if err == nil { + return &row, nil + } + + qs = models.Orm.QueryTable(new(models.SystemTenantUser)). + Filter("delete_time__isnull", true) + + if jwtTid > 0 { + qs = qs.Filter("tid", jwtTid) + } + + err = qs.Filter("uid", idOrUid).One(&row) + if err != nil { + return nil, err + } + + return &row, nil +} + +// GetAllUsers 获取当前租户后台用户列表 +// GET /backend/getAllUsers +func (c *BackendAdminUserController) GetAllUsers() { + _, jwtTid := c.getJWTUidTid() + + keyword := strings.TrimSpace(c.GetString("keyword")) + tid, _ := c.GetUint64("tid") + + if jwtTid > 0 { + tid = jwtTid + } + + cond := orm.NewCondition().And("delete_time__isnull", true) + + if tid > 0 { + cond = cond.And("tid", tid) + } + + if keyword != "" { + kwCond := orm.NewCondition(). + Or("name__icontains", keyword). + Or("phone__icontains", keyword). + Or("email__icontains", keyword). + Or("account__icontains", keyword) + cond = cond.AndCond(kwCond) + } + + var rows []models.SystemTenantUser + _, err := models.Orm.QueryTable(new(models.SystemTenantUser)). + SetCond(cond). + OrderBy("-is_default", "-id"). + All(&rows) + if err != nil { + c.Data["json"] = map[string]interface{}{"code": 500, "msg": "查询失败: " + err.Error()} + _ = c.ServeJSON() + return + } + + list := make([]backendUserInfoDTO, 0, len(rows)) + for _, row := range rows { + list = append(list, toBackendUserInfoDTO(row)) + } + + c.Data["json"] = map[string]interface{}{ + "code": 200, + "msg": "success", + "data": map[string]interface{}{ + "list": list, + "total": len(list), + }, + } + _ = c.ServeJSON() +} + +// GetTenantUsers 获取指定租户后台用户 +// GET /backend/getTenantUsers/:tid +func (c *BackendAdminUserController) GetTenantUsers() { + tidStr := c.Ctx.Input.Param(":tid") + tid, _ := strconv.ParseUint(tidStr, 10, 64) + + _, jwtTid := c.getJWTUidTid() + if jwtTid > 0 { + tid = jwtTid + } + + if tid == 0 { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "tid 不能为空"} + _ = c.ServeJSON() + return + } + + var rows []models.SystemTenantUser + _, err := models.Orm.QueryTable(new(models.SystemTenantUser)). + Filter("tid", tid). + Filter("delete_time__isnull", true). + OrderBy("-is_default", "-id"). + All(&rows) + + if err != nil { + c.Data["json"] = map[string]interface{}{"code": 500, "msg": "查询失败: " + err.Error()} + _ = c.ServeJSON() + return + } + + list := make([]backendUserInfoDTO, 0, len(rows)) + for _, row := range rows { + list = append(list, toBackendUserInfoDTO(row)) + } + + c.Data["json"] = map[string]interface{}{ + "code": 200, + "msg": "success", + "data": map[string]interface{}{ + "list": list, + "total": len(list), + }, + } + _ = c.ServeJSON() +} + +// GetUserInfo 获取后台租户用户详情 +// GET /backend/getUserInfo/:id +func (c *BackendAdminUserController) GetUserInfo() { + jwtUid, jwtTid := c.getJWTUidTid() + + idStr := c.Ctx.Input.Param(":id") + id, _ := strconv.ParseUint(idStr, 10, 64) + + if id == 0 { + id = jwtUid + } + + if id == 0 { c.Data["json"] = map[string]interface{}{"code": 401, "msg": "未登录或非法请求"} _ = c.ServeJSON() return } - var u *models.SystemTenantUser - var err error - - if tid > 0 { - u, err = services.GetTenantUserByUidAndTid(uid, tid) - } else { - u, err = services.GetTenantUserByUid(uid) - } - + u, err := findBackendTenantUser(id, jwtTid) if err != nil || u == nil { c.Data["json"] = map[string]interface{}{"code": 404, "msg": "后台用户信息不存在"} _ = c.ServeJSON() return } - tenant, err := services.GetTenantByID(u.Tid) - tenantName := "未知租户" - tenantCode := "" - if err == nil && tenant != nil { - tenantName = tenant.TenantName - tenantCode = tenant.TenantCode + c.Data["json"] = map[string]interface{}{ + "code": 200, + "msg": "success", + "data": toBackendUserInfoDTO(*u), + } + _ = c.ServeJSON() +} + +// AddUser 添加后台租户用户 +// POST /backend/addUser +func (c *BackendAdminUserController) AddUser() { + p, ok := c.parseTenantUserPayload() + if !ok { + return + } + + _, jwtTid := c.getJWTUidTid() + if jwtTid > 0 { + p.Tid = jwtTid + } + + if p.Tid == 0 { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "tid 不能为空"} + _ = c.ServeJSON() + return + } + + if p.Account == nil || strings.TrimSpace(*p.Account) == "" { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "account 不能为空"} + _ = c.ServeJSON() + return + } + + if p.Password == nil || strings.TrimSpace(*p.Password) == "" { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "password 不能为空"} + _ = c.ServeJSON() + return + } + + account := strings.TrimSpace(*p.Account) + p.Account = &account + + hashed, err := passwordutil.Hash(strings.TrimSpace(*p.Password)) + if err != nil { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": err.Error()} + _ = c.ServeJSON() + return + } + p.Password = &hashed + + if p.Uid == 0 { + uid, err := generateTenantUID(p.Tid) + if err != nil { + c.Data["json"] = map[string]interface{}{"code": 500, "msg": "生成用户ID失败"} + _ = c.ServeJSON() + return + } + p.Uid = uid + } + + isDefault := int8(0) + if p.IsDefault != nil { + isDefault = *p.IsDefault + } + + status := int8(1) + if p.Status != nil { + status = *p.Status + } + + id, err := services.BindTenantUser( + p.Tid, + p.Uid, + p.Account, + p.Name, + p.Phone, + p.Email, + p.Sex, + p.Birth, + p.Password, + isDefault, + status, + p.Remark, + ) + + if err != nil { + c.Data["json"] = map[string]interface{}{"code": 500, "msg": "添加失败: " + err.Error()} + _ = c.ServeJSON() + return + } + + if isDefault == 1 { + _ = services.SetDefaultTenant(p.Uid, p.Tid) } c.Data["json"] = map[string]interface{}{ "code": 200, "msg": "success", - "data": backendUserInfoDTO{ - ID: u.ID, - Tid: u.Tid, - Uid: u.Uid, - Account: u.Account, - Name: u.Name, - Phone: u.Phone, - Email: u.Email, - Status: u.Status, - CreateTime: u.CreateTime.Format("2006-01-02 15:04:05"), - TenantName: tenantName, - TenantCode: tenantCode, - }, + "data": map[string]interface{}{"id": id}, } _ = c.ServeJSON() } + +// EditUser 编辑后台租户用户 +// POST /backend/editUser/:id +func (c *BackendAdminUserController) EditUser() { + idStr := c.Ctx.Input.Param(":id") + id, _ := strconv.ParseUint(idStr, 10, 64) + + if id == 0 { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "id 不能为空"} + _ = c.ServeJSON() + return + } + + p, ok := c.parseTenantUserPayload() + if !ok { + return + } + + _, jwtTid := c.getJWTUidTid() + + row, err := findBackendTenantUser(id, jwtTid) + if err != nil || row == nil { + c.Data["json"] = map[string]interface{}{"code": 404, "msg": "用户不存在"} + _ = c.ServeJSON() + return + } + + update := map[string]interface{}{} + + if p.Tid > 0 && jwtTid == 0 { + update["tid"] = p.Tid + } + + if p.Uid > 0 { + update["uid"] = p.Uid + } + + if p.Account != nil { + account := strings.TrimSpace(*p.Account) + if account != "" { + update["account"] = account + } + } + + if p.Name != nil { + update["name"] = *p.Name + } + + if p.Phone != nil { + update["phone"] = *p.Phone + } + + if p.Email != nil { + update["email"] = *p.Email + } + + if p.Sex != nil { + update["sex"] = *p.Sex + } + + if p.Birth != nil { + birth := strings.TrimSpace(*p.Birth) + if birth == "" { + update["birth"] = nil + } else { + update["birth"] = birth + } + } + + if p.Password != nil && strings.TrimSpace(*p.Password) != "" { + hashed, err := passwordutil.Hash(strings.TrimSpace(*p.Password)) + if err != nil { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": err.Error()} + _ = c.ServeJSON() + return + } + update["password"] = hashed + } + + if p.IsDefault != nil { + update["is_default"] = *p.IsDefault + } + + if p.Status != nil { + update["status"] = *p.Status + } + + if p.Remark != nil { + update["remark"] = *p.Remark + } + + if len(update) == 0 { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "无更新字段"} + _ = c.ServeJSON() + return + } + + _, err = models.Orm.QueryTable(new(models.SystemTenantUser)). + Filter("id", row.ID). + Update(update) + + if err != nil { + c.Data["json"] = map[string]interface{}{"code": 500, "msg": "编辑失败: " + err.Error()} + _ = c.ServeJSON() + return + } + + if p.IsDefault != nil && *p.IsDefault == 1 { + _ = services.SetDefaultTenant(row.Uid, row.Tid) + } + + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success"} + _ = c.ServeJSON() +} + +// DeleteUser 删除后台租户用户 +// DELETE /backend/deleteUser/:id +func (c *BackendAdminUserController) DeleteUser() { + idStr := c.Ctx.Input.Param(":id") + id, _ := strconv.ParseUint(idStr, 10, 64) + + if id == 0 { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "id 不能为空"} + _ = c.ServeJSON() + return + } + + _, jwtTid := c.getJWTUidTid() + + row, err := findBackendTenantUser(id, jwtTid) + if err != nil || row == nil { + c.Data["json"] = map[string]interface{}{"code": 404, "msg": "用户不存在"} + _ = c.ServeJSON() + return + } + + if err := services.UnbindTenantUser(row.ID); err != nil { + c.Data["json"] = map[string]interface{}{"code": 500, "msg": "删除失败: " + err.Error()} + _ = c.ServeJSON() + return + } + + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success"} + _ = c.ServeJSON() +} + +// ChangePassword 修改后台租户用户密码 +// POST /backend/changePassword +func (c *BackendAdminUserController) ChangePassword() { + var p backendChangePasswordPayload + + raw, _ := io.ReadAll(c.Ctx.Request.Body) + if err := json.Unmarshal(raw, &p); err != nil { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "参数错误"} + _ = c.ServeJSON() + return + } + + if p.ID == 0 { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "id 不能为空"} + _ = c.ServeJSON() + return + } + + if strings.TrimSpace(p.Password) == "" { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": "password 不能为空"} + _ = c.ServeJSON() + return + } + + _, jwtTid := c.getJWTUidTid() + + row, err := findBackendTenantUser(p.ID, jwtTid) + if err != nil || row == nil { + c.Data["json"] = map[string]interface{}{"code": 404, "msg": "用户不存在"} + _ = c.ServeJSON() + return + } + + hashed, err := passwordutil.Hash(strings.TrimSpace(p.Password)) + if err != nil { + c.Data["json"] = map[string]interface{}{"code": 400, "msg": err.Error()} + _ = c.ServeJSON() + return + } + + _, err = models.Orm.QueryTable(new(models.SystemTenantUser)). + Filter("id", row.ID). + Update(map[string]interface{}{ + "password": hashed, + }) + + if err != nil { + c.Data["json"] = map[string]interface{}{"code": 500, "msg": "修改失败: " + err.Error()} + _ = c.ServeJSON() + return + } + + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "修改成功"} + _ = c.ServeJSON() +} diff --git a/controllers/platform_tenant_user.go b/controllers/platform_tenant_user.go index 9dca893..2ea7ff5 100644 --- a/controllers/platform_tenant_user.go +++ b/controllers/platform_tenant_user.go @@ -194,7 +194,7 @@ func (c *PlatformTenantUserController) CreateTenantUser() { status = *p.Status } - id, err := services.BindTenantUser(p.Tid, p.Uid, p.Account, p.Name, p.Phone, p.Email, p.Password, isDefault, status, p.Remark) + id, err := services.BindTenantUser(p.Tid, p.Uid, p.Account, p.Name, p.Phone, p.Email, nil, nil, p.Password, isDefault, status, p.Remark) if err != nil { c.Data["json"] = map[string]interface{}{"code": 500, "msg": "创建失败: " + err.Error()} _ = c.ServeJSON() diff --git a/controllers/platform_user.go b/controllers/platform_user.go index 57bf91b..8c514e5 100644 --- a/controllers/platform_user.go +++ b/controllers/platform_user.go @@ -88,7 +88,7 @@ func (c *PlatformUserController) AddUser() { hashedPwd := hashed password := &hashedPwd - _, err := services.BindTenantUser(p.Tid, uid, account, name, phone, email, password, 0, status, p.Remark) + _, err := services.BindTenantUser(p.Tid, uid, account, name, phone, email, nil, nil, password, 0, status, p.Remark) if err == nil { c.Data["json"] = map[string]interface{}{ "code": 200, diff --git a/models/system_tenant_user.go b/models/system_tenant_user.go index b382628..1f64874 100644 --- a/models/system_tenant_user.go +++ b/models/system_tenant_user.go @@ -10,6 +10,8 @@ type SystemTenantUser struct { Name *string `orm:"column(name);size(64);null" json:"name"` Phone *string `orm:"column(phone);size(20);null" json:"phone"` Email *string `orm:"column(email);size(128);null" json:"email"` + Sex uint8 `orm:"column(sex);default(0)" json:"sex"` + Birth *string `orm:"column(birth);size(20);null" json:"birth"` Password *string `orm:"column(password);size(255);null" json:"password"` IsDefault int8 `orm:"column(is_default);default(0)" json:"is_default"` Status int8 `orm:"column(status);default(1)" json:"status"` diff --git a/routers/backend/backend.go b/routers/backend/backend.go index c2740c0..202efaa 100644 --- a/routers/backend/backend.go +++ b/routers/backend/backend.go @@ -47,14 +47,14 @@ func RegisterAuthRoutes() { // 模块接口 beego.Router("/backend/modules/getTenantList", &controllers.PlatformModulesController{}, "get:GetTenantList") - //用户接口 - beego.Router("/backend/getTenantUsers/:tid", &controllers.PlatformTenantUserController{}, "get:GetTenantUsersByTid") - beego.Router("/backend/getAllUsers", &controllers.PlatformAdminUserController{}, "get:GetAllUsers") + // 用户接口 + beego.Router("/backend/getTenantUsers/:tid", &controllers.BackendAdminUserController{}, "get:GetTenantUsers") + beego.Router("/backend/getAllUsers", &controllers.BackendAdminUserController{}, "get:GetAllUsers") beego.Router("/backend/getUserInfo/:id", &controllers.BackendAdminUserController{}, "get:GetUserInfo") - beego.Router("/backend/addUser", &controllers.PlatformAdminUserController{}, "post:AddUser") - beego.Router("/backend/editUser/:id", &controllers.PlatformAdminUserController{}, "post:EditUser") - beego.Router("/backend/deleteUser/:id", &controllers.PlatformAdminUserController{}, "delete:DeleteUser") - beego.Router("/backend/changePassword", &controllers.PlatformAdminUserController{}, "post:ChangePassword") + beego.Router("/backend/addUser", &controllers.BackendAdminUserController{}, "post:AddUser") + beego.Router("/backend/editUser/:id", &controllers.BackendAdminUserController{}, "post:EditUser") + beego.Router("/backend/deleteUser/:id", &controllers.BackendAdminUserController{}, "delete:DeleteUser") + beego.Router("/backend/changePassword", &controllers.BackendAdminUserController{}, "post:ChangePassword") // ERP 接口 beego.Router("/backend/erp/getOrganization", &controllers.BackendErpController{}, "get:GetOrganization") diff --git a/services/tenant_user.go b/services/tenant_user.go index c3db9cb..937f857 100644 --- a/services/tenant_user.go +++ b/services/tenant_user.go @@ -1,9 +1,13 @@ package services -import "server/models" +import ( + "strings" + + "server/models" +) // BindTenantUser 绑定用户到租户(若已存在则更新状态/默认值) -func BindTenantUser(tid, uid uint64, account, name, phone, email, password *string, isDefault, status int8, remark *string) (uint64, error) { +func BindTenantUser(tid, uid uint64, account, name, phone, email *string, sex *uint8, birth *string, password *string, isDefault, status int8, remark *string) (uint64, error) { var existed models.SystemTenantUser err := models.Orm.QueryTable(new(models.SystemTenantUser)). Filter("tid", tid). @@ -20,6 +24,17 @@ func BindTenantUser(tid, uid uint64, account, name, phone, email, password *stri "is_default": isDefault, "remark": remark, } + if sex != nil { + update["sex"] = *sex + } + if birth != nil { + trimmedBirth := strings.TrimSpace(*birth) + if trimmedBirth == "" { + update["birth"] = nil + } else { + update["birth"] = trimmedBirth + } + } _, uErr := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("id", existed.ID).Update(update) return existed.ID, uErr } @@ -36,6 +51,15 @@ func BindTenantUser(tid, uid uint64, account, name, phone, email, password *stri Status: status, Remark: remark, } + if sex != nil { + m.Sex = *sex + } + if birth != nil { + trimmedBirth := strings.TrimSpace(*birth) + if trimmedBirth != "" { + m.Birth = &trimmedBirth + } + } id, iErr := models.Orm.Insert(m) return uint64(id), iErr }