小程序一些功能更新

This commit is contained in:
李琦
2026-09-29 10:57:01 +08:00
parent 0cb70a7618
commit 3bb7fa8db3
96 changed files with 13890 additions and 213 deletions

View File

@@ -0,0 +1,193 @@
package logic
import (
"context"
"strconv"
"strings"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"golang.org/x/crypto/bcrypt"
v1 "tool-api/api/admin/v1"
"tool-api/internal/consts"
)
// ============================================================================
// 管理员账号管理(T17)
// ============================================================================
// AdminList 管理员列表
func AdminList(ctx context.Context) (*v1.AdminListRes, error) {
records, err := g.Model(consts.TableAdminUsers).OrderAsc("id").All()
if err != nil {
return nil, err
}
list := make([]v1.AdminItem, 0, len(records))
for _, r := range records {
list = append(list, v1.AdminItem{
Id: r["id"].Int64(),
Account: r["account"].String(),
NickName: r["nick_name"].String(),
RoleName: r["role_name"].String(),
RoleValue: r["role_value"].String(),
Status: r["status"].Int(),
CreatedAt: r["created_at"].String(),
})
}
return &v1.AdminListRes{List: list}, nil
}
// lastSuperGuard 保护「最后一个启用中的超级管理员」:
// 若该管理员当前是启用中的超管,而改动后会失去「启用中的超管」身份(降角色或停用),
// 且库中仅剩这一个,则拒绝——避免把自己锁在门外。
func lastSuperGuard(ctx context.Context, id int64, newRole string, newStatus int) error {
rec, err := g.Model(consts.TableAdminUsers).Where("id", id).One()
if err != nil {
return err
}
if rec.IsEmpty() {
return nil
}
isEnabledSuper := rec["role_value"].String() == consts.AdminRoleSuper &&
rec["status"].Int() == consts.AdminStatusEnabled
if !isEnabledSuper {
return nil
}
stillSuper := newRole == consts.AdminRoleSuper && newStatus == consts.AdminStatusEnabled
if stillSuper {
return nil
}
count, err := g.Model(consts.TableAdminUsers).
Where("role_value", consts.AdminRoleSuper).
Where("status", consts.AdminStatusEnabled).
Count()
if err != nil {
return err
}
if count <= 1 {
return gerror.New("至少保留一个启用中的超级管理员")
}
return nil
}
// AdminSave 新增/修改管理员。编辑不清空密码(除非显式传入新密码)。
func AdminSave(ctx context.Context, req *v1.AdminSaveReq) (*v1.AdminSaveRes, error) {
if req.Id > 0 {
rec, err := g.Model(consts.TableAdminUsers).Where("id", req.Id).One()
if err != nil {
return nil, err
}
if rec.IsEmpty() {
return nil, gerror.New("管理员不存在")
}
if err = lastSuperGuard(ctx, req.Id, req.RoleValue, rec["status"].Int()); err != nil {
return nil, err
}
data := g.Map{
"nick_name": req.NickName,
"role_name": roleNameOf(req.RoleValue),
"role_value": req.RoleValue,
}
pwdChanged := strings.TrimSpace(req.Password) != ""
if pwdChanged {
hash, herr := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if herr != nil {
return nil, herr
}
data["password"] = string(hash)
}
if _, err = g.Model(consts.TableAdminUsers).Where("id", req.Id).Data(data).Update(); err != nil {
return nil, err
}
WriteAudit(ctx, AuditEntry{
Action: "admin.update",
TargetType: "admin",
TargetId: strconv.FormatInt(req.Id, 10),
Before: g.Map{
"nick_name": rec["nick_name"].String(),
"role_value": rec["role_value"].String(),
},
After: g.Map{
"nick_name": req.NickName,
"role_value": req.RoleValue,
"pwd_changed": pwdChanged,
},
Result: consts.AuditResultSuccess,
})
return &v1.AdminSaveRes{}, nil
}
account := strings.TrimSpace(req.Account)
if account == "" {
return nil, gerror.New("请填写登录账号")
}
if strings.TrimSpace(req.Password) == "" {
return nil, gerror.New("请填写登录密码")
}
count, err := g.Model(consts.TableAdminUsers).Where("account", account).Count()
if err != nil {
return nil, err
}
if count > 0 {
return nil, gerror.New("账号已存在")
}
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
newId, err := g.Model(consts.TableAdminUsers).Data(g.Map{
"account": account,
"password": string(hash),
"nick_name": req.NickName,
"role_name": roleNameOf(req.RoleValue),
"role_value": req.RoleValue,
"status": consts.AdminStatusEnabled,
"created_at": gtime.Now(),
}).InsertAndGetId()
if err != nil {
return nil, err
}
WriteAudit(ctx, AuditEntry{
Action: "admin.create",
TargetType: "admin",
TargetId: strconv.FormatInt(newId, 10),
After: g.Map{
"account": account,
"nick_name": req.NickName,
"role_value": req.RoleValue,
},
Result: consts.AuditResultSuccess,
})
return &v1.AdminSaveRes{}, nil
}
// AdminStatus 启停管理员
func AdminStatus(ctx context.Context, id int64, status int) (*v1.AdminStatusRes, error) {
if status != consts.AdminStatusEnabled && status != consts.AdminStatusDisabled {
return nil, gerror.New("状态非法")
}
rec, err := g.Model(consts.TableAdminUsers).Where("id", id).One()
if err != nil {
return nil, err
}
if rec.IsEmpty() {
return nil, gerror.New("管理员不存在")
}
if err = lastSuperGuard(ctx, id, rec["role_value"].String(), status); err != nil {
return nil, err
}
if _, err = g.Model(consts.TableAdminUsers).Where("id", id).Data(g.Map{"status": status}).Update(); err != nil {
return nil, err
}
WriteAudit(ctx, AuditEntry{
Action: "admin.status",
TargetType: "admin",
TargetId: strconv.FormatInt(id, 10),
Before: g.Map{"status": rec["status"].Int()},
After: g.Map{"status": status},
Result: consts.AuditResultSuccess,
})
return &v1.AdminStatusRes{}, nil
}