mirror of
https://gitee.com/xiangheng/x_admin.git
synced 2025-10-03 15:26:26 +08:00
完善slow
This commit is contained in:
@@ -13,6 +13,21 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/XErr.umd.js"></script>
|
||||||
|
<script>
|
||||||
|
const xErr = new XErr.XErr(
|
||||||
|
{
|
||||||
|
Dns: `${location.origin}/api`,
|
||||||
|
Pid: 'e19e3be20de94f49b68fafb4c30668bc',
|
||||||
|
Uid: ''
|
||||||
|
},
|
||||||
|
new XErr.XErrWeb({
|
||||||
|
onloadTimeOut: 300
|
||||||
|
})
|
||||||
|
)
|
||||||
|
xErr.SetUid(2) //设置用户ID
|
||||||
|
</script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="/src/styles/loading.css" />
|
<link rel="stylesheet" href="/src/styles/loading.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
3
admin/public/XErr.umd.js
Normal file
3
admin/public/XErr.umd.js
Normal file
File diff suppressed because one or more lines are too long
@@ -11,19 +11,18 @@ import ElementPlus from 'element-plus'
|
|||||||
|
|
||||||
import VForm3 from 'vform3-builds' //引入VForm3库
|
import VForm3 from 'vform3-builds' //引入VForm3库
|
||||||
|
|
||||||
import { XErr, XErrWeb } from '../../x_err_sdk/web/index'
|
// import { Base, Web } from '../../x_err_sdk/web/index'
|
||||||
// { XErr, XErrWeb }
|
// const xErr = new Base(
|
||||||
const xErr = new XErr(
|
// {
|
||||||
{
|
// Dns: `${location.origin}/api`,
|
||||||
Dns: `${location.origin}/api`,
|
// Pid: 'e19e3be20de94f49b68fafb4c30668bc',
|
||||||
Pid: 'e19e3be20de94f49b68fafb4c30668bc',
|
// Uid: ''
|
||||||
Uid: ''
|
// },
|
||||||
},
|
// new Web({
|
||||||
new XErrWeb({
|
// onloadTimeOut: 300
|
||||||
onloadTimeOut: 3000
|
// })
|
||||||
})
|
// )
|
||||||
)
|
// xErr.SetUid(1) //设置用户ID
|
||||||
xErr.SetUid(1) //设置用户ID
|
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
app.use(install)
|
app.use(install)
|
||||||
|
@@ -97,10 +97,12 @@ const code = computed(() => {
|
|||||||
new XErr(
|
new XErr(
|
||||||
{
|
{
|
||||||
Dns: '${location.origin}/api',
|
Dns: '${location.origin}/api',
|
||||||
Pid: ${formData.ProjectKey},
|
Pid: '${formData.ProjectKey}',
|
||||||
Uid: ''
|
Uid: ''
|
||||||
},
|
},
|
||||||
new XErrWeb()
|
new XErrWeb({
|
||||||
|
onloadTimeOut: 3000
|
||||||
|
})
|
||||||
)`
|
)`
|
||||||
})
|
})
|
||||||
const formRules = {
|
const formRules = {
|
||||||
|
@@ -9,16 +9,22 @@
|
|||||||
label-width="70px"
|
label-width="70px"
|
||||||
label-position="left"
|
label-position="left"
|
||||||
>
|
>
|
||||||
<el-form-item label="项目key" prop="ProjectKey" class="w-[280px]">
|
<el-form-item label="项目" prop="ProjectKey" class="w-[280px]">
|
||||||
<el-input v-model="queryParams.ProjectKey" />
|
<el-select v-model="queryParams.ProjectKey" clearable>
|
||||||
</el-form-item>
|
<el-option label="全部" value="" />
|
||||||
<el-form-item label="sdk生成的客户端id" prop="ClientId" class="w-[280px]">
|
<el-option
|
||||||
<el-input v-model="queryParams.ClientId" />
|
v-for="(item, index) in listAllData.monitor_project_listAll"
|
||||||
|
:key="index"
|
||||||
|
:label="item.ProjectName"
|
||||||
|
:value="item.ProjectKey"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="用户id" prop="UserId" class="w-[280px]">
|
<el-form-item label="用户id" prop="UserId" class="w-[280px]">
|
||||||
<el-input v-model="queryParams.UserId" />
|
<el-input v-model="queryParams.UserId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间" prop="CreateTime" class="w-[280px]">
|
<el-form-item label="创建时间" prop="CreateTime" class="w-[420px]">
|
||||||
<daterange-picker
|
<daterange-picker
|
||||||
v-model:startTime="queryParams.CreateTimeStart"
|
v-model:startTime="queryParams.CreateTimeStart"
|
||||||
v-model:endTime="queryParams.CreateTimeEnd"
|
v-model:endTime="queryParams.CreateTimeEnd"
|
||||||
@@ -32,13 +38,13 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
<el-card class="!border-none mt-4" shadow="never">
|
<el-card class="!border-none mt-4" shadow="never">
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
<el-button v-perms="['admin:monitor_slow:add']" type="primary" @click="handleAdd()">
|
<!-- <el-button v-perms="['admin:monitor_slow:add']" type="primary" @click="handleAdd()">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<icon name="el-icon-Plus" />
|
<icon name="el-icon-Plus" />
|
||||||
</template>
|
</template>
|
||||||
新增
|
新增
|
||||||
</el-button>
|
</el-button> -->
|
||||||
<upload
|
<!-- <upload
|
||||||
v-perms="['admin:monitor_slow:ImportFile']"
|
v-perms="['admin:monitor_slow:ImportFile']"
|
||||||
class="ml-3 mr-3"
|
class="ml-3 mr-3"
|
||||||
:url="monitor_slow_import_file"
|
:url="monitor_slow_import_file"
|
||||||
@@ -53,8 +59,8 @@
|
|||||||
</template>
|
</template>
|
||||||
导入
|
导入
|
||||||
</el-button>
|
</el-button>
|
||||||
</upload>
|
</upload> -->
|
||||||
<el-button
|
<!-- <el-button
|
||||||
v-perms="['admin:monitor_slow:ExportFile']"
|
v-perms="['admin:monitor_slow:ExportFile']"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="exportFile"
|
@click="exportFile"
|
||||||
@@ -63,7 +69,7 @@
|
|||||||
<icon name="el-icon-Download" />
|
<icon name="el-icon-Download" />
|
||||||
</template>
|
</template>
|
||||||
导出
|
导出
|
||||||
</el-button>
|
</el-button> -->
|
||||||
<el-button
|
<el-button
|
||||||
v-perms="['admin:monitor_slow:delBatch']"
|
v-perms="['admin:monitor_slow:delBatch']"
|
||||||
type="danger"
|
type="danger"
|
||||||
@@ -81,22 +87,31 @@
|
|||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="55" />
|
<el-table-column type="selection" width="55" />
|
||||||
<el-table-column label="项目key" prop="ProjectKey" min-width="130" />
|
<el-table-column label="项目" prop="ProjectKey" width="150">
|
||||||
<el-table-column label="sdk生成的客户端id" prop="ClientId" min-width="130" />
|
|
||||||
<el-table-column label="用户id" prop="UserId" min-width="130" />
|
|
||||||
<el-table-column label="URL地址" prop="Path" min-width="130" />
|
|
||||||
<el-table-column label="时间" prop="Time" min-width="130" />
|
|
||||||
<el-table-column label="创建时间" prop="CreateTime" min-width="130" />
|
|
||||||
<el-table-column label="操作" width="120" fixed="right">
|
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button
|
<dict-value
|
||||||
|
:options="listAllData.monitor_project_listAll"
|
||||||
|
:value="row.ProjectKey"
|
||||||
|
labelKey="ProjectName"
|
||||||
|
valueKey="ProjectKey"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="用户id" prop="UserId" width="150" />
|
||||||
|
<el-table-column label="URL地址" prop="Path" />
|
||||||
|
<el-table-column label="时间(毫秒)" prop="Time" width="130" />
|
||||||
|
<el-table-column label="创建时间" prop="CreateTime" width="180" />
|
||||||
|
<el-table-column label="操作" width="80" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<!-- <el-button
|
||||||
v-perms="['admin:monitor_slow:edit']"
|
v-perms="['admin:monitor_slow:edit']"
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
@click="handleEdit(row)"
|
@click="handleEdit(row)"
|
||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button> -->
|
||||||
<el-button
|
<el-button
|
||||||
v-perms="['admin:monitor_slow:del']"
|
v-perms="['admin:monitor_slow:del']"
|
||||||
type="danger"
|
type="danger"
|
||||||
@@ -116,16 +131,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, shallowRef, nextTick } from 'vue'
|
import { ref, reactive, shallowRef } from 'vue'
|
||||||
import {
|
import {
|
||||||
monitor_slow_delete,
|
monitor_slow_delete,
|
||||||
monitor_slow_delete_batch,
|
monitor_slow_delete_batch,
|
||||||
monitor_slow_list,
|
monitor_slow_list
|
||||||
monitor_slow_import_file,
|
|
||||||
monitor_slow_export_file
|
|
||||||
} from '@/api/monitor/slow'
|
} from '@/api/monitor/slow'
|
||||||
import type { type_monitor_slow, type_monitor_slow_query } from '@/api/monitor/slow'
|
import type { type_monitor_slow, type_monitor_slow_query } from '@/api/monitor/slow'
|
||||||
|
|
||||||
|
import { useListAllData } from '@/hooks/useDictOptions'
|
||||||
import { usePaging } from '@/hooks/usePaging'
|
import { usePaging } from '@/hooks/usePaging'
|
||||||
import feedback from '@/utils/feedback'
|
import feedback from '@/utils/feedback'
|
||||||
import EditPopup from './edit.vue'
|
import EditPopup from './edit.vue'
|
||||||
@@ -148,19 +162,12 @@ const { pager, getLists, resetPage, resetParams } = usePaging<type_monitor_slow>
|
|||||||
fetchFun: monitor_slow_list,
|
fetchFun: monitor_slow_list,
|
||||||
params: queryParams
|
params: queryParams
|
||||||
})
|
})
|
||||||
|
const { listAllData } = useListAllData<{
|
||||||
|
monitor_project_listAll: any[]
|
||||||
|
}>({
|
||||||
|
monitor_project_listAll: '/monitor_project/listAll'
|
||||||
|
})
|
||||||
|
|
||||||
const handleAdd = async () => {
|
|
||||||
showEdit.value = true
|
|
||||||
await nextTick()
|
|
||||||
editRef.value?.open('add')
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleEdit = async (data: any) => {
|
|
||||||
showEdit.value = true
|
|
||||||
await nextTick()
|
|
||||||
editRef.value?.open('edit')
|
|
||||||
editRef.value?.getDetail(data)
|
|
||||||
}
|
|
||||||
const multipleSelection = ref<type_monitor_slow[]>([])
|
const multipleSelection = ref<type_monitor_slow[]>([])
|
||||||
const handleSelectionChange = (val: type_monitor_slow[]) => {
|
const handleSelectionChange = (val: type_monitor_slow[]) => {
|
||||||
console.log(val)
|
console.log(val)
|
||||||
@@ -191,11 +198,5 @@ const deleteBatch = async () => {
|
|||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const exportFile = async () => {
|
|
||||||
try {
|
|
||||||
await feedback.confirm('确定要导出?')
|
|
||||||
await monitor_slow_export_file(queryParams)
|
|
||||||
} catch (error) {}
|
|
||||||
}
|
|
||||||
getLists()
|
getLists()
|
||||||
</script>
|
</script>
|
||||||
|
@@ -23,10 +23,12 @@ export default ({ mode }) => {
|
|||||||
// 依赖预构建,避免开发刷新
|
// 依赖预构建,避免开发刷新
|
||||||
include: ['@wangeditor/editor-for-vue', 'vuedraggable', 'vue-echarts', 'crypto-js']
|
include: ['@wangeditor/editor-for-vue', 'vuedraggable', 'vue-echarts', 'crypto-js']
|
||||||
},
|
},
|
||||||
|
|
||||||
base: '/',
|
base: '/',
|
||||||
build: {
|
build: {
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
|
external: ['XErr'],
|
||||||
output: {
|
output: {
|
||||||
manualChunks: {
|
manualChunks: {
|
||||||
vue: ['vue'],
|
vue: ['vue'],
|
||||||
|
@@ -13,6 +13,7 @@ import (
|
|||||||
"x_admin/core/response"
|
"x_admin/core/response"
|
||||||
"x_admin/util"
|
"x_admin/util"
|
||||||
"x_admin/util/excel2"
|
"x_admin/util/excel2"
|
||||||
|
"x_admin/util/img_util"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
@@ -141,28 +142,24 @@ func (hd *MonitorClientHandler) Add(c *gin.Context) {
|
|||||||
data, err := url.QueryUnescape(c.Query("data"))
|
data, err := url.QueryUnescape(c.Query("data"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// response.CheckAndRespWithData(c, 0, err)
|
// response.CheckAndRespWithData(c, 0, err)
|
||||||
c.Writer.WriteString("0")
|
c.Data(200, "image/gif", img_util.EmptyGif())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var addReq MonitorClientAddReq
|
var addReq MonitorClientAddReq
|
||||||
json.Unmarshal([]byte(data), &addReq)
|
json.Unmarshal([]byte(data), &addReq)
|
||||||
// if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
lastClient, err := MonitorClientService.DetailByClientId(*addReq.ClientId)
|
lastClient, err := MonitorClientService.DetailByClientId(*addReq.ClientId)
|
||||||
|
|
||||||
uaStr := c.GetHeader("user-agent")
|
uaStr := c.GetHeader("user-agent")
|
||||||
ip := c.ClientIP()
|
ip := c.ClientIP()
|
||||||
|
|
||||||
// createFlag := true
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
last := lastClient.UserId + lastClient.Width.String() + lastClient.Height.String() + lastClient.Ip + lastClient.Ua
|
last := lastClient.UserId + lastClient.Width.String() + lastClient.Height.String() + lastClient.Ip + lastClient.Ua
|
||||||
newStr := *addReq.UserId + addReq.Width.String() + addReq.Height.String() + ip + uaStr
|
newStr := *addReq.UserId + addReq.Width.String() + addReq.Height.String() + ip + uaStr
|
||||||
if last == newStr {
|
if last == newStr {
|
||||||
// 前后数据一样,不用创建新的数据
|
// 前后数据一样,不用创建新的数据
|
||||||
fmt.Println("前后数据一样,不用创建新的数据")
|
fmt.Println("前后数据一样,不用创建新的数据")
|
||||||
c.Writer.WriteString("0")
|
c.Data(200, "image/gif", img_util.EmptyGif())
|
||||||
// response.CheckAndRespWithData(c, 0, nil)
|
// response.CheckAndRespWithData(c, 0, nil)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -188,10 +185,9 @@ func (hd *MonitorClientHandler) Add(c *gin.Context) {
|
|||||||
addReq.Province = ®ionInfo.Province
|
addReq.Province = ®ionInfo.Province
|
||||||
}
|
}
|
||||||
|
|
||||||
createId, _ := MonitorClientService.Add(addReq)
|
MonitorClientService.Add(addReq)
|
||||||
// response.CheckAndRespWithData(c, createId, e)
|
|
||||||
// c.Value(createId)
|
c.Data(200, "image/gif", img_util.EmptyGif())
|
||||||
c.Writer.WriteString(strconv.Itoa(createId))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary 监控-客户端信息删除
|
// @Summary 监控-客户端信息删除
|
||||||
|
@@ -1,11 +1,7 @@
|
|||||||
package monitor_error
|
package monitor_error
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
"image/gif"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -15,6 +11,7 @@ import (
|
|||||||
"x_admin/core/response"
|
"x_admin/core/response"
|
||||||
"x_admin/util"
|
"x_admin/util"
|
||||||
"x_admin/util/excel2"
|
"x_admin/util/excel2"
|
||||||
|
"x_admin/util/img_util"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
@@ -111,7 +108,8 @@ func (hd *MonitorErrorHandler) Detail(c *gin.Context) {
|
|||||||
func (hd *MonitorErrorHandler) Add(c *gin.Context) {
|
func (hd *MonitorErrorHandler) Add(c *gin.Context) {
|
||||||
data, err := url.QueryUnescape(c.Query("data"))
|
data, err := url.QueryUnescape(c.Query("data"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.CheckAndRespWithData(c, 0, err)
|
// response.CheckAndRespWithData(c, 0, err)
|
||||||
|
c.Data(200, "image/gif", img_util.EmptyGif())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,35 +122,8 @@ func (hd *MonitorErrorHandler) Add(c *gin.Context) {
|
|||||||
for i := 0; i < len(addReq); i++ {
|
for i := 0; i < len(addReq); i++ {
|
||||||
MonitorErrorService.Add(addReq[i])
|
MonitorErrorService.Add(addReq[i])
|
||||||
}
|
}
|
||||||
img := image.NewRGBA(image.Rect(0, 0, 1, 1))
|
|
||||||
|
|
||||||
// 设置像素颜色为黑色
|
|
||||||
img.Set(0, 0, color.Black)
|
|
||||||
|
|
||||||
// 创建GIF动画
|
|
||||||
g := &gif.GIF{
|
|
||||||
Image: []*image.Paletted{imageToPaletted(img)},
|
|
||||||
Delay: []int{0}, // 延迟时间,单位是10毫秒
|
|
||||||
}
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
|
|
||||||
// 编码GIF到缓冲区
|
|
||||||
err = gif.EncodeAll(&buffer, g)
|
|
||||||
|
|
||||||
// response.CheckAndRespWithData(c, g, nil)
|
// response.CheckAndRespWithData(c, g, nil)
|
||||||
c.Data(200, "image/gif", buffer.Bytes())
|
c.Data(200, "image/gif", img_util.EmptyGif())
|
||||||
}
|
|
||||||
|
|
||||||
// 将image.Image转换为*image.Paletted
|
|
||||||
func imageToPaletted(img image.Image) *image.Paletted {
|
|
||||||
b := img.Bounds()
|
|
||||||
pm := image.NewPaletted(b, color.Palette{color.Black})
|
|
||||||
for y := b.Min.Y; y < b.Max.Y; y++ {
|
|
||||||
for x := b.Min.X; x < b.Max.X; x++ {
|
|
||||||
pm.Set(x, y, img.At(x, y))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pm
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary 监控-错误列删除
|
// @Summary 监控-错误列删除
|
||||||
|
@@ -1,19 +1,22 @@
|
|||||||
package monitor_slow
|
package monitor_slow
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"x_admin/core/request"
|
"x_admin/core/request"
|
||||||
"x_admin/core/response"
|
"x_admin/core/response"
|
||||||
"x_admin/util"
|
"x_admin/util"
|
||||||
"x_admin/util/excel2"
|
"x_admin/util/excel2"
|
||||||
|
"x_admin/util/img_util"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type MonitorSlowHandler struct {
|
type MonitorSlowHandler struct {
|
||||||
requestGroup singleflight.Group
|
requestGroup singleflight.Group
|
||||||
}
|
}
|
||||||
@@ -31,6 +34,7 @@ type MonitorSlowHandler struct {
|
|||||||
// @Param Time query number false "时间"
|
// @Param Time query number false "时间"
|
||||||
// @Param CreateTimeStart query string false "创建时间"
|
// @Param CreateTimeStart query string false "创建时间"
|
||||||
// @Param CreateTimeEnd query string false "创建时间"
|
// @Param CreateTimeEnd query string false "创建时间"
|
||||||
|
//
|
||||||
// @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorSlowResp}} "成功"
|
// @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorSlowResp}} "成功"
|
||||||
// @Router /api/admin/monitor_slow/list [get]
|
// @Router /api/admin/monitor_slow/list [get]
|
||||||
func (hd *MonitorSlowHandler) List(c *gin.Context) {
|
func (hd *MonitorSlowHandler) List(c *gin.Context) {
|
||||||
@@ -87,7 +91,6 @@ func (hd *MonitorSlowHandler) Detail(c *gin.Context) {
|
|||||||
response.CheckAndRespWithData(c, res, err)
|
response.CheckAndRespWithData(c, res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @Summary 监控-错误列新增
|
// @Summary 监控-错误列新增
|
||||||
// @Tags monitor_slow-监控-错误列
|
// @Tags monitor_slow-监控-错误列
|
||||||
// @Produce json
|
// @Produce json
|
||||||
@@ -100,13 +103,19 @@ func (hd *MonitorSlowHandler) Detail(c *gin.Context) {
|
|||||||
// @Success 200 {object} response.Response "成功"
|
// @Success 200 {object} response.Response "成功"
|
||||||
// @Router /api/admin/monitor_slow/add [post]
|
// @Router /api/admin/monitor_slow/add [post]
|
||||||
func (hd *MonitorSlowHandler) Add(c *gin.Context) {
|
func (hd *MonitorSlowHandler) Add(c *gin.Context) {
|
||||||
var addReq MonitorSlowAddReq
|
data, err := url.QueryUnescape(c.Query("data"))
|
||||||
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
|
if err != nil {
|
||||||
|
c.Data(200, "image/gif", img_util.EmptyGif())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
createId, e := MonitorSlowService.Add(addReq)
|
|
||||||
response.CheckAndRespWithData(c,createId, e)
|
var addReq MonitorSlowAddReq
|
||||||
|
json.Unmarshal([]byte(data), &addReq)
|
||||||
|
|
||||||
|
MonitorSlowService.Add(addReq)
|
||||||
|
c.Data(200, "image/gif", img_util.EmptyGif())
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary 监控-错误列编辑
|
// @Summary 监控-错误列编辑
|
||||||
// @Tags monitor_slow-监控-错误列
|
// @Tags monitor_slow-监控-错误列
|
||||||
// @Produce json
|
// @Produce json
|
||||||
@@ -126,6 +135,7 @@ func (hd *MonitorSlowHandler) Edit(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
response.CheckAndRespWithData(c, editReq.Id, MonitorSlowService.Edit(editReq))
|
response.CheckAndRespWithData(c, editReq.Id, MonitorSlowService.Edit(editReq))
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary 监控-错误列删除
|
// @Summary 监控-错误列删除
|
||||||
// @Tags monitor_slow-监控-错误列
|
// @Tags monitor_slow-监控-错误列
|
||||||
// @Produce json
|
// @Produce json
|
||||||
@@ -143,6 +153,7 @@ func (hd *MonitorSlowHandler) Del(c *gin.Context) {
|
|||||||
|
|
||||||
// @Summary 监控-错误列删除-批量
|
// @Summary 监控-错误列删除-批量
|
||||||
// @Tags monitor_slow-监控-错误列
|
// @Tags monitor_slow-监控-错误列
|
||||||
|
//
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param Token header string true "token"
|
// @Param Token header string true "token"
|
||||||
// @Param Ids body string false "逗号分割的id"
|
// @Param Ids body string false "逗号分割的id"
|
||||||
@@ -162,8 +173,6 @@ func (hd *MonitorSlowHandler) DelBatch(c *gin.Context) {
|
|||||||
response.CheckAndResp(c, MonitorSlowService.DelBatch(Ids))
|
response.CheckAndResp(c, MonitorSlowService.DelBatch(Ids))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @Summary 监控-错误列导出
|
// @Summary 监控-错误列导出
|
||||||
// @Tags monitor_slow-监控-错误列
|
// @Tags monitor_slow-监控-错误列
|
||||||
// @Produce json
|
// @Produce json
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package monitor_slow
|
package monitor_slow
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"x_admin/core"
|
"x_admin/core"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MonitorSlowListReq 监控-错误列列表参数
|
// MonitorSlowListReq 监控-错误列列表参数
|
||||||
@@ -15,8 +15,6 @@ type MonitorSlowListReq struct {
|
|||||||
CreateTimeEnd *string // 结束创建时间
|
CreateTimeEnd *string // 结束创建时间
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MonitorSlowAddReq 监控-错误列新增参数
|
// MonitorSlowAddReq 监控-错误列新增参数
|
||||||
type MonitorSlowAddReq struct {
|
type MonitorSlowAddReq struct {
|
||||||
ProjectKey *string // 项目key
|
ProjectKey *string // 项目key
|
||||||
|
@@ -45,7 +45,7 @@ INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_sh
|
|||||||
// MonitorSlowRoute(rg)
|
// MonitorSlowRoute(rg)
|
||||||
func MonitorSlowRoute(rg *gin.RouterGroup) {
|
func MonitorSlowRoute(rg *gin.RouterGroup) {
|
||||||
handle := monitor_slow.MonitorSlowHandler{}
|
handle := monitor_slow.MonitorSlowHandler{}
|
||||||
rg.POST("/monitor_slow/add", middleware.RecordLog("慢接口新增"), handle.Add)
|
rg.GET("/monitor_slow/add", middleware.RecordLog("慢接口新增"), handle.Add)
|
||||||
r := rg.Group("/", middleware.TokenAuth())
|
r := rg.Group("/", middleware.TokenAuth())
|
||||||
r.GET("/monitor_slow/list", handle.List)
|
r.GET("/monitor_slow/list", handle.List)
|
||||||
r.GET("/monitor_slow/listAll", handle.ListAll)
|
r.GET("/monitor_slow/listAll", handle.ListAll)
|
||||||
|
38
server/util/img_util/img_util.go
Normal file
38
server/util/img_util/img_util.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package img_util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/gif"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EmptyGif() []byte {
|
||||||
|
img := image.NewRGBA(image.Rect(0, 0, 1, 1))
|
||||||
|
|
||||||
|
// 设置像素颜色为黑色
|
||||||
|
img.Set(0, 0, color.Black)
|
||||||
|
|
||||||
|
// 创建GIF动画
|
||||||
|
g := &gif.GIF{
|
||||||
|
Image: []*image.Paletted{imageToPaletted(img)},
|
||||||
|
Delay: []int{0}, // 延迟时间,单位是10毫秒
|
||||||
|
}
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
// 编码GIF到缓冲区
|
||||||
|
gif.EncodeAll(&buffer, g)
|
||||||
|
return buffer.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将image.Image转换为*image.Paletted
|
||||||
|
func imageToPaletted(img image.Image) *image.Paletted {
|
||||||
|
b := img.Bounds()
|
||||||
|
pm := image.NewPaletted(b, color.Palette{color.Black})
|
||||||
|
for y := b.Min.Y; y < b.Max.Y; y++ {
|
||||||
|
for x := b.Min.X; x < b.Max.X; x++ {
|
||||||
|
pm.Set(x, y, img.At(x, y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pm
|
||||||
|
}
|
@@ -2,21 +2,25 @@
|
|||||||
"name": "@adtkcn/x_err_sdk",
|
"name": "@adtkcn/x_err_sdk",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "错误监控sdk",
|
"description": "错误监控sdk",
|
||||||
"main": "dist/web/index.js",
|
"main": "dist/web/XErr.umd.js",
|
||||||
"private": false,
|
"private": false,
|
||||||
|
"file": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run build:web&&npm run build:ts",
|
"build": "vite build&&npm run build:ts",
|
||||||
"build:web": "esbuild web/index.ts --bundle --sourcemap --minify --outfile=dist/web/index.js --format=esm --target=es2015",
|
|
||||||
"build:ts": "tsc --emitDeclarationOnly",
|
"build:ts": "tsc --emitDeclarationOnly",
|
||||||
"outdated": "pnpm outdated"
|
"outdated": "pnpm outdated"
|
||||||
},
|
},
|
||||||
"keywords": ["x_err_sdk","X_admin"],
|
"keywords": [
|
||||||
|
"x_err_sdk",
|
||||||
|
"X_admin"
|
||||||
|
],
|
||||||
"author": "adtkcn",
|
"author": "adtkcn",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
"uuid": "^11.0.2",
|
"uuid": "^11.0.2",
|
||||||
"esbuild": "^0.24.0"
|
"vite": "^5.4.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,13 +5,20 @@ export type LogWithEnv = {
|
|||||||
ScreenWidth?: number;
|
ScreenWidth?: number;
|
||||||
};
|
};
|
||||||
export type LogWithError = {
|
export type LogWithError = {
|
||||||
Type: "error"|"event"|"resources"|'click'|'historyChange'|'hashChange'|'onloadTime';
|
Type: "error"|"event"|"resources"|'click';
|
||||||
EventType: string;
|
EventType: string;
|
||||||
Path:string;
|
Path:string;
|
||||||
Message?: string;
|
Message?: string;
|
||||||
Stack?: string;
|
Stack?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ISlow = {
|
||||||
|
Type: "onloadTime"
|
||||||
|
|
||||||
|
Path:string;
|
||||||
|
Time: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// 扩展必须实现的接口
|
// 扩展必须实现的接口
|
||||||
export interface IErrorEvent {
|
export interface IErrorEvent {
|
||||||
@@ -23,4 +30,4 @@ export interface IErrorEvent {
|
|||||||
listen(callback: ListenCallbackFn): void;
|
listen(callback: ListenCallbackFn): void;
|
||||||
unListen(): void;
|
unListen(): void;
|
||||||
}
|
}
|
||||||
export type ListenCallbackFn = (params: LogWithError) => void;
|
export type ListenCallbackFn = (params: LogWithError|ISlow) => void;
|
||||||
|
21
x_err_sdk/vite.config.js
Normal file
21
x_err_sdk/vite.config.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { defineConfig, loadEnv } from 'vite'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: 'web/index.ts', // 库的入口文件
|
||||||
|
name: 'XErr', // 库的名称
|
||||||
|
fileName: (format) => `web/XErr.${format}.js`, // 输出文件名
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
// 外部化处理不想打包进库的依赖
|
||||||
|
// external: ['vue'],
|
||||||
|
output: {
|
||||||
|
globals: {
|
||||||
|
// vue: 'Vue'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@@ -1,5 +1,5 @@
|
|||||||
import { v1 as uuid_v1 } from "uuid";
|
import { v1 as uuid_v1 } from "uuid";
|
||||||
import type { LogWithError, IErrorEvent, LogWithEnv } from "../types";
|
import type { LogWithError, IErrorEvent,ISlow, LogWithEnv } from "../types";
|
||||||
|
|
||||||
type Uid = string | number;
|
type Uid = string | number;
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ type Props = {
|
|||||||
Uid?: Uid; //用户标识
|
Uid?: Uid; //用户标识
|
||||||
};
|
};
|
||||||
|
|
||||||
class XLog {
|
class Base {
|
||||||
private Dns: string = "";
|
private Dns: string = "";
|
||||||
private client_id: string = "";
|
private client_id: string = "";
|
||||||
private Pid: string = "";
|
private Pid: string = "";
|
||||||
@@ -38,17 +38,23 @@ class XLog {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (props.Uid) {
|
if (props.Uid) {
|
||||||
this.Uid = props.Uid;
|
this.Uid = String(props.Uid);
|
||||||
}
|
}
|
||||||
this.setClientID();
|
this.setClientID();
|
||||||
this.SetUid();
|
this.SetUid();
|
||||||
this.getLocalMessage();
|
this.getLocalMessage();
|
||||||
|
|
||||||
// 监听错误
|
|
||||||
platform.listen((params: LogWithError) => {
|
|
||||||
console.log("listenCallback", params);
|
|
||||||
|
|
||||||
|
// 监听错误
|
||||||
|
platform.listen((params: LogWithError|ISlow) => {
|
||||||
|
console.log("listenCallback", params);
|
||||||
|
if(params.Type=='onloadTime'){
|
||||||
|
let slow=params as ISlow;
|
||||||
|
this.uploadSlow(slow);
|
||||||
|
}else{
|
||||||
this.Push(params);
|
this.Push(params);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.timer = setInterval(() => {
|
this.timer = setInterval(() => {
|
||||||
@@ -59,8 +65,8 @@ class XLog {
|
|||||||
// 设置用户id
|
// 设置用户id
|
||||||
public SetUid(uid?: Uid) {
|
public SetUid(uid?: Uid) {
|
||||||
if (uid) {
|
if (uid) {
|
||||||
this.Uid = uid;
|
this.Uid =String(uid) ;
|
||||||
this.platform?.setCache("x_err_uid", uid);
|
this.platform?.setCache("x_err_uid", this.Uid);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const u_id = this.platform?.getCache("x_err_uid");
|
const u_id = this.platform?.getCache("x_err_uid");
|
||||||
@@ -127,6 +133,23 @@ class XLog {
|
|||||||
});
|
});
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
|
public uploadSlow=(envInfo: ISlow) =>{
|
||||||
|
if (!this.Dns) return; //未设置Dns服务器不上传
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.platform
|
||||||
|
?.upload(this.Dns + `/admin/monitor_slow/add`, {
|
||||||
|
ProjectKey: this.Pid,
|
||||||
|
ClientId: this.client_id,
|
||||||
|
UserId: this.Uid,
|
||||||
|
Path: envInfo.Path,
|
||||||
|
Time: envInfo.Time,
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
// 上传失败
|
||||||
|
});
|
||||||
|
} catch (error) {}
|
||||||
|
}
|
||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
public upload() {
|
public upload() {
|
||||||
@@ -149,4 +172,4 @@ class XLog {
|
|||||||
this.platform?.unListen();
|
this.platform?.unListen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default XLog;
|
export default Base;
|
@@ -1,6 +1,4 @@
|
|||||||
import XErr from "./err-entry"
|
import Base from "./base";
|
||||||
import XErrWeb from "./err-implement"
|
import Web from "./web";
|
||||||
|
|
||||||
|
|
||||||
export {XErr,XErrWeb}
|
|
||||||
|
|
||||||
|
export { Base, Web };
|
@@ -2,18 +2,18 @@ import type {
|
|||||||
LogWithError,
|
LogWithError,
|
||||||
LogWithEnv,
|
LogWithEnv,
|
||||||
ListenCallbackFn,
|
ListenCallbackFn,
|
||||||
IErrorEvent,
|
IErrorEvent,ISlow
|
||||||
} from "../types";
|
} from "../types";
|
||||||
|
|
||||||
interface LoggerProps {
|
interface LoggerProps {
|
||||||
// timeout:number
|
// timeout:number
|
||||||
onloadTimeOut?: number;
|
onloadTimeOut?: number;
|
||||||
}
|
}
|
||||||
class Logger implements IErrorEvent {
|
class Web implements IErrorEvent {
|
||||||
props: LoggerProps;
|
props: LoggerProps;
|
||||||
constructor(props?: LoggerProps) {
|
constructor(props?: LoggerProps) {
|
||||||
this.props = {
|
this.props = {
|
||||||
onloadTimeOut: 3000,
|
onloadTimeOut: 5000,
|
||||||
...props,
|
...props,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ class Logger implements IErrorEvent {
|
|||||||
}
|
}
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
private callback(err: LogWithError): void {}
|
private callback(err: LogWithError|ISlow): void {}
|
||||||
private listenError = (err: any) => {
|
private listenError = (err: any) => {
|
||||||
console.error([err]);
|
console.error([err]);
|
||||||
let target = err.target;
|
let target = err.target;
|
||||||
@@ -117,46 +117,8 @@ class Logger implements IErrorEvent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// private listenClick = (e: Event) => {
|
|
||||||
// let target = e.target as HTMLElement;
|
|
||||||
// let tagName = target?.localName;
|
|
||||||
// let name = [tagName];
|
|
||||||
// if (target.id) {
|
|
||||||
// name.push("#" + target.id);
|
|
||||||
// }
|
|
||||||
// target.classList.forEach((item) => {
|
|
||||||
// name.push("." + item);
|
|
||||||
// });
|
|
||||||
// if (target.innerText) {
|
|
||||||
// name.push(":" + target.innerText.slice(0, 20));
|
|
||||||
// }
|
|
||||||
// this.callback({
|
|
||||||
// Type: "click",
|
|
||||||
// EventType: "click",
|
|
||||||
// Path: window.location.href,
|
|
||||||
// Message: name.join(""),
|
|
||||||
// Stack: "",
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
// private listenHistoryRouterChange = () => {
|
|
||||||
// this.callback({
|
|
||||||
// Type: "historyChange",
|
|
||||||
// EventType: "popstate",
|
|
||||||
// Path: window.location.href,
|
|
||||||
// Message: "",
|
|
||||||
// Stack: "",
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
// // 监听hash
|
|
||||||
// private listenHashRouterChange = () => {
|
|
||||||
// this.callback({
|
|
||||||
// Type: "hashChange",
|
|
||||||
// EventType: "hashChange",
|
|
||||||
// Path: window.location.href,
|
|
||||||
// Message: "",
|
|
||||||
// Stack: "",
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
private handleStack(stack: string): string {
|
private handleStack(stack: string): string {
|
||||||
let newStack: string[] = [];
|
let newStack: string[] = [];
|
||||||
if (stack) {
|
if (stack) {
|
||||||
@@ -186,10 +148,8 @@ class Logger implements IErrorEvent {
|
|||||||
// 页面加载时间5s以上
|
// 页面加载时间5s以上
|
||||||
this.callback({
|
this.callback({
|
||||||
Type: "onloadTime",
|
Type: "onloadTime",
|
||||||
EventType: "onloadTime",
|
|
||||||
Path: window.location.href,
|
Path: window.location.href,
|
||||||
Message: "时间:" + parseFloat(onloadTime.toFixed(2)) + "ms",
|
Time:onloadTime
|
||||||
Stack: "",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,4 +176,4 @@ class Logger implements IErrorEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Logger;
|
export default Web;
|
Reference in New Issue
Block a user