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") }