feat(错误日志): 实现前后端错误日志收集与管理功能
This commit is contained in:
parent
5be32930f8
commit
d36eeb5134
|
|
@ -23,6 +23,7 @@ type ApiGroup struct {
|
|||
AutoCodeTemplateApi
|
||||
SysParamsApi
|
||||
SysVersionApi
|
||||
SysErrorApi
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -46,4 +47,5 @@ var (
|
|||
autoCodeHistoryService = service.ServiceGroupApp.SystemServiceGroup.AutoCodeHistory
|
||||
autoCodeTemplateService = service.ServiceGroupApp.SystemServiceGroup.AutoCodeTemplate
|
||||
sysVersionService = service.ServiceGroupApp.SystemServiceGroup.SysVersionService
|
||||
sysErrprService = service.ServiceGroupApp.SystemServiceGroup.SysErrorService
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,169 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type SysErrorApi struct{}
|
||||
|
||||
// CreateSysError 创建错误日志
|
||||
// @Tags SysError
|
||||
// @Summary 创建错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body system.SysError true "创建错误日志"
|
||||
// @Success 200 {object} response.Response{msg=string} "创建成功"
|
||||
// @Router /sysErrpr/createSysError [post]
|
||||
func (sysErrprApi *SysErrorApi) CreateSysError(c *gin.Context) {
|
||||
// 创建业务用Context
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var sysErrpr system.SysError
|
||||
err := c.ShouldBindJSON(&sysErrpr)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
err = sysErrprService.CreateSysError(ctx, &sysErrpr)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("创建失败!", zap.Error(err))
|
||||
response.FailWithMessage("创建失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("创建成功", c)
|
||||
}
|
||||
|
||||
// DeleteSysError 删除错误日志
|
||||
// @Tags SysError
|
||||
// @Summary 删除错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body system.SysError true "删除错误日志"
|
||||
// @Success 200 {object} response.Response{msg=string} "删除成功"
|
||||
// @Router /sysErrpr/deleteSysError [delete]
|
||||
func (sysErrprApi *SysErrorApi) DeleteSysError(c *gin.Context) {
|
||||
// 创建业务用Context
|
||||
ctx := c.Request.Context()
|
||||
|
||||
ID := c.Query("ID")
|
||||
err := sysErrprService.DeleteSysError(ctx, ID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("删除失败!", zap.Error(err))
|
||||
response.FailWithMessage("删除失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// DeleteSysErrorByIds 批量删除错误日志
|
||||
// @Tags SysError
|
||||
// @Summary 批量删除错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Success 200 {object} response.Response{msg=string} "批量删除成功"
|
||||
// @Router /sysErrpr/deleteSysErrorByIds [delete]
|
||||
func (sysErrprApi *SysErrorApi) DeleteSysErrorByIds(c *gin.Context) {
|
||||
// 创建业务用Context
|
||||
ctx := c.Request.Context()
|
||||
|
||||
IDs := c.QueryArray("IDs[]")
|
||||
err := sysErrprService.DeleteSysErrorByIds(ctx, IDs)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
|
||||
response.FailWithMessage("批量删除失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("批量删除成功", c)
|
||||
}
|
||||
|
||||
// UpdateSysError 更新错误日志
|
||||
// @Tags SysError
|
||||
// @Summary 更新错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body system.SysError true "更新错误日志"
|
||||
// @Success 200 {object} response.Response{msg=string} "更新成功"
|
||||
// @Router /sysErrpr/updateSysError [put]
|
||||
func (sysErrprApi *SysErrorApi) UpdateSysError(c *gin.Context) {
|
||||
// 从ctx获取标准context进行业务行为
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var sysErrpr system.SysError
|
||||
err := c.ShouldBindJSON(&sysErrpr)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
err = sysErrprService.UpdateSysError(ctx, sysErrpr)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("更新失败!", zap.Error(err))
|
||||
response.FailWithMessage("更新失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("更新成功", c)
|
||||
}
|
||||
|
||||
// FindSysError 用id查询错误日志
|
||||
// @Tags SysError
|
||||
// @Summary 用id查询错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param ID query uint true "用id查询错误日志"
|
||||
// @Success 200 {object} response.Response{data=system.SysError,msg=string} "查询成功"
|
||||
// @Router /sysErrpr/findSysError [get]
|
||||
func (sysErrprApi *SysErrorApi) FindSysError(c *gin.Context) {
|
||||
// 创建业务用Context
|
||||
ctx := c.Request.Context()
|
||||
|
||||
ID := c.Query("ID")
|
||||
resysErrpr, err := sysErrprService.GetSysError(ctx, ID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询失败!", zap.Error(err))
|
||||
response.FailWithMessage("查询失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithData(resysErrpr, c)
|
||||
}
|
||||
|
||||
// GetSysErrorList 分页获取错误日志列表
|
||||
// @Tags SysError
|
||||
// @Summary 分页获取错误日志列表
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data query systemReq.SysErrorSearch true "分页获取错误日志列表"
|
||||
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
|
||||
// @Router /sysErrpr/getSysErrorList [get]
|
||||
func (sysErrprApi *SysErrorApi) GetSysErrorList(c *gin.Context) {
|
||||
// 创建业务用Context
|
||||
ctx := c.Request.Context()
|
||||
|
||||
var pageInfo systemReq.SysErrorSearch
|
||||
err := c.ShouldBindQuery(&pageInfo)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
list, total, err := sysErrprService.GetSysErrorInfoList(ctx, pageInfo)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: pageInfo.Page,
|
||||
PageSize: pageInfo.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
|
@ -62,6 +62,7 @@ func RegisterTables() {
|
|||
system.JoinTemplate{},
|
||||
system.SysParams{},
|
||||
system.SysVersion{},
|
||||
system.SysError{},
|
||||
|
||||
example.ExaFile{},
|
||||
example.ExaCustomer{},
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ func Routers() *gin.Engine {
|
|||
systemRouter.InitAuthorityBtnRouterRouter(PrivateGroup) // 按钮权限管理
|
||||
systemRouter.InitSysExportTemplateRouter(PrivateGroup, PublicGroup) // 导出模板
|
||||
systemRouter.InitSysParamsRouter(PrivateGroup, PublicGroup) // 参数管理
|
||||
systemRouter.InitSysErrorRouter(PrivateGroup, PublicGroup) // 错误日志
|
||||
exampleRouter.InitCustomerRouter(PrivateGroup) // 客户路由
|
||||
exampleRouter.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由
|
||||
exampleRouter.InitAttachmentCategoryRouterRouter(PrivateGroup) // 文件上传下载分类
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package request
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SysErrorSearch struct{
|
||||
CreatedAtRange []time.Time `json:"createdAtRange" form:"createdAtRange[]"`
|
||||
Form *string `json:"form" form:"form"`
|
||||
Info *string `json:"info" form:"info"`
|
||||
request.PageInfo
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// 自动生成模板SysError
|
||||
package system
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
)
|
||||
|
||||
// 错误日志 结构体 SysError
|
||||
type SysError struct {
|
||||
global.GVA_MODEL
|
||||
Form *string `json:"form" form:"form" gorm:"comment:错误来源;column:form;type:text;" binding:"required"` //错误来源
|
||||
Info *string `json:"info" form:"info" gorm:"comment:错误内容;column:info;type:text;"` //错误内容
|
||||
Level string `json:"level" form:"level" gorm:"comment:日志等级;column:level;"`
|
||||
Solution *string `json:"solution" form:"solution" gorm:"comment:解决方案;column:solution;"` //解决方案
|
||||
}
|
||||
|
||||
// TableName 错误日志 SysError自定义表名 sys_error
|
||||
func (SysError) TableName() string {
|
||||
return "sys_error"
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ type RouterGroup struct {
|
|||
SysExportTemplateRouter
|
||||
SysParamsRouter
|
||||
SysVersionRouter
|
||||
SysErrorRouter
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -43,4 +44,5 @@ var (
|
|||
autoCodeTemplateApi = api.ApiGroupApp.SystemApiGroup.AutoCodeTemplateApi
|
||||
exportTemplateApi = api.ApiGroupApp.SystemApiGroup.SysExportTemplateApi
|
||||
sysVersionApi = api.ApiGroupApp.SystemApiGroup.SysVersionApi
|
||||
sysErrprApi = api.ApiGroupApp.SystemApiGroup.SysErrorApi
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/middleware"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SysErrorRouter struct{}
|
||||
|
||||
// InitSysErrorRouter 初始化 错误日志 路由信息
|
||||
func (s *SysErrorRouter) InitSysErrorRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
|
||||
sysErrprRouter := Router.Group("sysErrpr").Use(middleware.OperationRecord())
|
||||
sysErrprRouterWithoutRecord := Router.Group("sysErrpr")
|
||||
sysErrprRouterWithoutAuth := PublicRouter.Group("sysErrpr")
|
||||
{
|
||||
sysErrprRouter.DELETE("deleteSysError", sysErrprApi.DeleteSysError) // 删除错误日志
|
||||
sysErrprRouter.DELETE("deleteSysErrorByIds", sysErrprApi.DeleteSysErrorByIds) // 批量删除错误日志
|
||||
sysErrprRouter.PUT("updateSysError", sysErrprApi.UpdateSysError) // 更新错误日志
|
||||
}
|
||||
{
|
||||
sysErrprRouterWithoutRecord.GET("findSysError", sysErrprApi.FindSysError) // 根据ID获取错误日志
|
||||
sysErrprRouterWithoutRecord.GET("getSysErrorList", sysErrprApi.GetSysErrorList) // 获取错误日志列表
|
||||
}
|
||||
{
|
||||
sysErrprRouterWithoutAuth.POST("createSysError", sysErrprApi.CreateSysError) // 新建错误日志
|
||||
}
|
||||
}
|
||||
|
|
@ -22,4 +22,5 @@ type ServiceGroup struct {
|
|||
AutoCodePackage autoCodePackage
|
||||
AutoCodeHistory autoCodeHistory
|
||||
AutoCodeTemplate autoCodeTemplate
|
||||
SysErrorService
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
|
||||
)
|
||||
|
||||
type SysErrorService struct{}
|
||||
|
||||
// CreateSysError 创建错误日志记录
|
||||
// Author [yourname](https://github.com/yourname)
|
||||
func (sysErrprService *SysErrorService) CreateSysError(ctx context.Context, sysErrpr *system.SysError) (err error) {
|
||||
err = global.GVA_DB.Create(sysErrpr).Error
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteSysError 删除错误日志记录
|
||||
// Author [yourname](https://github.com/yourname)
|
||||
func (sysErrprService *SysErrorService) DeleteSysError(ctx context.Context, ID string) (err error) {
|
||||
err = global.GVA_DB.Delete(&system.SysError{}, "id = ?", ID).Error
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteSysErrorByIds 批量删除错误日志记录
|
||||
// Author [yourname](https://github.com/yourname)
|
||||
func (sysErrprService *SysErrorService) DeleteSysErrorByIds(ctx context.Context, IDs []string) (err error) {
|
||||
err = global.GVA_DB.Delete(&[]system.SysError{}, "id in ?", IDs).Error
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateSysError 更新错误日志记录
|
||||
// Author [yourname](https://github.com/yourname)
|
||||
func (sysErrprService *SysErrorService) UpdateSysError(ctx context.Context, sysErrpr system.SysError) (err error) {
|
||||
err = global.GVA_DB.Model(&system.SysError{}).Where("id = ?", sysErrpr.ID).Updates(&sysErrpr).Error
|
||||
return err
|
||||
}
|
||||
|
||||
// GetSysError 根据ID获取错误日志记录
|
||||
// Author [yourname](https://github.com/yourname)
|
||||
func (sysErrprService *SysErrorService) GetSysError(ctx context.Context, ID string) (sysErrpr system.SysError, err error) {
|
||||
err = global.GVA_DB.Where("id = ?", ID).First(&sysErrpr).Error
|
||||
return
|
||||
}
|
||||
|
||||
// GetSysErrorInfoList 分页获取错误日志记录
|
||||
// Author [yourname](https://github.com/yourname)
|
||||
func (sysErrprService *SysErrorService) GetSysErrorInfoList(ctx context.Context, info systemReq.SysErrorSearch) (list []system.SysError, total int64, err error) {
|
||||
limit := info.PageSize
|
||||
offset := info.PageSize * (info.Page - 1)
|
||||
// 创建db
|
||||
db := global.GVA_DB.Model(&system.SysError{}).Order("created desc")
|
||||
var sysErrprs []system.SysError
|
||||
// 如果有条件搜索 下方会自动创建搜索语句
|
||||
if len(info.CreatedAtRange) == 2 {
|
||||
db = db.Where("created_at BETWEEN ? AND ?", info.CreatedAtRange[0], info.CreatedAtRange[1])
|
||||
}
|
||||
|
||||
if info.Form != nil && *info.Form != "" {
|
||||
db = db.Where("form = ?", *info.Form)
|
||||
}
|
||||
if info.Info != nil && *info.Info != "" {
|
||||
db = db.Where("info LIKE ?", "%"+*info.Info+"%")
|
||||
}
|
||||
err = db.Count(&total).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if limit != 0 {
|
||||
db = db.Limit(limit).Offset(offset)
|
||||
}
|
||||
|
||||
err = db.Find(&sysErrprs).Error
|
||||
return sysErrprs, total, err
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
import service from '@/utils/request'
|
||||
// @Tags SysError
|
||||
// @Summary 创建错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body model.SysError true "创建错误日志"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
|
||||
// @Router /sysErrpr/createSysError [post]
|
||||
export const createSysError = (data) => {
|
||||
return service({
|
||||
url: '/sysErrpr/createSysError',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags SysError
|
||||
// @Summary 删除错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body model.SysError true "删除错误日志"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
|
||||
// @Router /sysErrpr/deleteSysError [delete]
|
||||
export const deleteSysError = (params) => {
|
||||
return service({
|
||||
url: '/sysErrpr/deleteSysError',
|
||||
method: 'delete',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags SysError
|
||||
// @Summary 批量删除错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body request.IdsReq true "批量删除错误日志"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
|
||||
// @Router /sysErrpr/deleteSysError [delete]
|
||||
export const deleteSysErrorByIds = (params) => {
|
||||
return service({
|
||||
url: '/sysErrpr/deleteSysErrorByIds',
|
||||
method: 'delete',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags SysError
|
||||
// @Summary 更新错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body model.SysError true "更新错误日志"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
|
||||
// @Router /sysErrpr/updateSysError [put]
|
||||
export const updateSysError = (data) => {
|
||||
return service({
|
||||
url: '/sysErrpr/updateSysError',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags SysError
|
||||
// @Summary 用id查询错误日志
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data query model.SysError true "用id查询错误日志"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
|
||||
// @Router /sysErrpr/findSysError [get]
|
||||
export const findSysError = (params) => {
|
||||
return service({
|
||||
url: '/sysErrpr/findSysError',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags SysError
|
||||
// @Summary 分页获取错误日志列表
|
||||
// @Security ApiKeyAuth
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data query request.PageInfo true "分页获取错误日志列表"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
|
||||
// @Router /sysErrpr/getSysErrorList [get]
|
||||
export const getSysErrorList = (params) => {
|
||||
return service({
|
||||
url: '/sysErrpr/getSysErrorList',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags SysError
|
||||
// @Summary 不需要鉴权的错误日志接口
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data query systemReq.SysErrorSearch true "分页获取错误日志列表"
|
||||
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
|
||||
// @Router /sysErrpr/getSysErrorPublic [get]
|
||||
export const getSysErrorPublic = () => {
|
||||
return service({
|
||||
url: '/sysErrpr/getSysErrorPublic',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
|
@ -1,51 +1,24 @@
|
|||
import { createSysError } from '@/api/system/sysError'
|
||||
|
||||
function sendErrorTip(errorInfo) {
|
||||
console.groupCollapsed(`捕获到错误: ${errorInfo.type}`);
|
||||
console.log('错误类型:', errorInfo.type);
|
||||
console.log('错误信息:', errorInfo.message);
|
||||
console.log('调用栈:', errorInfo.stack);
|
||||
if (errorInfo.component) {
|
||||
console.log('组件名:', errorInfo.component.name)
|
||||
console.log('组件地址:', errorInfo.component.__file)
|
||||
}
|
||||
if (errorInfo.vueInfo) console.log('Vue 信息:', errorInfo.vueInfo);
|
||||
if (errorInfo.source) console.log('来源文件:', errorInfo.source);
|
||||
if (errorInfo.lineno) console.log('行号:', errorInfo.lineno);
|
||||
if (errorInfo.colno) console.log('列号:', errorInfo.colno);
|
||||
console.groupEnd();
|
||||
setTimeout(() => {
|
||||
const errorData = {
|
||||
form: errorInfo.type,
|
||||
info: `${errorInfo.message}\nStack: ${errorInfo.stack}${errorInfo.component ? `\nComponent: ${errorInfo.component.name || 'Unknown'}` : ''}${errorInfo.vueInfo ? `\nVue Info: ${errorInfo.vueInfo}` : ''}${errorInfo.source ? `\nSource: ${errorInfo.source}:${errorInfo.lineno}:${errorInfo.colno}` : ''}`,
|
||||
level: 'error',
|
||||
solution: null
|
||||
}
|
||||
|
||||
createSysError(errorData).catch(apiErr => {
|
||||
console.error('Failed to create error record:', apiErr)
|
||||
})
|
||||
}, 0)
|
||||
}
|
||||
|
||||
function initVueErrorHandler(app) {
|
||||
app.config.errorHandler = (err, vm, info) => {
|
||||
let errorType = 'Vue Error';
|
||||
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
sendErrorTip({
|
||||
type: errorType,
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
component: vm.$options || 'Unknown Vue Component',
|
||||
vueInfo: info
|
||||
type: 'Frontend',
|
||||
message: `错误信息: ${event.reason}`,
|
||||
stack: `调用栈: ${event.reason?.stack || '没有调用栈信息'}`,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function initJsErrorHandler() {
|
||||
window.onerror = (message, source, lineno, colno, error) => {
|
||||
let errorType = 'JS Error';
|
||||
|
||||
sendErrorTip({
|
||||
type: errorType,
|
||||
message: message,
|
||||
stack: error ? error.stack : 'No stack available',
|
||||
source: source,
|
||||
lineno: lineno,
|
||||
colno: colno
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
export function initErrorHandler(app) {
|
||||
initVueErrorHandler(app)
|
||||
initJsErrorHandler()
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,13 +15,10 @@ import auth from '@/directive/auth'
|
|||
import clickOutSide from '@/directive/clickOutSide'
|
||||
import { store } from '@/pinia'
|
||||
import App from './App.vue'
|
||||
// import { initErrorHandler } from '@/core/error-handel'
|
||||
|
||||
import '@/core/error-handel'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
// 注入错误处理捕获
|
||||
// initErrorHandler(app)
|
||||
app.config.productionTip = false
|
||||
|
||||
app
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ export const useUserStore = defineStore('user', () => {
|
|||
}
|
||||
})
|
||||
}
|
||||
console.log(appStore.config)
|
||||
}
|
||||
|
||||
const setToken = (val) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,378 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="gva-search-box">
|
||||
<el-form
|
||||
ref="elSearchFormRef"
|
||||
:inline="true"
|
||||
:model="searchInfo"
|
||||
class="demo-form-inline"
|
||||
@keyup.enter="onSubmit"
|
||||
>
|
||||
<el-form-item label="创建日期" prop="createdAtRange">
|
||||
<template #label>
|
||||
<span>
|
||||
创建日期
|
||||
<el-tooltip
|
||||
content="搜索范围是开始日期(包含)至结束日期(不包含)"
|
||||
>
|
||||
<el-icon><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<el-date-picker
|
||||
v-model="searchInfo.createdAtRange"
|
||||
class="!w-380px"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="错误来源" prop="form">
|
||||
<el-input v-model="searchInfo.form" placeholder="搜索条件" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="错误内容" prop="info">
|
||||
<el-input v-model="searchInfo.info" placeholder="搜索条件" />
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="showAllQuery">
|
||||
<!-- 将需要控制显示状态的查询条件添加到此范围内 -->
|
||||
</template>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="search" @click="onSubmit"
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button icon="refresh" @click="onReset">重置</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="arrow-down"
|
||||
@click="showAllQuery = true"
|
||||
v-if="!showAllQuery"
|
||||
>展开</el-button
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="arrow-up"
|
||||
@click="showAllQuery = false"
|
||||
v-else
|
||||
>收起</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="gva-table-box">
|
||||
<div class="gva-btn-list">
|
||||
<el-button
|
||||
icon="delete"
|
||||
style="margin-left: 10px"
|
||||
:disabled="!multipleSelection.length"
|
||||
@click="onDelete"
|
||||
>删除</el-button
|
||||
>
|
||||
</div>
|
||||
<el-table
|
||||
ref="multipleTable"
|
||||
style="width: 100%"
|
||||
tooltip-effect="dark"
|
||||
:data="tableData"
|
||||
row-key="ID"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
|
||||
<el-table-column
|
||||
sortable
|
||||
align="left"
|
||||
label="日期"
|
||||
prop="CreatedAt"
|
||||
width="180"
|
||||
>
|
||||
<template #default="scope">{{
|
||||
formatDate(scope.row.CreatedAt)
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
align="left"
|
||||
label="错误来源"
|
||||
prop="form"
|
||||
width="120"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
align="left"
|
||||
label="错误等级"
|
||||
prop="level"
|
||||
width="120"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
align="left"
|
||||
label="错误内容"
|
||||
prop="info"
|
||||
show-overflow-tooltip
|
||||
width="240"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
align="left"
|
||||
label="解决方案"
|
||||
show-overflow-tooltip
|
||||
prop="solution"
|
||||
width="120"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
align="left"
|
||||
label="操作"
|
||||
fixed="right"
|
||||
:min-width="appStore.operateMinWith"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
class="table-button"
|
||||
@click="getDetails(scope.row)"
|
||||
><el-icon><ai-gva /></el-icon
|
||||
>方案</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
class="table-button"
|
||||
@click="getDetails(scope.row)"
|
||||
><el-icon style="margin-right: 5px"><InfoFilled /></el-icon
|
||||
>查看</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
icon="delete"
|
||||
@click="deleteRow(scope.row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="gva-pagination">
|
||||
<el-pagination
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:current-page="page"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 30, 50, 100]"
|
||||
:total="total"
|
||||
@current-change="handleCurrentChange"
|
||||
@size-change="handleSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-drawer
|
||||
destroy-on-close
|
||||
:size="appStore.drawerSize"
|
||||
v-model="detailShow"
|
||||
:show-close="true"
|
||||
:before-close="closeDetailShow"
|
||||
title="查看"
|
||||
>
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="错误来源">
|
||||
{{ detailForm.form }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="错误等级">
|
||||
{{ detailForm.level }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="错误内容">
|
||||
<pre class="whitespace-pre-wrap break-words">{{ detailForm.info }}</pre>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="解决方案">
|
||||
<pre class="whitespace-pre-wrap break-words">{{ detailForm.solution }}</pre>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
deleteSysError,
|
||||
deleteSysErrorByIds,
|
||||
findSysError,
|
||||
getSysErrorList
|
||||
} from '@/api/system/sysError'
|
||||
|
||||
import { formatDate } from '@/utils/format'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
import { useAppStore } from '@/pinia'
|
||||
|
||||
defineOptions({
|
||||
name: 'SysError'
|
||||
})
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
// 控制更多查询条件显示/隐藏状态
|
||||
const showAllQuery = ref(false)
|
||||
|
||||
const elSearchFormRef = ref()
|
||||
|
||||
// =========== 表格控制部分 ===========
|
||||
const page = ref(1)
|
||||
const total = ref(0)
|
||||
const pageSize = ref(10)
|
||||
const tableData = ref([])
|
||||
const searchInfo = ref({})
|
||||
// 重置
|
||||
const onReset = () => {
|
||||
searchInfo.value = {}
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const onSubmit = () => {
|
||||
elSearchFormRef.value?.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
page.value = 1
|
||||
getTableData()
|
||||
})
|
||||
}
|
||||
|
||||
// 分页
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 修改页面容量
|
||||
const handleCurrentChange = (val) => {
|
||||
page.value = val
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 查询
|
||||
const getTableData = async () => {
|
||||
const table = await getSysErrorList({
|
||||
page: page.value,
|
||||
pageSize: pageSize.value,
|
||||
...searchInfo.value
|
||||
})
|
||||
if (table.code === 0) {
|
||||
tableData.value = table.data.list
|
||||
total.value = table.data.total
|
||||
page.value = table.data.page
|
||||
pageSize.value = table.data.pageSize
|
||||
}
|
||||
}
|
||||
|
||||
getTableData()
|
||||
|
||||
// ============== 表格控制部分结束 ===============
|
||||
|
||||
// 获取需要的字典 可能为空 按需保留
|
||||
const setOptions = async () => {}
|
||||
|
||||
// 获取需要的字典 可能为空 按需保留
|
||||
setOptions()
|
||||
|
||||
// 多选数据
|
||||
const multipleSelection = ref([])
|
||||
// 多选
|
||||
const handleSelectionChange = (val) => {
|
||||
multipleSelection.value = val
|
||||
}
|
||||
|
||||
// 删除行
|
||||
const deleteRow = (row) => {
|
||||
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteSysErrorFunc(row)
|
||||
})
|
||||
}
|
||||
|
||||
// 多选删除
|
||||
const onDelete = async () => {
|
||||
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const IDs = []
|
||||
if (multipleSelection.value.length === 0) {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: '请选择要删除的数据'
|
||||
})
|
||||
return
|
||||
}
|
||||
multipleSelection.value &&
|
||||
multipleSelection.value.map((item) => {
|
||||
IDs.push(item.ID)
|
||||
})
|
||||
const res = await deleteSysErrorByIds({ IDs })
|
||||
if (res.code === 0) {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '删除成功'
|
||||
})
|
||||
if (tableData.value.length === IDs.length && page.value > 1) {
|
||||
page.value--
|
||||
}
|
||||
getTableData()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除行
|
||||
const deleteSysErrorFunc = async (row) => {
|
||||
const res = await deleteSysError({ ID: row.ID })
|
||||
if (res.code === 0) {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '删除成功'
|
||||
})
|
||||
if (tableData.value.length === 1 && page.value > 1) {
|
||||
page.value--
|
||||
}
|
||||
getTableData()
|
||||
}
|
||||
}
|
||||
|
||||
const detailForm = ref({})
|
||||
|
||||
// 查看详情控制标记
|
||||
const detailShow = ref(false)
|
||||
|
||||
// 打开详情弹窗
|
||||
const openDetailShow = () => {
|
||||
detailShow.value = true
|
||||
}
|
||||
|
||||
// 打开详情
|
||||
const getDetails = async (row) => {
|
||||
// 打开弹窗
|
||||
const res = await findSysError({ ID: row.ID })
|
||||
if (res.code === 0) {
|
||||
detailForm.value = res.data
|
||||
openDetailShow()
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭详情弹窗
|
||||
const closeDetailShow = () => {
|
||||
detailShow.value = false
|
||||
detailForm.value = {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
Loading…
Reference in New Issue