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" ) // BackendLoginLogController 登录日志(yz_system_login_log) type BackendLoginLogController struct { beego.Controller } func (c *BackendLoginLogController) jsonErr(httpStatus, bizCode int, msg string) { c.Ctx.Output.SetStatus(httpStatus) c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg} _ = c.ServeJSON() } func (c *BackendLoginLogController) backendClaims() (*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 != "backend" { return nil, fmt.Errorf("无权访问") } return claims, nil } // RecordLoginLog 写入一条登录日志(登录成功/失败均记录,失败不影响登录流程)。 func RecordLoginLog(tid *uint64, userID uint64, account, userName, tenantName, loginType string, status int8, message string, ip, userAgent string) { if len(userAgent) > 500 { userAgent = userAgent[:500] } if len(message) > 255 { message = message[:255] } row := &models.SystemLoginLog{ Tid: tid, UserID: userID, Account: account, UserName: userName, TenantName: tenantName, LoginType: loginType, Status: status, Message: message, IP: ip, UserAgent: userAgent, } if _, err := models.Orm.Insert(row); err != nil { fmt.Println("record login log error:", err) } } // List GET /backend/loginLogs?page=1&pageSize=20&keyword=&status=&loginType=&startTime=&endTime= func (c *BackendLoginLogController) List() { if _, err := c.backendClaims(); 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")) statusStr := strings.TrimSpace(c.GetString("status")) loginType := strings.TrimSpace(c.GetString("loginType")) startTimeStr := strings.TrimSpace(c.GetString("startTime")) endTimeStr := strings.TrimSpace(c.GetString("endTime")) qs := models.Orm.QueryTable(new(models.SystemLoginLog)).Filter("delete_time__isnull", true) cond := orm.NewCondition() needCond := false if statusStr != "" { if st, err := strconv.Atoi(statusStr); err == nil { cond = cond.And("status", st) needCond = true } } if loginType != "" { cond = cond.And("login_type", loginType) needCond = true } if keyword != "" { kw := orm.NewCondition(). Or("account__icontains", keyword). Or("user_name__icontains", keyword). Or("tenant_name__icontains", keyword). Or("ip__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.SystemLoginLog _, 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, "account": rows[i].Account, "user_name": rows[i].UserName, "tenant_name": rows[i].TenantName, "login_type": rows[i].LoginType, "status": rows[i].Status, "message": rows[i].Message, "ip": rows[i].IP, "user_agent": rows[i].UserAgent, "create_time": rows[i].CreateTime.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 /backend/loginLogs/:id func (c *BackendLoginLogController) Detail() { if _, err := c.backendClaims(); 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.SystemLoginLog err = models.Orm.QueryTable(new(models.SystemLoginLog)). 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, "account": row.Account, "user_name": row.UserName, "tenant_name": row.TenantName, "login_type": row.LoginType, "status": row.Status, "message": row.Message, "ip": row.IP, "user_agent": row.UserAgent, "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 /backend/loginLogs/:id func (c *BackendLoginLogController) Delete() { if _, err := c.backendClaims(); 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.SystemLoginLog)). 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 backendLoginLogBatchDeletePayload struct { IDs []uint64 `json:"ids"` } // BatchDelete POST /backend/loginLogs/batchDelete func (c *BackendLoginLogController) BatchDelete() { if _, err := c.backendClaims(); 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 backendLoginLogBatchDeletePayload 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.SystemLoginLog)). 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() }