小程序一些功能更新
This commit is contained in:
142
internal/logic/admin_audit.go
Normal file
142
internal/logic/admin_audit.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
|
||||
v1 "tool-api/api/admin/v1"
|
||||
"tool-api/internal/consts"
|
||||
)
|
||||
|
||||
// auditId 审计对象主键统一转字符串(避免与 note.go 的 itoa(int) 冲突)
|
||||
func auditId(v int64) string { return strconv.FormatInt(v, 10) }
|
||||
|
||||
// ============================================================================
|
||||
// 后台操作审计(T17)
|
||||
//
|
||||
// WriteAudit 只负责「落一条记录」,调用点负责提供前后值;写入失败仅告警,
|
||||
// 绝不因审计异常影响主流程(审计是旁路,不是业务前置条件)。
|
||||
// ============================================================================
|
||||
|
||||
// AuditEntry 一条待写入的操作审计
|
||||
type AuditEntry struct {
|
||||
Action string // 动作,如 user.set_level / event.status / admin.create
|
||||
TargetType string // 对象类型:user/event/table/admin/export...
|
||||
TargetId string // 对象主键(字符串,兼容复合键)
|
||||
Before interface{} // 操作前值(可为 nil / map / struct)
|
||||
After interface{} // 操作后值
|
||||
Result int // consts.AuditResultSuccess / Fail
|
||||
Remark string
|
||||
}
|
||||
|
||||
// auditJSON 把前后值序列化成 JSON 字符串;nil 存 NULL。
|
||||
func auditJSON(v interface{}) interface{} {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func auditClientIp(ctx context.Context) string {
|
||||
req := g.RequestFromCtx(ctx)
|
||||
if req == nil {
|
||||
return ""
|
||||
}
|
||||
return req.GetClientIp()
|
||||
}
|
||||
|
||||
// WriteAudit 写入一条操作审计(操作人取自上下文,由 AdminPerm 中间件注入)。
|
||||
func WriteAudit(ctx context.Context, e AuditEntry) {
|
||||
data := g.Map{
|
||||
"admin_id": CtxAdminId(ctx),
|
||||
"admin_account": CtxAdminAccount(ctx),
|
||||
"admin_name": CtxAdminName(ctx),
|
||||
"role_value": CtxAdminRole(ctx),
|
||||
"action": e.Action,
|
||||
"target_type": e.TargetType,
|
||||
"target_id": e.TargetId,
|
||||
"before_json": auditJSON(e.Before),
|
||||
"after_json": auditJSON(e.After),
|
||||
"result": e.Result,
|
||||
"remark": e.Remark,
|
||||
"ip": auditClientIp(ctx),
|
||||
"created_at": gtime.Now(),
|
||||
}
|
||||
if _, err := g.Model(consts.TableAdminAuditLog).Data(data).Insert(); err != nil {
|
||||
g.Log().Warningf(ctx, "[audit] 写入失败 action=%s err=%v", e.Action, err)
|
||||
}
|
||||
}
|
||||
|
||||
// AdminAuditList 审计列表(多条件筛选 + 分页)。
|
||||
func AdminAuditList(ctx context.Context, req *v1.AuditListReq) (*v1.AuditListRes, error) {
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize <= 0 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
m := g.Model(consts.TableAdminAuditLog)
|
||||
if req.AdminKeyword != "" {
|
||||
m = m.WhereLike("admin_account", "%"+req.AdminKeyword+"%")
|
||||
}
|
||||
if req.Action != "" {
|
||||
m = m.WhereLike("action", "%"+req.Action+"%")
|
||||
}
|
||||
if req.Result != nil {
|
||||
m = m.Where("result", *req.Result)
|
||||
}
|
||||
if req.DateFrom != "" {
|
||||
m = m.WhereGTE("created_at", req.DateFrom+" 00:00:00")
|
||||
}
|
||||
if req.DateTo != "" {
|
||||
m = m.WhereLTE("created_at", req.DateTo+" 23:59:59")
|
||||
}
|
||||
total, err := m.Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records, err := m.Page(req.Page, req.PageSize).OrderDesc("id").All()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := make([]v1.AuditItem, 0, len(records))
|
||||
for _, r := range records {
|
||||
list = append(list, v1.AuditItem{
|
||||
Id: r["id"].Int64(),
|
||||
AdminId: r["admin_id"].Int64(),
|
||||
AdminAccount: r["admin_account"].String(),
|
||||
AdminName: r["admin_name"].String(),
|
||||
RoleValue: r["role_value"].String(),
|
||||
Action: r["action"].String(),
|
||||
TargetType: r["target_type"].String(),
|
||||
TargetId: r["target_id"].String(),
|
||||
BeforeJson: r["before_json"].String(),
|
||||
AfterJson: r["after_json"].String(),
|
||||
Result: r["result"].Int(),
|
||||
Remark: r["remark"].String(),
|
||||
Ip: r["ip"].String(),
|
||||
CreatedAt: r["created_at"].String(),
|
||||
})
|
||||
}
|
||||
return &v1.AuditListRes{List: list, Total: total}, nil
|
||||
}
|
||||
|
||||
// AdminAuditRecord 前端主动上报一条审计(如「导出」为纯前端动作,服务端无法感知)。
|
||||
func AdminAuditRecord(ctx context.Context, req *v1.AuditRecordReq) (*v1.AuditRecordRes, error) {
|
||||
WriteAudit(ctx, AuditEntry{
|
||||
Action: req.Action,
|
||||
TargetType: req.TargetType,
|
||||
TargetId: req.TargetId,
|
||||
Result: consts.AuditResultSuccess,
|
||||
Remark: req.Remark,
|
||||
})
|
||||
return &v1.AuditRecordRes{}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user