package controllers import ( "Quincy_admin/config" "Quincy_admin/schemas" "Quincy_admin/services" "Quincy_admin/utils" "fmt" "net/http" "net/url" "os" "path/filepath" "strconv" "strings" "github.com/gin-gonic/gin" ) type CommonController struct { service *services.CommonService config *config.Config } func NewCommonController(service *services.CommonService) *CommonController { return &CommonController{service: service, config: config.LoadConfig()} } // GetLoginLogList 获取系统登录日志 // @Summary 系统登录日志 // @Description 系统登录日志 // @Tags 系统管理 // @Produce json // @Param role body schemas.LoginLogListRequest true "req" // @Success 200 {object} utils.Response{data=schemas.LoginLog} // @Failure 500 {object} utils.Response // @Router /system/log/login/list [post] // @Security ApiKeyAuth func (c *CommonController) GetLoginLogList(ctx *gin.Context) { var req schemas.LoginLogListRequest if err := ctx.ShouldBindJSON(&req); err != nil { utils.Error(ctx, http.StatusBadRequest, "参数错误") return } if req.PageIndex <= 0 || req.PageSize <= 0 || req.PageSize > 100 { utils.Error(ctx, http.StatusBadRequest, "分页参数错误") return } items, total, err := c.service.GetLoginLogList(&req) if err != nil { fmt.Println("获取用户列表时出错:", err) utils.Error(ctx, http.StatusInternalServerError, "获取日志列表失败") return } response := schemas.LoginLogListResponse{ Item: items, Total: total, PageIndex: req.PageIndex, PageSize: req.PageSize, } utils.Success(ctx, response) } // DownloadLogFile 下载日志文件 // @Summary 下载日志文件 // @Description 下载指定的日志文件内容 // @Tags 系统管理 // @Produce application/octet-stream // @Param filename query string true "日志文件名" // @Success 200 {file} file "日志文件内容" // @Failure 400 {object} utils.Response // @Failure 404 {object} utils.Response // @Failure 500 {object} utils.Response // @Router /system/log/download [get] // @Security ApiKeyAuth // DownloadLogFile 下载日志文件 func (c *CommonController) DownloadLogFile(ctx *gin.Context) { filename := ctx.Query("filename") if filename == "" { utils.Error(ctx, http.StatusBadRequest, "参数 filename 不能为空") return } // 验证文件名安全性 if strings.Contains(filename, "..") || strings.Contains(filename, "/") || strings.Contains(filename, "\\") { utils.Error(ctx, http.StatusBadRequest, "无效的文件名") return } // 使用 filepath.Join 处理跨平台路径分隔符 filePath := filepath.Join(c.config.Log.Path, filename) // 检查文件是否存在 if _, err := os.Stat(filePath); os.IsNotExist(err) { utils.Error(ctx, http.StatusNotFound, "日志文件不存在") return } // 对文件名进行编码以支持中文 encodedFilename := url.QueryEscape(filename) // 设置响应头 ctx.Header("Content-Description", "File Transfer") ctx.Header("Content-Transfer-Encoding", "binary") ctx.Header("Content-Disposition", "attachment; filename*=UTF-8''"+encodedFilename) ctx.Header("Content-Type", "application/octet-stream") // 返回文件内容 ctx.File(filePath) } // ViewLogFile 查看日志文件内容 // @Summary 查看日志文件内容 // @Description 返回指定日志文件的内容 // @Tags 系统管理 // @Produce json // @Param filename query string true "日志文件名" // @Param lines query int false "返回行数,默认100行" // @Success 200 {object} utils.Response{data=string} // @Failure 400 {object} utils.Response // @Failure 404 {object} utils.Response // @Failure 500 {object} utils.Response // @Router /system/log/view [get] // @Security ApiKeyAuth // ViewLogFile 查看日志文件内容 func (c *CommonController) ViewLogFile(ctx *gin.Context) { filename := ctx.Query("filename") if filename == "" { utils.Error(ctx, http.StatusBadRequest, "参数 filename 不能为空") return } linesStr := ctx.Query("lines") lines := 100 // 默认返回100行 if linesStr != "" { var err error lines, err = strconv.Atoi(linesStr) if err != nil || lines <= 0 { utils.Error(ctx, http.StatusBadRequest, "参数 lines 必须是正整数") return } if lines > 1000 { lines = 1000 // 限制最大行数 } } // 验证文件名安全性 if strings.Contains(filename, "..") || strings.Contains(filename, "/") || strings.Contains(filename, "\\") { utils.Error(ctx, http.StatusBadRequest, "无效的文件名") return } // 使用配置文件中的日志目录 f := c.config.Log.Path + "/" + filename // 读取文件内容 content, err := c.service.ReadLastLines(f, lines) if err != nil { if os.IsNotExist(err) { utils.Error(ctx, http.StatusNotFound, "日志文件不存在") } else { utils.Error(ctx, http.StatusInternalServerError, "读取日志文件失败: "+err.Error()) } return } utils.Success(ctx, content) }