go-platform/controllers/platform_operation_log.go

352 lines
9.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controllers
import (
"encoding/json"
"fmt"
"io"
"strconv"
"strings"
"time"
"server/models"
"server/pkg/jwtutil"
"github.com/beego/beego/v2/client/orm"
beego "github.com/beego/beego/v2/server/web"
)
// PlatformOperationLogController 操作日志yz_system_operation_log
type PlatformOperationLogController struct {
beego.Controller
}
func (c *PlatformOperationLogController) platformClaims() (*jwtutil.Claims, error) {
auth := c.Ctx.Request.Header.Get("Authorization")
if auth == "" {
return nil, fmt.Errorf("未登录")
}
parts := strings.SplitN(auth, " ", 2)
if len(parts) != 2 || parts[0] != "Bearer" {
return nil, fmt.Errorf("认证信息格式错误")
}
claims, err := jwtutil.ParseToken(parts[1])
if err != nil {
return nil, fmt.Errorf("无效的token")
}
if claims.UserType != "platform" {
return nil, fmt.Errorf("无权访问")
}
return claims, nil
}
func (c *PlatformOperationLogController) jsonErr(httpStatus, bizCode int, msg string) {
c.Ctx.Output.SetStatus(httpStatus)
c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg}
_ = c.ServeJSON()
}
// List GET /platform/operationLogs?page=1&pageSize=20&keyword=&module=&action=&status=&startTime=&endTime=
func (c *PlatformOperationLogController) List() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 20)
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 20
}
if pageSize > 200 {
pageSize = 200
}
keyword := strings.TrimSpace(c.GetString("keyword"))
module := strings.TrimSpace(c.GetString("module"))
action := strings.TrimSpace(c.GetString("action"))
statusStr := strings.TrimSpace(c.GetString("status"))
startTimeStr := strings.TrimSpace(c.GetString("startTime"))
endTimeStr := strings.TrimSpace(c.GetString("endTime"))
qs := models.Orm.QueryTable(new(models.SystemOperationLog)).Filter("delete_time__isnull", true)
// 条件拼装
cond := orm.NewCondition()
needCond := false
if module != "" {
cond = cond.And("module", module)
needCond = true
}
if action != "" {
cond = cond.And("action", action)
needCond = true
}
if statusStr != "" {
if st, err := strconv.Atoi(statusStr); err == nil {
cond = cond.And("status", st)
needCond = true
}
}
if keyword != "" {
kw := orm.NewCondition().
Or("module__icontains", keyword).
Or("action__icontains", keyword).
Or("method__icontains", keyword).
Or("url__icontains", keyword).
Or("ip__icontains", keyword).
Or("user_agent__icontains", keyword)
if uid, err := strconv.ParseUint(keyword, 10, 64); err == nil && uid > 0 {
kw = kw.Or("user_id", uid)
}
cond = cond.AndCond(kw)
needCond = true
}
if t, err := parseTimeFlexible(startTimeStr); err == nil && !t.IsZero() {
cond = cond.And("create_time__gte", t)
needCond = true
}
if t, err := parseTimeFlexible(endTimeStr); err == nil && !t.IsZero() {
cond = cond.And("create_time__lte", t)
needCond = true
}
if needCond {
qs = qs.SetCond(cond)
}
total, err := qs.Count()
if err != nil {
c.jsonErr(500, 500, "获取操作日志失败: "+err.Error())
return
}
var rows []models.SystemOperationLog
_, err = qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows)
if err != nil {
c.jsonErr(500, 500, "获取操作日志失败: "+err.Error())
return
}
list := make([]map[string]interface{}, 0, len(rows))
for i := range rows {
item := map[string]interface{}{
"id": rows[i].ID,
"tid": rows[i].Tid,
"user_id": rows[i].UserID,
"module": rows[i].Module,
"action": rows[i].Action,
"method": rows[i].Method,
"url": rows[i].URL,
"ip": rows[i].IP,
"user_agent": rows[i].UserAgent,
"request_data": rows[i].RequestData,
"response_data": rows[i].ResponseData,
"status": rows[i].Status,
"error_message": rows[i].ErrorMessage,
"execution_time": rows[i].ExecutionTime,
"create_time": rows[i].CreateTime.Format("2006-01-02 15:04:05"),
"update_time": "",
}
if rows[i].UpdateTime != nil {
item["update_time"] = rows[i].UpdateTime.Format("2006-01-02 15:04:05")
}
list = append(list, item)
}
c.Data["json"] = map[string]interface{}{
"code": 200,
"msg": "success",
"data": map[string]interface{}{
"list": list,
"total": total,
},
}
_ = c.ServeJSON()
}
// Detail GET /platform/operationLogs/:id
func (c *PlatformOperationLogController) Detail() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
idStr := c.Ctx.Input.Param(":id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil || id == 0 {
c.jsonErr(400, 400, "无效ID")
return
}
var row models.SystemOperationLog
err = models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("id", id).
Filter("delete_time__isnull", true).
One(&row)
if err != nil {
c.jsonErr(404, 404, "记录不存在")
return
}
out := map[string]interface{}{
"id": row.ID,
"tid": row.Tid,
"user_id": row.UserID,
"module": row.Module,
"action": row.Action,
"method": row.Method,
"url": row.URL,
"ip": row.IP,
"user_agent": row.UserAgent,
"request_data": row.RequestData,
"response_data": row.ResponseData,
"status": row.Status,
"error_message": row.ErrorMessage,
"execution_time": row.ExecutionTime,
"create_time": row.CreateTime.Format("2006-01-02 15:04:05"),
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": out}
_ = c.ServeJSON()
}
// Delete DELETE /platform/operationLogs/:id
func (c *PlatformOperationLogController) Delete() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
idStr := c.Ctx.Input.Param(":id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil || id == 0 {
c.jsonErr(400, 400, "无效ID")
return
}
now := time.Now()
n, err := models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("id", id).
Filter("delete_time__isnull", true).
Update(map[string]interface{}{"delete_time": now})
if err != nil {
c.jsonErr(500, 500, "删除失败: "+err.Error())
return
}
if n == 0 {
c.jsonErr(404, 404, "记录不存在")
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "删除成功"}
_ = c.ServeJSON()
}
type batchDeletePayload struct {
IDs []uint64 `json:"ids"`
}
// BatchDelete POST /platform/operationLogs/batchDelete
func (c *PlatformOperationLogController) BatchDelete() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
raw, err := io.ReadAll(c.Ctx.Request.Body)
if err != nil {
c.jsonErr(400, 400, "参数错误")
return
}
var p batchDeletePayload
if err := json.Unmarshal(raw, &p); err != nil {
c.jsonErr(400, 400, "参数错误")
return
}
if len(p.IDs) == 0 {
c.jsonErr(400, 400, "请选择要删除的日志")
return
}
now := time.Now()
_, err = models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("id__in", p.IDs).
Filter("delete_time__isnull", true).
Update(map[string]interface{}{"delete_time": now})
if err != nil {
c.jsonErr(500, 500, "批量删除失败: "+err.Error())
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "批量删除成功"}
_ = c.ServeJSON()
}
// Statistics GET /platform/operationLogs/statistics
// 供前端筛选项modules/actions
func (c *PlatformOperationLogController) Statistics() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
var moduleRows []models.SystemOperationLog
_, _ = models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("delete_time__isnull", true).
Filter("module__isnull", false).
Limit(1000).
All(&moduleRows, "Module")
modSet := map[string]struct{}{}
for i := range moduleRows {
m := strings.TrimSpace(moduleRows[i].Module)
if m != "" {
modSet[m] = struct{}{}
}
}
modules := make([]string, 0, len(modSet))
for k := range modSet {
modules = append(modules, k)
}
var actionRows []models.SystemOperationLog
_, _ = models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("delete_time__isnull", true).
Filter("action__isnull", false).
Limit(1000).
All(&actionRows, "Action")
actSet := map[string]struct{}{}
for i := range actionRows {
a := strings.TrimSpace(actionRows[i].Action)
if a != "" {
actSet[a] = struct{}{}
}
}
actions := make([]string, 0, len(actSet))
for k := range actSet {
actions = append(actions, k)
}
c.Data["json"] = map[string]interface{}{
"code": 200,
"msg": "success",
"data": map[string]interface{}{
"modules": modules,
"actions": actions,
},
}
_ = c.ServeJSON()
}
func parseTimeFlexible(s string) (time.Time, error) {
s = strings.TrimSpace(s)
if s == "" {
return time.Time{}, fmt.Errorf("empty")
}
layouts := []string{
"2006-01-02 15:04:05",
"2006-01-02 15:04",
"2006-01-02",
time.RFC3339,
}
for _, ly := range layouts {
if t, err := time.ParseInLocation(ly, s, time.Local); err == nil {
return t, nil
}
}
return time.Time{}, fmt.Errorf("invalid time")
}