Merge branch 'dev'

This commit is contained in:
xiangheng
2024-11-08 17:45:58 +08:00
90 changed files with 8810 additions and 4415 deletions

View File

@@ -13,6 +13,21 @@
padding: 0;
}
</style>
<script src="/XErr.umd.js"></script>
<script>
const xErr = new XErr.Base(
{
Dns: `${location.origin}/api`,
Pid: 'e19e3be20de94f49b68fafb4c30668bc',
Uid: ''
},
new XErr.Web({
onloadTimeOut: 5000
})
)
xErr.SetUid(2) //设置用户ID
</script>
<link rel="stylesheet" href="/src/styles/loading.css" />
</head>
<body>

3
admin/public/XErr.umd.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,11 @@ export type type_monitor_client = {
UserId?: string
Os?: string
Browser?: string
Country?: string
Province?: string
City?: string
Operator?: string
Ip?: string
Width?: number
Height?: number
Ua?: string
@@ -26,14 +30,16 @@ export type type_monitor_client_query = {
UserId?: string
Os?: string
Browser?: string
Country?: string
Province?: string
City?: string
Operator?: string
Ip?: string
Width?: number
Height?: number
Ua?: string
CreateTimeStart?: string
CreateTimeEnd?: string
ClientTimeStart?: string
ClientTimeEnd?: string
}
// 添加编辑
export type type_monitor_client_edit = {
@@ -43,7 +49,11 @@ export type type_monitor_client_edit = {
UserId?: string
Os?: string
Browser?: string
Country?: string
Province?: string
City?: string
Operator?: string
Ip?: string
Width?: number
Height?: number
Ua?: string

View File

@@ -0,0 +1,77 @@
import request from '@/utils/request'
import type { Pages } from '@/utils/request'
import config from '@/config'
import queryString from 'query-string'
import { getToken } from '@/utils/auth'
import { clearEmpty } from '@/utils/util'
export type type_monitor_slow = {
Id?: number
ProjectKey?: string
ClientId?: string
UserId?: string
Path?: string
Time?: number
CreateTime?: string
}
// 查询
export type type_monitor_slow_query = {
ProjectKey?: string
ClientId?: string
UserId?: string
Path?: string
Time?: number
CreateTimeStart?: string
CreateTimeEnd?: string
}
// 添加编辑
export type type_monitor_slow_edit = {
Id?: number
ProjectKey?: string
ClientId?: string
UserId?: string
Path?: string
Time?: number
}
// 监控-错误列列表
export function monitor_slow_list(params?: type_monitor_slow_query) {
return request.get<Pages<type_monitor_slow>>({ url: '/monitor_slow/list', params: clearEmpty(params) })
}
// 监控-错误列列表-所有
export function monitor_slow_list_all(params?: type_monitor_slow_query) {
return request.get<type_monitor_slow[]>({ url: '/monitor_slow/listAll', params: clearEmpty(params) })
}
// 监控-错误列详情
export function monitor_slow_detail(Id: number | string) {
return request.get<type_monitor_slow>({ url: '/monitor_slow/detail', params: { Id } })
}
// 监控-错误列新增
export function monitor_slow_add(data: type_monitor_slow_edit) {
return request.post<null>({ url: '/monitor_slow/add', data })
}
// 监控-错误列编辑
export function monitor_slow_edit(data: type_monitor_slow_edit) {
return request.post<null>({ url: '/monitor_slow/edit', data })
}
// 监控-错误列删除
export function monitor_slow_delete(Id: number | string) {
return request.post<null>({ url: '/monitor_slow/del', data: { Id } })
}
// 监控-错误列删除-批量
export function monitor_slow_delete_batch(data: { Ids: string }) {
return request.post<null>({ url: '/monitor_slow/delBatch', data })
}
// 监控-错误列导入
export const monitor_slow_import_file = '/monitor_slow/ImportFile'
// 监控-错误列导出
export function monitor_slow_export_file(params: any) {
return (window.location.href =`${config.baseUrl}${config.urlPrefix}/monitor_slow/ExportFile?token=${getToken()}&` + queryString.stringify(clearEmpty(params)))
}

View File

@@ -1,14 +1,12 @@
<template>
<div>
<template v-for="(item, index) in getOptions" :key="index">
<span :style="{ color: item.color }"
>{{ index != 0 ? '、' : '' }}{{ item[props.labelKey] }}</span
>
</template>
</div>
<template v-for="(item, index) in getOptions" :key="index">
<span :style="{ color: item.color }"
>{{ index != 0 ? '、' : '' }}{{ item[props.labelKey] }}</span
>
</template>
</template>
<script lang="ts" setup>
import { computed, withDefaults } from 'vue'
import { computed } from 'vue'
defineOptions({
name: 'dict-value'
})

View File

@@ -29,7 +29,7 @@ import type { IEditorConfig, IToolbarConfig } from '@wangeditor/editor'
import MaterialPicker from '@/components/material/picker.vue'
import { addUnit } from '@/utils/util'
import { withDefaults, computed, shallowRef, ref, onBeforeUnmount } from 'vue'
import { computed, shallowRef, ref, onBeforeUnmount } from 'vue'
import type { CSSProperties } from 'vue'
const props = withDefaults(

View File

@@ -0,0 +1,26 @@
<template>
<div class="ov w-[100%]">
<highlightjs autodetect :code="code" :language="lang" />
</div>
</template>
<script lang="ts" setup>
import 'highlight.js/styles/monokai.min.css'
import hljs from 'highlight.js/lib/common'
import javascript from 'highlight.js/lib/languages/javascript'
import go from 'highlight.js/lib/languages/go'
hljs.registerLanguage('javascript', javascript)
hljs.registerLanguage('go', go)
import hljsVuePlugin from '@highlightjs/vue-plugin'
const highlightjs = hljsVuePlugin.component
interface Props {
code: string
lang: 'javascript' | 'go'
}
withDefaults(defineProps<Props>(), {
code: '',
lang: 'javascript'
})
</script>

View File

@@ -77,7 +77,7 @@
</template>
<script lang="ts" setup>
import { ref, withDefaults } from 'vue'
import { ref } from 'vue'
import { computed, nextTick, onMounted, reactive, shallowRef, watch } from 'vue'
import { useEventListener } from '@vueuse/core'
import { ElInput } from 'element-plus'

View File

@@ -11,6 +11,19 @@ import ElementPlus from 'element-plus'
import VForm3 from 'vform3-builds' //引入VForm3库
// import { Base, Web } from '../../x_err_sdk/web/index'
// const xErr = new Base(
// {
// Dns: `${location.origin}/api`,
// Pid: 'e19e3be20de94f49b68fafb4c30668bc',
// Uid: ''
// },
// new Web({
// onloadTimeOut: 300
// })
// )
// xErr.SetUid(1) //设置用户ID
const app = createApp(App)
app.use(install)
app.use(ElementPlus)

View File

@@ -39,13 +39,13 @@
</template>
删除
</el-button>
<el-button
<!-- <el-button
v-perms="['admin:gen:genCode', 'admin:gen:downloadCode']"
:disabled="!selectData.length"
@click="handleGenerate(selectData)"
>
生成代码
</el-button>
</el-button> -->
</div>
<div class="mt-4">
<el-table

View File

@@ -35,11 +35,15 @@
<div class="flex-1 overflow-auto">
<div style="height: calc(100vh - 200px)">
<highlightjs
<highlight-code
:code="showItem.value"
lang="javascript"
></highlight-code>
<!-- <highlightjs
autodetect
:code="showItem.value"
language="javascript"
/>
/> -->
</div>
</div>
</div>
@@ -66,17 +70,17 @@ import { onMounted, ref, computed } from 'vue'
import feedback from '@/utils/feedback'
import useClipboard from 'vue-clipboard3'
import 'highlight.js/styles/monokai.min.css'
import hljs from 'highlight.js/lib/common'
import javascript from 'highlight.js/lib/languages/javascript'
import go from 'highlight.js/lib/languages/go'
// import 'highlight.js/styles/monokai.min.css'
// import hljs from 'highlight.js/lib/common'
// import javascript from 'highlight.js/lib/languages/javascript'
// import go from 'highlight.js/lib/languages/go'
// Then register the languages you need
hljs.registerLanguage('javascript', javascript)
hljs.registerLanguage('go', go)
// hljs.registerLanguage('javascript', javascript)
// hljs.registerLanguage('go', go)
import hljsVuePlugin from '@highlightjs/vue-plugin'
const highlightjs = hljsVuePlugin.component
// import hljsVuePlugin from '@highlightjs/vue-plugin'
// const highlightjs = hljsVuePlugin.component
const props = defineProps<{
modelValue: boolean

View File

@@ -0,0 +1,66 @@
<script setup lang="ts">
// import { onUnmounted } from 'vue'
// import { XErr, XErrWeb } from '../../../../x_err_sdk/web/index'
// // { XErr, XErrWeb }
// const xErr = new XErr(
// {
// Dns: 'http://localhost:5174/api',
// Pid: 'e19e3be20de94f49b68fafb4c30668bc',
// Uid: '10'
// },
// new XErrWeb()
// )
// onUnmounted(() => {
// xErr.unListen()
// })
defineProps<{ msg: string }>()
function error() {
throw new Error('主动抛error')
}
function promiseError() {
Promise.reject('主动抛promise1')
Promise.reject(new Error('主动抛promiseError2'))
}
function yufaError() {
// try {
setTimeout(() => {
a = 1
// a = 2;
}, 100)
// } catch (error) {
// console.log(error);
// }
}
function loadError() {
const img = new Image()
console.log(img)
img.src = 'http://a.cn'
document.body.appendChild(img)
}
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button class="a b" type="button" aa="11" @click="error">主动抛error</button>
<button class="a b" type="button" aa="11" @click="yufaError">语法错误</button>
<button class="a b c" id="abv" type="button" @click="promiseError">promise error</button>
<button type="button" @click="loadError">资源加载错误</button>
<!-- <img src="http://a.cn/a/b" alt="" srcset="" />
<link rel="stylesheet" href="http://a.cn/c/c/c" /> -->
</div>
</template>
<style scoped>
button {
color: #fff;
background-color: rgb(150, 149, 149);
border: 0;
padding: 6px 10px;
margin: 6px;
font-size: 14px;
line-height: 18px;
}
</style>

View File

@@ -69,7 +69,7 @@
</div>
</template>
<script lang="ts" setup>
import { shallowRef, reactive, defineOptions } from 'vue'
import { shallowRef, reactive } from 'vue'
import { flow_apply_detail } from '@/api/flow/flow_apply'
import { flow_history_list, flow_history_edit } from '@/api/flow/flow_history'
import type { type_flow_history } from '@/api/flow/flow_history'

View File

@@ -58,7 +58,7 @@
<script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router'
import { defineOptions, ref, shallowRef, reactive } from 'vue'
import { ref, shallowRef, reactive } from 'vue'
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { noticeDetail, setNoticeConfig } from '@/api/message'

View File

@@ -81,7 +81,12 @@ const formData = reactive({
UserId: null,
Os: null,
Browser: null,
Country: null,
Province: null,
City: null,
Operator: null,
Ip: null,
Width: null,
Height: null,
Ua: null,
@@ -117,27 +122,7 @@ const formRules = {
trigger: ['blur']
}
],
Os: [
{
required: true,
message: '请输入系统',
trigger: ['blur']
}
],
Browser: [
{
required: true,
message: '请输入浏览器',
trigger: ['blur']
}
],
City: [
{
required: true,
message: '请输入城市',
trigger: ['blur']
}
],
Width: [
{
required: true,
@@ -152,13 +137,7 @@ const formRules = {
trigger: ['blur']
}
],
Ua: [
{
required: true,
message: '请输入ua记录',
trigger: ['blur']
}
],
ClientTime: [
{
required: true,

View File

@@ -6,7 +6,7 @@
class="mb-[-16px]"
:model="queryParams"
:inline="true"
label-width="70px"
label-width="90px"
label-position="left"
>
<el-form-item label="项目" prop="ProjectKey" class="w-[280px]">
@@ -20,9 +20,9 @@
/>
</el-select>
</el-form-item>
<el-form-item label="客户端id" prop="ClientId" class="w-[280px]">
<!-- <el-form-item label="客户端id" prop="ClientId" class="w-[280px]">
<el-input v-model="queryParams.ClientId" />
</el-form-item>
</el-form-item> -->
<el-form-item label="用户id" prop="UserId" class="w-[280px]">
<el-input v-model="queryParams.UserId" />
</el-form-item>
@@ -32,13 +32,25 @@
<el-form-item label="浏览器" prop="Browser" class="w-[280px]">
<el-input v-model="queryParams.Browser" />
</el-form-item>
<el-form-item label="国家" prop="Country" class="w-[280px]">
<el-input v-model="queryParams.Country" />
</el-form-item>
<el-form-item label="省份" prop="Province" class="w-[280px]">
<el-input v-model="queryParams.Province" />
</el-form-item>
<el-form-item label="城市" prop="City" class="w-[280px]">
<el-input v-model="queryParams.City" />
</el-form-item>
<el-form-item label="ua记录" prop="Ua" class="w-[280px]">
<el-input v-model="queryParams.Ua" />
<el-form-item label="电信运营商" prop="Operator" class="w-[280px]">
<el-input v-model="queryParams.Operator" />
</el-form-item>
<el-form-item label="创建时间" prop="CreateTime" class="w-[280px]">
<el-form-item label="ip" prop="Ip" class="w-[280px]">
<el-input v-model="queryParams.Ip" />
</el-form-item>
<!-- <el-form-item label="ua记录" prop="Ua" class="w-[280px]">
<el-input v-model="queryParams.Ua" />
</el-form-item> -->
<el-form-item label="创建时间" prop="CreateTime" class="w-[425px]">
<daterange-picker
v-model:startTime="queryParams.CreateTimeStart"
v-model:endTime="queryParams.CreateTimeEnd"
@@ -116,15 +128,56 @@
/>
</template>
</el-table-column>
<el-table-column label="客户端id" prop="ClientId" min-width="130" />
<el-table-column label="用户id" prop="UserId" min-width="130" />
<el-table-column label="系统" prop="Os" min-width="130" />
<el-table-column label="浏览器" prop="Browser" min-width="130" />
<el-table-column label="城市" prop="City" min-width="130" />
<el-table-column label="屏幕" prop="Width" min-width="130" />
<el-table-column label="屏幕高度" prop="Height" min-width="130" />
<el-table-column label="ua记录" prop="Ua" min-width="130" />
<el-table-column label="创建时间" prop="CreateTime" min-width="130" />
<!-- <el-table-column label="客户端id" prop="ClientId" min-width="130" /> -->
<el-table-column label="用户id" prop="UserId">
<template #default="{ row }">
<el-popover
placement="top-start"
:width="500"
trigger="hover"
:content="row.ClientId"
>
<template #reference>
<el-link type="primary">{{ row.UserId }}</el-link>
</template>
<div> ID {{ row.UserId }}</div>
<div>客户端ID{{ row.ClientId }}</div>
</el-popover>
</template>
</el-table-column>
<el-table-column label="浏览器" prop="Browser" min-width="150">
<template #default="{ row }">
<el-popover
placement="top-start"
title="浏览器ua"
:width="500"
trigger="hover"
:content="row.Ua"
>
<template #reference>
<el-link type="primary">{{ row.Os }} / {{ row.Browser }}</el-link>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column label="IP" prop="Ip" />
<el-table-column label="区域">
<template #default="{ row }">
{{ row.Country }}{{ row.Province }}{{ row.City }}
</template>
</el-table-column>
<!-- <el-table-column label="省份" prop="Province" />
<el-table-column label="城市" prop="City" /> -->
<el-table-column label="运营商" prop="Operator" />
<el-table-column label="屏幕" prop="Width">
<template #default="{ row }"> {{ row.Width }} * {{ row.Height }} </template>
</el-table-column>
<!-- <el-table-column label="屏幕高度" prop="Height" min-width="130" /> -->
<!-- <el-table-column label="ua记录" prop="Ua" min-width="380" /> -->
<el-table-column label="创建时间" prop="CreateTime" min-width="140" />
<el-table-column label="操作" width="80" fixed="right">
<template #default="{ row }">
@@ -182,14 +235,16 @@ const queryParams = reactive<type_monitor_client_query>({
UserId: null,
Os: null,
Browser: null,
Country: null,
Province: null,
City: null,
Operator: null,
Ip: null,
Width: null,
Height: null,
Ua: null,
CreateTimeStart: null,
CreateTimeEnd: null,
ClientTimeStart: null,
ClientTimeEnd: null
CreateTimeEnd: null
})
const { pager, getLists, resetPage, resetParams } = usePaging<type_monitor_client>({

View File

@@ -4,47 +4,47 @@
ref="popupRef"
:title="popupTitle"
:async="true"
width="90%"
width="98%"
:clickModalClose="true"
@confirm="handleSubmit"
@close="handleClose"
>
<el-row :gutter="20">
<el-col :span="12">
<el-row :gutter="10">
<el-col :xs="24" :md="14">
<el-card>
<template #header>
<div class="card-header">
<span>错误详情</span>
<span
>
<dict-value
:options="listAllData.monitor_project_listAll"
:value="formData.ProjectKey"
labelKey="ProjectName"
valueKey="ProjectKey"
/>错误详情</span
>
</div>
</template>
<el-form ref="formRef">
<el-form-item label="项目key" prop="ProjectKey">
<dict-value
:options="listAllData.monitor_project_listAll"
:value="formData.ProjectKey"
labelKey="ProjectName"
valueKey="ProjectKey"
/>
</el-form-item>
<!-- <el-form-item label="项目key" prop="ProjectKey"> </el-form-item> -->
<el-form-item label="事件类型" prop="EventType">
<el-form-item label="事件类型" prop="EventType">
{{ formData.EventType }}
</el-form-item>
<el-form-item label="URL地址" prop="Path">
<el-form-item label="URL地址" prop="Path">
{{ formData.Path }}
</el-form-item>
<el-form-item label="错误消息" prop="Message">
<el-form-item label="错误消息" prop="Message">
{{ formData.Message }}
</el-form-item>
<el-form-item label="错误堆栈" prop="Stack">
<el-form-item label="" prop="Stack">
{{ formData.Stack }}
</el-form-item>
</el-form>
<!-- <template #footer>Footer content</template> -->
</el-card>
</el-col>
<el-col :span="12">
<el-col :xs="24" :md="10">
<el-card>
<template #header>
<div class="card-header">
@@ -61,24 +61,31 @@
>
<template #title>
<div class="flex-1 text-left">
{{ user.UserId }}
{{ user.City }} {{ user.Browser }}{{ user.Ip }}
</div>
<span class="">
<span>
{{ user.CreateTime }}
</span>
</template>
<el-descriptions border>
<el-descriptions-item label="城市:">{{
user.City
<el-descriptions border :column="2">
<el-descriptions-item label="省市区">
{{ user.Country }}{{ user.Province }}{{ user.City }}
</el-descriptions-item>
<el-descriptions-item label="浏览器">
{{ user.Os }}/{{ user.Browser }}
</el-descriptions-item>
<el-descriptions-item label="网络">{{
user.Operator
}}</el-descriptions-item>
<el-descriptions-item label="IP">{{
user.Ip
}}</el-descriptions-item>
<el-descriptions-item label="OS">{{
user.Os
<el-descriptions-item label="业务ID">{{
user.UserId
}}</el-descriptions-item>
<el-descriptions-item label="屏幕尺寸:">
<el-tag size="small"
>{{ user.Width }}*{{ user.Height }}</el-tag
>
<el-descriptions-item label="屏幕">
{{ user.Width }}*{{ user.Height }}
</el-descriptions-item>
<el-descriptions-item label="userAgent">
{{ user.Ua }}

View File

@@ -98,8 +98,7 @@ const formData = reactive({
Path: null,
Message: null,
Stack: null,
Md5: null,
ClientTime: null
Md5: null
})
const formRules = {

View File

@@ -7,7 +7,7 @@
:model="queryParams"
:inline="true"
label-width="70px"
label-position="left"
label-position="right"
>
<el-form-item label="项目" prop="ProjectKey" class="w-[280px]">
<el-select v-model="queryParams.ProjectKey" clearable>
@@ -38,42 +38,6 @@
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<div class="text-right">
<el-button
v-perms="['admin:monitor_error:add']"
type="primary"
@click="handleAdd()"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
<upload
v-perms="['admin:monitor_error:ImportFile']"
class="ml-3 mr-3"
:url="monitor_error_import_file"
:data="{ cid: 0 }"
type="file"
:show-progress="true"
@change="resetPage"
>
<el-button type="primary">
<template #icon>
<icon name="el-icon-Upload" />
</template>
导入
</el-button>
</upload>
<el-button
v-perms="['admin:monitor_error:ExportFile']"
type="primary"
@click="exportFile"
>
<template #icon>
<icon name="el-icon-Download" />
</template>
导出
</el-button>
<el-button
v-perms="['admin:monitor_error:delBatch']"
type="danger"
@@ -92,7 +56,7 @@
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column label="项目" prop="ProjectKey" min-width="100">
<el-table-column label="项目" prop="ProjectKey" min-width="80">
<template #default="{ row }">
<dict-value
:options="listAllData.monitor_project_listAll"
@@ -102,13 +66,13 @@
/>
</template>
</el-table-column>
<el-table-column label="事件类型" prop="EventType" min-width="130" />
<el-table-column label="事件类型" prop="EventType" width="130" />
<el-table-column label="URL地址" prop="Path" min-width="130" />
<el-table-column label="错误消息" prop="Message" min-width="130" />
<el-table-column label="错误堆栈" prop="Stack" min-width="130" />
<el-table-column label="md5" prop="Md5" min-width="130" />
<el-table-column label="创建时间" prop="CreateTime" min-width="130" />
<el-table-column label="更新时间" prop="ClientTime" min-width="130" />
<!-- <el-table-column label="md5" prop="Md5" min-width="130" /> -->
<el-table-column label="创建时间" prop="CreateTime" width="170" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button
@@ -154,9 +118,7 @@ import { ref, reactive, shallowRef, nextTick } from 'vue'
import {
monitor_error_delete,
monitor_error_delete_batch,
monitor_error_list,
monitor_error_import_file,
monitor_error_export_file
monitor_error_list
} from '@/api/monitor/error'
import type { type_monitor_error, type_monitor_error_query } from '@/api/monitor/error'
@@ -197,11 +159,6 @@ const { listAllData } = useListAllData<{
})
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add')
}
const multipleSelection = ref<type_monitor_error[]>([])
const handleSelectionChange = (val: type_monitor_error[]) => {
@@ -240,11 +197,5 @@ const deleteBatch = async () => {
} catch (error) {}
}
const exportFile = async () => {
try {
await feedback.confirm('确定要导出?')
await monitor_error_export_file(queryParams)
} catch (error) {}
}
getLists()
</script>

View File

@@ -4,14 +4,14 @@
ref="popupRef"
:title="popupTitle"
:async="true"
width="550px"
width="700px"
:clickModalClose="true"
@confirm="handleSubmit"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="84px" :rules="formRules">
<el-form-item label="项目uuid" prop="ProjectKey">
<el-input v-model="formData.ProjectKey" placeholder="请输入项目uuid" />
<el-form-item label="项目uuid" prop="ProjectKey" v-if="mode === 'edit'">
{{ formData.ProjectKey }}
</el-form-item>
<el-form-item label="项目名称" prop="ProjectName">
<el-input v-model="formData.ProjectName" placeholder="请输入项目名称" />
@@ -48,6 +48,9 @@
/>
</el-select>
</el-form-item>
<el-form-item label="使用SDK" v-if="mode == 'edit'">
<highlight-code :code="code" lang="javascript"></highlight-code>
</el-form-item>
</el-form>
</popup>
</div>
@@ -73,6 +76,7 @@ defineProps({
default: () => ({})
}
})
const emit = defineEmits(['success', 'close'])
const formRef = shallowRef<FormInstance>()
const popupRef = shallowRef<InstanceType<typeof Popup>>()
@@ -88,7 +92,19 @@ const formData = reactive({
ProjectType: null,
Status: null
})
const code = computed(() => {
return `import { XErr, XErrWeb } from '../../x_err_sdk/web/index'
new XErr(
{
Dns: '${location.origin}/api',
Pid: '${formData.ProjectKey}',
Uid: ''
},
new XErrWeb({
onloadTimeOut: 3000
})
)`
})
const formRules = {
Id: [
{

View File

@@ -37,13 +37,13 @@
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="CreateTime" class="w-[280px]">
<el-form-item label="创建时间" prop="CreateTime" class="w-[430px]">
<daterange-picker
v-model:startTime="queryParams.CreateTimeStart"
v-model:endTime="queryParams.CreateTimeEnd"
/>
</el-form-item>
<el-form-item label="更新时间" prop="UpdateTime" class="w-[280px]">
<el-form-item label="更新时间" prop="UpdateTime" class="w-[420px]">
<daterange-picker
v-model:startTime="queryParams.UpdateTimeStart"
v-model:endTime="queryParams.UpdateTimeEnd"

View File

@@ -0,0 +1,158 @@
<template>
<div class="edit-popup">
<popup
ref="popupRef"
:title="popupTitle"
:async="true"
width="550px"
:clickModalClose="true"
@confirm="handleSubmit"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="84px" :rules="formRules">
<el-form-item label="项目key" prop="ProjectKey">
<el-input v-model="formData.ProjectKey" placeholder="请输入项目key" />
</el-form-item>
<el-form-item label="sdk生成的客户端id" prop="ClientId">
<el-input v-model="formData.ClientId" placeholder="请输入sdk生成的客户端id" />
</el-form-item>
<el-form-item label="用户id" prop="UserId">
<el-input v-model="formData.UserId" placeholder="请输入用户id" />
</el-form-item>
<el-form-item label="URL地址" prop="Path">
<el-input
v-model="formData.Path"
placeholder="请输入URL地址"
type="textarea"
:autosize="{ minRows: 4, maxRows: 6 }"
/>
</el-form-item>
<el-form-item label="时间" prop="Time">
<el-input v-model="formData.Time" type="number" placeholder="请输入时间" />
</el-form-item>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import { monitor_slow_edit, monitor_slow_add, monitor_slow_detail } from '@/api/monitor/slow'
import Popup from '@/components/popup/index.vue'
import feedback from '@/utils/feedback'
import { ref, shallowRef, computed, reactive } from 'vue'
import type { PropType } from 'vue'
defineProps({
dictData: {
type: Object as PropType<Record<string, any[]>>,
default: () => ({})
},
listAllData:{
type: Object as PropType<Record<string, any[]>>,
default: () => ({})
}
})
const emit = defineEmits(['success', 'close'])
const formRef = shallowRef<FormInstance>()
const popupRef = shallowRef<InstanceType<typeof Popup>>()
const mode = ref('add')
const popupTitle = computed(() => {
return mode.value == 'edit' ? '编辑监控-错误列' : '新增监控-错误列'
})
const formData = reactive({
Id: null,
ProjectKey: null,
ClientId: null,
UserId: null,
Path: null,
Time: null,
})
const formRules = {
Id: [
{
required: true,
message: '请输入错误id',
trigger: ['blur']
}
],
ProjectKey: [
{
required: true,
message: '请输入项目key',
trigger: ['blur']
}
],
ClientId: [
{
required: true,
message: '请输入sdk生成的客户端id',
trigger: ['blur']
}
],
UserId: [
{
required: true,
message: '请输入用户id',
trigger: ['blur']
}
],
Path: [
{
required: true,
message: '请输入URL地址',
trigger: ['blur']
}
],
Time: [
{
required: true,
message: '请输入时间',
trigger: ['blur']
}
],
}
const handleSubmit = async () => {
try {
await formRef.value?.validate()
const data: any = { ...formData }
mode.value == 'edit' ? await monitor_slow_edit(data) : await monitor_slow_add(data)
popupRef.value?.close()
feedback.msgSuccess('操作成功')
emit('success')
} catch (error) {}
}
const open = (type = 'add') => {
mode.value = type
popupRef.value?.open()
}
const setFormData = async (data: Record<string, any>) => {
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key]
}
}
}
const getDetail = async (row: Record<string, any>) => {
try {
const data = await monitor_slow_detail(row.Id)
setFormData(data)
} catch (error) {}
}
const handleClose = () => {
emit('close')
}
defineExpose({
open,
setFormData,
getDetail
})
</script>

View File

@@ -0,0 +1,202 @@
<template>
<div class="index-lists">
<el-card class="!border-none" shadow="never">
<el-form
ref="formRef"
class="mb-[-16px]"
:model="queryParams"
:inline="true"
label-width="70px"
label-position="left"
>
<el-form-item label="项目" prop="ProjectKey" class="w-[280px]">
<el-select v-model="queryParams.ProjectKey" clearable>
<el-option label="全部" value="" />
<el-option
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 label="用户id" prop="UserId" class="w-[280px]">
<el-input v-model="queryParams.UserId" />
</el-form-item>
<el-form-item label="创建时间" prop="CreateTime" class="w-[420px]">
<daterange-picker
v-model:startTime="queryParams.CreateTimeStart"
v-model:endTime="queryParams.CreateTimeEnd"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<div class="text-right">
<!-- <el-button v-perms="['admin:monitor_slow:add']" type="primary" @click="handleAdd()">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button> -->
<!-- <upload
v-perms="['admin:monitor_slow:ImportFile']"
class="ml-3 mr-3"
:url="monitor_slow_import_file"
:data="{ cid: 0 }"
type="file"
:show-progress="true"
@change="resetPage"
>
<el-button type="primary">
<template #icon>
<icon name="el-icon-Upload" />
</template>
导入
</el-button>
</upload> -->
<!-- <el-button
v-perms="['admin:monitor_slow:ExportFile']"
type="primary"
@click="exportFile"
>
<template #icon>
<icon name="el-icon-Download" />
</template>
导出
</el-button> -->
<el-button
v-perms="['admin:monitor_slow:delBatch']"
type="danger"
:disabled="!multipleSelection.length"
@click="deleteBatch"
>
批量删除
</el-button>
</div>
<el-table
class="mt-4"
size="large"
v-loading="pager.loading"
:data="pager.lists"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column label="项目" prop="ProjectKey" width="150">
<template #default="{ row }">
<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']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button> -->
<el-button
v-perms="['admin:monitor_slow:del']"
type="danger"
link
@click="handleDelete(row.Id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, shallowRef } from 'vue'
import {
monitor_slow_delete,
monitor_slow_delete_batch,
monitor_slow_list
} 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 feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
defineOptions({
name: 'monitor_slow'
})
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const queryParams = reactive<type_monitor_slow_query>({
ProjectKey: null,
ClientId: null,
UserId: null,
Path: null,
Time: null,
CreateTimeStart: null,
CreateTimeEnd: null
})
const { pager, getLists, resetPage, resetParams } = usePaging<type_monitor_slow>({
fetchFun: monitor_slow_list,
params: queryParams
})
const { listAllData } = useListAllData<{
monitor_project_listAll: any[]
}>({
monitor_project_listAll: '/monitor_project/listAll'
})
const multipleSelection = ref<type_monitor_slow[]>([])
const handleSelectionChange = (val: type_monitor_slow[]) => {
console.log(val)
multipleSelection.value = val
}
const handleDelete = async (Id: number) => {
try {
await feedback.confirm('确定要删除?')
await monitor_slow_delete(Id)
feedback.msgSuccess('删除成功')
getLists()
} catch (error) {}
}
// 批量删除
const deleteBatch = async () => {
if (multipleSelection.value.length === 0) {
feedback.msgError('请选择要删除的数据')
return
}
try {
await feedback.confirm('确定要删除?')
await monitor_slow_delete_batch({
Ids: multipleSelection.value.map((item) => item.Id).join(',')
})
feedback.msgSuccess('删除成功')
getLists()
} catch (error) {}
}
getLists()
</script>

View File

@@ -23,10 +23,12 @@ export default ({ mode }) => {
// 依赖预构建,避免开发刷新
include: ['@wangeditor/editor-for-vue', 'vuedraggable', 'vue-echarts', 'crypto-js']
},
base: '/',
build: {
sourcemap: true,
rollupOptions: {
external: ['XErr'],
output: {
manualChunks: {
vue: ['vue'],

View File

@@ -4,8 +4,13 @@
## 前端页面使用history模式需要重定向
```nginx
location / {
index /index.html;
try_files $uri $uri/ /index.html;
}
# 找不到静态文件返回404
location ~* \.(?:html|css|js|png|jpg|jpeg|gif|webp|pdf|mp4|mp3|aac|ico|svg|woff|woff2|ttf|eot)$ {
try_files $uri =404;
}
```

View File

@@ -17,6 +17,9 @@
},
{
"path": ".workflow"
},
{
"path": "x_err_sdk"
}
],
"settings": {

View File

@@ -5,7 +5,7 @@ import (
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -58,7 +58,7 @@ func (service ArticleCollectService) List(page request.PageReq, listReq ArticleC
return
}
result := []ArticleCollectResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,

View File

@@ -8,6 +8,7 @@ import (
"x_admin/core/response"
"x_admin/model/common_model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -66,7 +67,7 @@ func (albSrv albumService) AlbumList(page request.PageReq, listReq CommonAlbumLi
return
}
albumResps := []CommonAlbumListResp{}
util.ConvertUtil.Copy(&albumResps, albums)
convert_util.Copy(&albumResps, albums)
// TODO: engine默认local
engine := "local"
for i := 0; i < len(albumResps); i++ {
@@ -134,7 +135,7 @@ func (albSrv albumService) AlbumAdd(addReq CommonAlbumAddReq) (res uint, e error
// core.Logger.Errorf("AlbumAdd Decode err: err=[%+v]", err)
// return response.SystemError
//}
util.ConvertUtil.Copy(&alb, addReq)
convert_util.Copy(&alb, addReq)
err := albSrv.db.Create(&alb).Error
if e = response.CheckErr(err, "Album添加失败"); e != nil {
return
@@ -173,14 +174,14 @@ func (albSrv albumService) CateList(listReq CommonCateListReq) (mapList []Common
return
}
cateResps := []CommonCateListResp{}
util.ConvertUtil.Copy(&cateResps, cates)
convert_util.Copy(&cateResps, cates)
return cateResps, nil
}
// CateAdd 分类新增
func (albSrv albumService) CateAdd(addReq CommonCateAddReq) (e error) {
var cate common_model.AlbumCate
util.ConvertUtil.Copy(&cate, addReq)
convert_util.Copy(&cate, addReq)
err := albSrv.db.Create(&cate).Error
e = response.CheckErr(err, "Cate添加失败")
return

View File

@@ -8,14 +8,6 @@ import (
)
func IndexRoute(rg *gin.RouterGroup) {
// db := core.GetDB()
// permSrv := system.NewSystemAuthPermService(db)
// roleSrv := system.NewSystemAuthRoleService(db, permSrv)
// adminSrv := system.NewSystemAuthAdminService(db, permSrv, roleSrv)
// service := system.NewSystemLoginService(db, adminSrv)
// authSrv := system.NewSystemAuthMenuService(db, permSrv)
// IndexService := NewIndexService()
handle := indexHandler{}
rg = rg.Group("/common", middleware.TokenAuth())

View File

@@ -10,15 +10,10 @@ import (
"gorm.io/gorm"
)
type IIndexService interface {
Console() (res map[string]interface{}, e error)
Config() (res map[string]interface{}, e error)
}
var Service = NewIndexService()
// NewIndexService 初始化
func NewIndexService() IIndexService {
func NewIndexService() *indexService {
db := core.GetDB()
return &indexService{db: db}
}
@@ -47,7 +42,7 @@ func (iSrv indexService) Console() (res map[string]interface{}, e error) {
}
// 今日数据
today := map[string]interface{}{
"time": "2022-08-11 15:08:29",
"time": util.NullTimeUtil.Now(),
"todayVisits": 10, // 访问量(人)
"totalVisits": 100, // 总访问量
"todaySales": 30, // 销售额(元)
@@ -65,7 +60,7 @@ func (iSrv indexService) Console() (res map[string]interface{}, e error) {
}
visitor := map[string]interface{}{
"date": date,
"list": []int{12, 13, 11, 5, 8, 22, 14, 9, 456, 62, 78, 12, 18, 22, 46},
"list": []int{12, 13, 11, 5, 100, 22, 14, 9, 456, 62, 78, 12, 18, 22, 46},
}
return map[string]interface{}{
"version": version,

View File

@@ -4,7 +4,7 @@ import (
"mime/multipart"
"x_admin/admin/common/album"
"x_admin/plugin"
"x_admin/util"
"x_admin/util/convert_util"
)
type IUploadService interface {
@@ -39,14 +39,14 @@ func (upSrv uploadService) uploadFile(file *multipart.FileHeader, folder string,
return
}
var addReq album.CommonAlbumAddReq
util.ConvertUtil.Copy(&addReq, upRes)
convert_util.Copy(&addReq, upRes)
addReq.Aid = aid
addReq.Cid = cid
var albumId uint
if albumId, e = album.Service.AlbumAdd(addReq); e != nil {
return
}
util.ConvertUtil.Copy(&res, addReq)
convert_util.Copy(&res, addReq)
res.ID = albumId
res.Path = upRes.Path
return res, nil

View File

@@ -8,6 +8,7 @@ import (
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -81,7 +82,7 @@ func (service flowApplyService) List(page request.PageReq, listReq FlowApplyList
return
}
result := []FlowApplyResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -100,7 +101,7 @@ func (service flowApplyService) Detail(id int) (res FlowApplyResp, e error) {
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
@@ -111,7 +112,7 @@ func (service flowApplyService) Add(addReq FlowApplyAddReq) (e error) {
if e = response.CheckErrDBNotRecord(err, "模板不存在!"); e != nil {
return
}
util.ConvertUtil.Copy(&obj, addReq)
convert_util.Copy(&obj, addReq)
// obj.FlowName = flow_template_resp.FlowName
obj.FlowGroup = flow_template_resp.FlowGroup
obj.FlowRemark = flow_template_resp.FlowRemark
@@ -136,7 +137,7 @@ func (service flowApplyService) Edit(editReq FlowApplyEditReq) (e error) {
return
}
// 更新
util.ConvertUtil.Copy(&obj, editReq)
convert_util.Copy(&obj, editReq)
err = service.db.Model(&obj).Updates(obj).Error
e = response.CheckErr(err, "编辑失败")
return

View File

@@ -14,6 +14,7 @@ import (
"x_admin/model"
"x_admin/model/system_model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -93,7 +94,7 @@ func (service flowHistoryService) List(page request.PageReq, listReq FlowHistory
return
}
list := []FlowHistoryResp{}
util.ConvertUtil.Copy(&list, modelList)
convert_util.Copy(&list, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -122,7 +123,7 @@ func (service flowHistoryService) ListAll(listReq FlowHistoryListReq) (res []Flo
if e = response.CheckErr(err, "获取列表失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, modelList)
convert_util.Copy(&res, modelList)
return res, nil
}
@@ -136,14 +137,14 @@ func (service flowHistoryService) Detail(id int) (res FlowHistoryResp, e error)
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
// Add 流程历史新增
func (service flowHistoryService) Add(addReq FlowHistoryAddReq) (e error) {
var obj model.FlowHistory
util.ConvertUtil.Copy(&obj, addReq)
convert_util.Copy(&obj, addReq)
err := service.db.Create(&obj).Error
e = response.CheckErr(err, "添加失败")
return
@@ -161,7 +162,7 @@ func (service flowHistoryService) Edit(editReq FlowHistoryEditReq) (e error) {
return
}
// 更新
util.ConvertUtil.Copy(&obj, editReq)
convert_util.Copy(&obj, editReq)
err = service.db.Model(&obj).Updates(obj).Error
e = response.CheckErr(err, "编辑失败")
return
@@ -422,7 +423,7 @@ func (service flowHistoryService) Back(back BackReq) (e error) {
}
var obj model.FlowApply
util.ConvertUtil.Copy(&obj, applyDetail)
convert_util.Copy(&obj, applyDetail)
obj.Status = 4
err = tx.Save(&obj).Error
if err != nil {

View File

@@ -5,7 +5,7 @@ import (
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -67,7 +67,7 @@ func (service flowTemplateService) List(page request.PageReq, listReq FlowTempla
return
}
result := []FlowTemplateResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -83,7 +83,7 @@ func (service flowTemplateService) ListAll() (res []FlowTemplateResp, e error) {
if e = response.CheckErr(err, "获取列表失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, modelList)
convert_util.Copy(&res, modelList)
return res, nil
}
@@ -97,14 +97,14 @@ func (service flowTemplateService) Detail(id int) (res FlowTemplateResp, e error
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
// Add 流程模板新增
func (service flowTemplateService) Add(addReq FlowTemplateAddReq) (e error) {
var obj model.FlowTemplate
util.ConvertUtil.Copy(&obj, addReq)
convert_util.Copy(&obj, addReq)
err := service.db.Create(&obj).Error
e = response.CheckErr(err, "添加失败")
return
@@ -122,7 +122,7 @@ func (service flowTemplateService) Edit(editReq FlowTemplateEditReq) (e error) {
return
}
// 更新
util.ConvertUtil.Copy(&obj, editReq)
convert_util.Copy(&obj, editReq)
err = service.db.Model(&obj).Updates(obj).Error
e = response.CheckErr(err, "编辑失败")
return

View File

@@ -9,6 +9,7 @@ import (
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model/gen_model"
"x_admin/util/convert_util"
"strings"
@@ -123,11 +124,11 @@ func (genSrv generateService) Detail(id uint) (res GenTableDetailResp, e error)
return
}
var base GenTableBaseResp
util.ConvertUtil.Copy(&base, genTb)
convert_util.Copy(&base, genTb)
var gen GenTableGenResp
util.ConvertUtil.Copy(&gen, genTb)
convert_util.Copy(&gen, genTb)
var colResp []GenColumnResp
util.ConvertUtil.Copy(&colResp, columns)
convert_util.Copy(&colResp, columns)
return GenTableDetailResp{
Base: base,
Gen: gen,
@@ -143,7 +144,7 @@ func (genSrv generateService) ImportTable(tableNames []string) (e error) {
return
}
var tables []gen_model.GenTable
util.ConvertUtil.Copy(&tables, dbTbs)
convert_util.Copy(&tables, dbTbs)
if len(tables) == 0 {
e = response.AssertArgumentError.SetMessage("表不存在!")
return
@@ -281,7 +282,7 @@ func (genSrv generateService) EditTable(editReq EditTableReq) (e error) {
if e = response.CheckErr(err, "查找数据失败"); e != nil {
return
}
util.ConvertUtil.Copy(&genTable, editReq)
convert_util.Copy(&genTable, editReq)
err = genSrv.db.Transaction(func(tx *gorm.DB) error {
genTable.SubTableName = strings.Replace(editReq.SubTableName, config.Config.DbTablePrefix, "", 1)
txErr := tx.Save(&genTable).Error
@@ -290,7 +291,7 @@ func (genSrv generateService) EditTable(editReq EditTableReq) (e error) {
}
for i := 0; i < len(editReq.Columns); i++ {
var col gen_model.GenTableColumn
util.ConvertUtil.Copy(&col, editReq.Columns[i])
convert_util.Copy(&col, editReq.Columns[i])
txErr = tx.Save(&col).Error
if te := response.CheckErr(txErr, "更新失败"); te != nil {
return te

View File

@@ -26,19 +26,17 @@ admin:{{{.ModuleName }}}:detail
admin:{{{.ModuleName }}}:ExportFile
admin:{{{.ModuleName }}}:ImportFile
// 列表-先添加菜单获取菜单id
// 列表
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, paths, component, is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'C', '{{{ .FunctionName }}}', '{{{nameToPath .ModuleName }}}/index', '{{{nameToPath .ModuleName }}}/index', 0, 1, 0, now(), now());
按钮-替换pid参数为菜单id
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'A', '{{{ .FunctionName }}}添加','admin:{{{ .ModuleName }}}:add', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'A', '{{{ .FunctionName }}}编辑','admin:{{{ .ModuleName }}}:edit', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'A', '{{{ .FunctionName }}}删除','admin:{{{ .ModuleName }}}:del', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'A', '{{{ .FunctionName }}}删除-批量','admin:{{{ .ModuleName }}}:delBatch', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'A', '{{{ .FunctionName }}}列表','admin:{{{ .ModuleName }}}:list', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'A', '{{{ .FunctionName }}}全部列表','admin:{{{ .ModuleName }}}:listAll', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'A', '{{{ .FunctionName }}}详情','admin:{{{ .ModuleName }}}:detail', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'A', '{{{ .FunctionName }}}导出excel','admin:{{{ .ModuleName }}}:ExportFile', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'A', '{{{ .FunctionName }}}导入excel','admin:{{{ .ModuleName }}}:ImportFile', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) SELECT id, 'A', '{{{ .FunctionName }}}添加','admin:{{{ .ModuleName }}}:add', 0, 1, 0, now(), now() FROM x_system_auth_menu WHERE component='{{{nameToPath .ModuleName }}}/index';
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) SELECT id, 'A', '{{{ .FunctionName }}}编辑','admin:{{{ .ModuleName }}}:edit', 0, 1, 0, now(), now() FROM x_system_auth_menu WHERE component='{{{nameToPath .ModuleName }}}/index';
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) SELECT id, 'A', '{{{ .FunctionName }}}删除','admin:{{{ .ModuleName }}}:del', 0, 1, 0, now(), now() FROM x_system_auth_menu WHERE component='{{{nameToPath .ModuleName }}}/index';
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) SELECT id, 'A', '{{{ .FunctionName }}}删除-批量','admin:{{{ .ModuleName }}}:delBatch', 0, 1, 0, now(), now() FROM x_system_auth_menu WHERE component='{{{nameToPath .ModuleName }}}/index';
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) SELECT id, 'A', '{{{ .FunctionName }}}列表','admin:{{{ .ModuleName }}}:list', 0, 1, 0, now(), now() FROM x_system_auth_menu WHERE component='{{{nameToPath .ModuleName }}}/index';
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) SELECT id, 'A', '{{{ .FunctionName }}}全部列表','admin:{{{ .ModuleName }}}:listAll', 0, 1, 0, now(), now() FROM x_system_auth_menu WHERE component='{{{nameToPath .ModuleName }}}/index';
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) SELECT id, 'A', '{{{ .FunctionName }}}详情','admin:{{{ .ModuleName }}}:detail', 0, 1, 0, now(), now() FROM x_system_auth_menu WHERE component='{{{nameToPath .ModuleName }}}/index';
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) SELECT id, 'A', '{{{ .FunctionName }}}导出excel','admin:{{{ .ModuleName }}}:ExportFile', 0, 1, 0, now(), now() FROM x_system_auth_menu WHERE component='{{{nameToPath .ModuleName }}}/index';
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) SELECT id, 'A', '{{{ .FunctionName }}}导入excel','admin:{{{ .ModuleName }}}:ImportFile', 0, 1, 0, now(), now() FROM x_system_auth_menu WHERE component='{{{nameToPath .ModuleName }}}/index';
*/

View File

@@ -7,6 +7,7 @@ import (
"x_admin/model"
"gorm.io/gorm"
"x_admin/util"
"x_admin/util/convert_util"
"x_admin/util/excel2"
)
@@ -82,7 +83,7 @@ func (service {{{ toCamelCase .EntityName }}}Service) List(page request.PageReq,
return
}
result := []{{{ toUpperCamelCase .EntityName }}}Resp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -100,7 +101,7 @@ func (service {{{ toCamelCase .EntityName }}}Service) ListAll(listReq {{{ toUppe
if e = response.CheckErr(err, "查询全部失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, modelList)
convert_util.Copy(&res, modelList)
return res, nil
}
@@ -125,14 +126,14 @@ func (service {{{ toCamelCase .EntityName }}}Service) Detail({{{ toUpperCamelCas
cacheUtil.SetCache(obj.{{{ toUpperCamelCase .PrimaryKey }}}, obj)
}
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
// Add {{{ .FunctionName }}}新增
func (service {{{ toCamelCase .EntityName }}}Service) Add(addReq {{{ toUpperCamelCase .EntityName }}}AddReq) (createId int,e error) {
var obj model.{{{ toUpperCamelCase .EntityName }}}
util.ConvertUtil.StructToStruct(addReq,&obj)
convert_util.StructToStruct(addReq,&obj)
err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err)
if e != nil {
@@ -154,7 +155,7 @@ func (service {{{ toCamelCase .EntityName }}}Service) Edit(editReq {{{ toUpperCa
if e = response.CheckErr(err, "查询失败"); e != nil {
return
}
util.ConvertUtil.Copy(&obj, editReq)
convert_util.Copy(&obj, editReq)
err = service.db.Model(&obj).Select("*").Updates(obj).Error
if e = response.CheckErr(err, "编辑失败"); e != nil {
@@ -200,9 +201,7 @@ func (service {{{ toCamelCase .EntityName }}}Service) DelBatch(Ids []string) (e
return err
}
//
for _, v := range Ids {
cacheUtil.RemoveCache(v)
}
cacheUtil.RemoveCache(Ids)
return nil
}
@@ -237,14 +236,14 @@ func (service {{{ toCamelCase .EntityName }}}Service) ExportFile(listReq {{{ toU
return
}
result := []{{{ toUpperCamelCase .EntityName }}}Resp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return result, nil
}
// 导入
func (service {{{ toCamelCase .EntityName }}}Service) ImportFile(importReq []{{{ toUpperCamelCase .EntityName }}}Resp) (e error) {
var importData []model.{{{ toUpperCamelCase .EntityName }}}
util.ConvertUtil.Copy(&importData, importReq)
convert_util.Copy(&importData, importReq)
err := service.db.Create(&importData).Error
e = response.CheckErr(err, "添加失败")
return e

View File

@@ -173,7 +173,7 @@
</div>
</template>
<script lang="ts" setup>
import { ref,reactive,shallowRef } from 'vue'
import { ref,reactive,shallowRef,nextTick } from 'vue'
import { {{{ .ModuleName }}}_delete,{{{ .ModuleName }}}_delete_batch, {{{ .ModuleName }}}_list,{{{.ModuleName}}}_import_file, {{{.ModuleName}}}_export_file } from '@/api/{{{nameToPath .ModuleName }}}'
import type { type_{{{ .ModuleName }}},type_{{{.ModuleName}}}_query } from "@/api/{{{nameToPath .ModuleName }}}";

View File

@@ -1,14 +1,19 @@
package monitor_client
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"x_admin/core"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/util"
"x_admin/util/excel2"
"x_admin/util/img_util"
"github.com/gin-gonic/gin"
"golang.org/x/sync/singleflight"
@@ -29,7 +34,11 @@ type MonitorClientHandler struct {
// @Param UserId query string false "用户id"
// @Param Os query string false "系统"
// @Param Browser query string false "浏览器"
// @Param Country query string false "国家"
// @Param Province query string false "省份"
// @Param City query string false "城市"
// @Param Operator query string false "电信运营商"
// @Param Ip query string false "ip"
// @Param Width query number false "屏幕"
// @Param Height query number false "屏幕高度"
// @Param Ua query string false "ua记录"
@@ -59,7 +68,11 @@ func (hd *MonitorClientHandler) List(c *gin.Context) {
// @Param UserId query string false "用户id"
// @Param Os query string false "系统"
// @Param Browser query string false "浏览器"
// @Param Country query string false "国家"
// @Param Province query string false "省份"
// @Param City query string false "城市"
// @Param Operator query string false "电信运营商"
// @Param Ip query string false "ip"
// @Param Width query number false "屏幕"
// @Param Height query number false "屏幕高度"
// @Param Ua query string false "ua记录"
@@ -114,44 +127,67 @@ func (hd *MonitorClientHandler) Detail(c *gin.Context) {
// @Param UserId body string false "用户id"
// @Param Os body string false "系统"
// @Param Browser body string false "浏览器"
// @Param City body string false "城市"
// @Param Country query string false "国家"
// @Param Province query string false "省份"
// @Param City query string false "城市"
// @Param Operator query string false "电信运营商"
// @Param Ip query string false "ip"
// @Param Width body number false "屏幕"
// @Param Height body number false "屏幕高度"
// @Param Ua body string false "ua记录"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_client/add [post]
func (hd *MonitorClientHandler) Add(c *gin.Context) {
var addReq MonitorClientAddReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
data, err := url.QueryUnescape(c.Query("data"))
if err != nil {
// response.CheckAndRespWithData(c, 0, err)
c.Data(200, "image/gif", img_util.EmptyGif())
return
}
createId, e := MonitorClientService.Add(addReq)
response.CheckAndRespWithData(c, createId, e)
}
var addReq MonitorClientAddReq
json.Unmarshal([]byte(data), &addReq)
// @Summary 监控-客户端信息编辑
// @Tags monitor_client-监控-客户端信息
// @Produce json
// @Param Token header string true "token"
// @Param Id body number false "uuid"
// @Param ProjectKey body string false "项目key"
// @Param ClientId body string false "sdk生成的客户端id"
// @Param UserId body string false "用户id"
// @Param Os body string false "系统"
// @Param Browser body string false "浏览器"
// @Param City body string false "城市"
// @Param Width body number false "屏幕"
// @Param Height body number false "屏幕高度"
// @Param Ua body string false "ua记录"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_client/edit [post]
// func (hd *MonitorClientHandler) Edit(c *gin.Context) {
// var editReq MonitorClientEditReq
// if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &editReq)) {
// return
// }
// response.CheckAndRespWithData(c, editReq.Id, MonitorClientService.Edit(editReq))
// }
lastClient, err := MonitorClientService.DetailByClientId(*addReq.ClientId)
uaStr := c.GetHeader("user-agent")
ip := c.ClientIP()
if err == nil {
last := lastClient.UserId + lastClient.Width.String() + lastClient.Height.String() + lastClient.Ip + lastClient.Ua
newStr := *addReq.UserId + addReq.Width.String() + addReq.Height.String() + ip + uaStr
if last == newStr {
// 前后数据一样,不用创建新的数据
fmt.Println("前后数据一样,不用创建新的数据")
c.Data(200, "image/gif", img_util.EmptyGif())
// response.CheckAndRespWithData(c, 0, nil)
return
} else {
// 新建的话需要清除lastClient对应的缓存
cacheUtil.RemoveCache("ClientId:" + lastClient.ClientId)
}
}
if uaStr != "" {
ua := core.UAParser.Parse(uaStr)
addReq.Ua = &uaStr
addReq.Os = &ua.Os.Family
addReq.Browser = &ua.UserAgent.Family
}
addReq.Ip = &ip
if ip != "" && ip != "127.0.0.1" {
regionInfo := util.IpUtil.Parse(ip)
// regionInfo := util.IpUtil.Parse("118.24.157.190")
addReq.City = &regionInfo.City
addReq.Country = &regionInfo.Country
addReq.Operator = &regionInfo.Operator
addReq.Province = &regionInfo.Province
}
MonitorClientService.Add(addReq)
c.Data(200, "image/gif", img_util.EmptyGif())
}
// @Summary 监控-客户端信息删除
// @Tags monitor_client-监控-客户端信息
@@ -199,7 +235,11 @@ func (hd *MonitorClientHandler) DelBatch(c *gin.Context) {
// @Param UserId query string false "用户id"
// @Param Os query string false "系统"
// @Param Browser query string false "浏览器"
// @Param Country query string false "国家"
// @Param Province query string false "省份"
// @Param City query string false "城市"
// @Param Operator query string false "电信运营商"
// @Param Ip query string false "ip"
// @Param Width query number false "屏幕"
// @Param Height query number false "屏幕高度"
// @Param Ua query string false "ua记录"

View File

@@ -6,12 +6,18 @@ import (
// MonitorClientListReq 监控-客户端信息列表参数
type MonitorClientListReq struct {
ProjectKey *string // 项目key
ClientId *string // sdk生成的客户端id
UserId *string // 用户id
Os *string // 系统
Browser *string // 浏览器
City *string // 城市
ProjectKey *string // 项目key
ClientId *string // sdk生成的客户端id
UserId *string // 用户id
Os *string // 系统
Browser *string // 浏览器
Country *string // 国家
Province *string // 省份
City *string // 城市
Operator *string // 电信运营商
Ip *string // ip
Width *int // 屏幕
Height *int // 屏幕高度
Ua *string // ua记录
@@ -27,7 +33,11 @@ type MonitorClientAddReq struct {
UserId *string // 用户id
Os *string // 系统
Browser *string // 浏览器
Country *string // 国家
Province *string // 省份
City *string // 城市
Operator *string // 电信运营商
Ip *string // ip
Width core.NullInt // 屏幕
Height core.NullInt // 屏幕高度
Ua *string // ua记录
@@ -42,7 +52,11 @@ type MonitorClientEditReq struct {
UserId *string // 用户id
Os *string // 系统
Browser *string // 浏览器
Country *string // 国家
Province *string // 省份
City *string // 城市
Operator *string // 电信运营商
Ip *string // ip
Width core.NullInt // 屏幕
Height core.NullInt // 屏幕高度
Ua *string // ua记录
@@ -71,7 +85,11 @@ type MonitorClientResp struct {
UserId string // 用户id
Os string // 系统
Browser string // 浏览器
Country string // 国家
Province string // 省份
City string // 城市
Operator string // 电信运营商
Ip string // ip
Width core.NullInt // 屏幕
Height core.NullInt // 屏幕高度
Ua string // ua记录

View File

@@ -1,11 +1,13 @@
package monitor_client
import (
"errors"
"x_admin/core"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"x_admin/util/convert_util"
"x_admin/util/excel2"
"gorm.io/gorm"
@@ -49,9 +51,21 @@ func (service monitorClientService) GetModel(listReq MonitorClientListReq) *gorm
if listReq.Browser != nil {
dbModel = dbModel.Where("browser = ?", *listReq.Browser)
}
if listReq.Country != nil {
dbModel = dbModel.Where("country = ?", *listReq.Country)
}
if listReq.Province != nil {
dbModel = dbModel.Where("province = ?", *listReq.Province)
}
if listReq.City != nil {
dbModel = dbModel.Where("city = ?", *listReq.City)
}
if listReq.Operator != nil {
dbModel = dbModel.Where("operator = ?", *listReq.Operator)
}
if listReq.Ip != nil {
dbModel = dbModel.Where("ip = ?", *listReq.Ip)
}
if listReq.Width != nil {
dbModel = dbModel.Where("width = ?", *listReq.Width)
}
@@ -90,35 +104,7 @@ func (service monitorClientService) List(page request.PageReq, listReq MonitorCl
return
}
result := []MonitorClientResp{}
util.ConvertUtil.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
Count: count,
Lists: result,
}, nil
}
// List 监控-客户端信息列表
func (service monitorClientService) ListByErrorId(page request.PageReq, listReq MonitorClientListReq, errorId int) (res response.PageResp, e error) {
// 分页信息
limit := page.PageSize
offset := page.PageSize * (page.PageNo - 1)
dbModel := service.GetModel(listReq)
// 总数
var count int64
err := dbModel.Count(&count).Error
if e = response.CheckErr(err, "失败"); e != nil {
return
}
// 数据
var modelList []model.MonitorClient
err = dbModel.Limit(limit).Offset(offset).Order("id desc").Find(&modelList).Error
if e = response.CheckErr(err, "查询失败"); e != nil {
return
}
result := []MonitorClientResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -137,10 +123,32 @@ func (service monitorClientService) ListAll(listReq MonitorClientListReq) (res [
if e = response.CheckErr(err, "查询全部失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, modelList)
convert_util.Copy(&res, modelList)
return res, nil
}
func (service monitorClientService) DetailByClientId(ClientId string) (res MonitorClientResp, e error) {
if ClientId == "" {
return res, errors.New("ClientId不能为空")
}
var obj = model.MonitorClient{}
err := cacheUtil.GetCache("ClientId:"+ClientId, &obj)
if err != nil {
err := service.db.Where("client_id = ?", ClientId).Order("id DESC").Limit(1).First(&obj).Error
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "获取详情失败"); e != nil {
return
}
cacheUtil.SetCache(obj.Id, obj)
cacheUtil.SetCache("ClientId:"+obj.ClientId, obj)
}
convert_util.Copy(&res, obj)
return
}
// Detail 监控-客户端信息详情
func (service monitorClientService) Detail(Id int) (res MonitorClientResp, e error) {
var obj = model.MonitorClient{}
@@ -154,65 +162,37 @@ func (service monitorClientService) Detail(Id int) (res MonitorClientResp, e err
return
}
cacheUtil.SetCache(obj.Id, obj)
cacheUtil.SetCache("ClientId:"+obj.ClientId, obj)
}
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
// ErrorUser 监控-客户端信息详情
func (service monitorClientService) ErrorUsers(error_id int) (res []MonitorClientResp, e error) {
var obj = []model.MonitorClient{}
service.db.Raw("SELECT client.* from x_monitor_error_list as list left join x_monitor_client as client on client.client_id = list.client_id where list.error_id = ? Order by list.id DESC", error_id).Scan(&obj)
service.db.Raw("SELECT client.*,list.create_time AS create_time from x_monitor_error_list as list right join x_monitor_client as client on client.id = list.cid where list.eid = ? Order by list.id DESC LIMIT 0,20", error_id).Scan(&obj)
// if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
// return
// }
// if e = response.CheckErr(err, "获取失败"); e != nil {
// return
// }
// cacheUtil.SetCache(obj.Id, obj)
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
// Add 监控-客户端信息新增
func (service monitorClientService) Add(addReq MonitorClientAddReq) (createId int, e error) {
var obj model.MonitorClient
util.ConvertUtil.StructToStruct(addReq, &obj)
convert_util.StructToStruct(addReq, &obj)
err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err)
if e != nil {
return 0, e
}
cacheUtil.SetCache(obj.Id, obj)
cacheUtil.SetCache("ClientId:"+obj.ClientId, obj)
createId = obj.Id
return
}
// // Edit 监控-客户端信息编辑
// func (service monitorClientService) Edit(editReq MonitorClientEditReq) (e error) {
// var obj model.MonitorClient
// err := service.db.Where("id = ?", editReq.Id).Limit(1).First(&obj).Error
// // 校验
// if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
// return
// }
// if e = response.CheckErr(err, "查询失败"); e != nil {
// return
// }
// util.ConvertUtil.Copy(&obj, editReq)
// err = service.db.Model(&obj).Select("*").Updates(obj).Error
// if e = response.CheckErr(err, "编辑失败"); e != nil {
// return
// }
// cacheUtil.RemoveCache(obj.Id)
// service.Detail(obj.Id)
// return
// }
// Del 监控-客户端信息删除
func (service monitorClientService) Del(Id int) (e error) {
var obj model.MonitorClient
@@ -228,20 +208,34 @@ func (service monitorClientService) Del(Id int) (e error) {
err = service.db.Delete(&obj).Error
e = response.CheckErr(err, "删除失败")
cacheUtil.RemoveCache(obj.Id)
cacheUtil.RemoveCache("ClientId:" + obj.ClientId)
return
}
// DelBatch 用户协议-批量删除
func (service monitorClientService) DelBatch(Ids []string) (e error) {
var obj model.MonitorClient
err := service.db.Where("id in (?)", Ids).Delete(&obj).Error
var obj []model.MonitorClient
// 查询Ids对应的数据
err := service.db.Where("id in (?)", Ids).Find(&obj).Error
if err != nil {
return err
}
// 删除缓存
for _, v := range Ids {
cacheUtil.RemoveCache(v)
if len(obj) == 0 {
return errors.New("数据不存在")
}
err = service.db.Where("id in (?)", Ids).Delete(model.MonitorClient{}).Error
if err != nil {
return err
}
// md5集合
var Clients []string
for _, v := range obj {
Clients = append(Clients, "ClientId:"+v.ClientId)
}
// 删除缓存
cacheUtil.RemoveCache(Ids)
cacheUtil.RemoveCache(Clients)
return nil
}
@@ -275,14 +269,14 @@ func (service monitorClientService) ExportFile(listReq MonitorClientListReq) (re
return
}
result := []MonitorClientResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return result, nil
}
// 导入
func (service monitorClientService) ImportFile(importReq []MonitorClientResp) (e error) {
var importData []model.MonitorClient
util.ConvertUtil.Copy(&importData, importReq)
convert_util.Copy(&importData, importReq)
err := service.db.Create(&importData).Error
e = response.CheckErr(err, "添加失败")
return e

View File

@@ -1,7 +1,9 @@
package monitor_error
import (
"encoding/json"
"net/http"
"net/url"
"strconv"
"strings"
"time"
@@ -9,6 +11,7 @@ import (
"x_admin/core/response"
"x_admin/util"
"x_admin/util/excel2"
"x_admin/util/img_util"
"github.com/gin-gonic/gin"
"golang.org/x/sync/singleflight"
@@ -18,23 +21,23 @@ type MonitorErrorHandler struct {
requestGroup singleflight.Group
}
// @Summary 监控-错误列列表
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param PageNo query int true "页码"
// @Param PageSize query int true "每页数量"
// @Param ProjectKey query string false "项目key"
// @Param EventType query string false "事件类型"
// @Param Path query string false "URL地址"
// @Param Message query string false "错误消息"
// @Param Stack query string false "错误堆栈"
// @Param Md5 query string false "md5"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Summary 监控-错误列列表
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param PageNo query int true "页码"
// @Param PageSize query int true "每页数量"
// @Param ProjectKey query string false "项目key"
// @Param EventType query string false "事件类型"
// @Param Path query string false "URL地址"
// @Param Message query string false "错误消息"
// @Param Stack query string false "错误堆栈"
// @Param Md5 query string false "md5"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
//
// @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorErrorResp}} "成功"
// @Router /api/admin/monitor_error/list [get]
// @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorErrorResp}} "成功"
// @Router /api/admin/monitor_error/list [get]
func (hd *MonitorErrorHandler) List(c *gin.Context) {
var page request.PageReq
var listReq MonitorErrorListReq
@@ -48,19 +51,19 @@ func (hd *MonitorErrorHandler) List(c *gin.Context) {
response.CheckAndRespWithData(c, res, err)
}
// @Summary 监控-错误列列表-所有
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param ProjectKey query string false "项目key"
// @Param EventType query string false "事件类型"
// @Param Path query string false "URL地址"
// @Param Message query string false "错误消息"
// @Param Stack query string false "错误堆栈"
// @Param Md5 query string false "md5"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Success 200 {object} response.Response{ data=[]MonitorErrorResp} "成功"
// @Router /api/admin/monitor_error/listAll [get]
// @Summary 监控-错误列列表-所有
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param ProjectKey query string false "项目key"
// @Param EventType query string false "事件类型"
// @Param Path query string false "URL地址"
// @Param Message query string false "错误消息"
// @Param Stack query string false "错误堆栈"
// @Param Md5 query string false "md5"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Success 200 {object} response.Response{ data=[]MonitorErrorResp} "成功"
// @Router /api/admin/monitor_error/listAll [get]
func (hd *MonitorErrorHandler) ListAll(c *gin.Context) {
var listReq MonitorErrorListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
@@ -70,13 +73,13 @@ func (hd *MonitorErrorHandler) ListAll(c *gin.Context) {
response.CheckAndRespWithData(c, res, err)
}
// @Summary 监控-错误列详情
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param Id query number false "错误id"
// @Success 200 {object} response.Response{ data=MonitorErrorResp} "成功"
// @Router /api/admin/monitor_error/detail [get]
// @Summary 监控-错误列详情
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param Id query number false "错误id"
// @Success 200 {object} response.Response{ data=MonitorErrorResp} "成功"
// @Router /api/admin/monitor_error/detail [get]
func (hd *MonitorErrorHandler) Detail(c *gin.Context) {
var detailReq MonitorErrorDetailReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) {
@@ -90,34 +93,46 @@ func (hd *MonitorErrorHandler) Detail(c *gin.Context) {
response.CheckAndRespWithData(c, res, err)
}
// @Summary 监控-错误列新增
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param ProjectKey body string false "项目key"
// @Param EventType body string false "事件类型"
// @Param Path body string false "URL地址"
// @Param Message body string false "错误消息"
// @Param Stack body string false "错误堆栈"
// @Param Md5 body string false "md5"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_error/add [post]
// @Summary 监控-错误列新增
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param ProjectKey body string false "项目key"
// @Param EventType body string false "事件类型"
// @Param Path body string false "URL地址"
// @Param Message body string false "错误消息"
// @Param Stack body string false "错误堆栈"
// @Param Md5 body string false "md5"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_error/add [post]
func (hd *MonitorErrorHandler) Add(c *gin.Context) {
var addReq MonitorErrorAddReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
data, err := url.QueryUnescape(c.Query("data"))
if err != nil {
// response.CheckAndRespWithData(c, 0, err)
c.Data(200, "image/gif", img_util.EmptyGif())
return
}
createId, e := MonitorErrorService.Add(addReq)
response.CheckAndRespWithData(c, createId, e)
var addReq []MonitorErrorAddReq
json.Unmarshal([]byte(data), &addReq)
// if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
// return
// }
for i := 0; i < len(addReq); i++ {
MonitorErrorService.Add(addReq[i])
}
// response.CheckAndRespWithData(c, g, nil)
c.Data(200, "image/gif", img_util.EmptyGif())
}
// @Summary 监控-错误列删除
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param Id body number false "错误id"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_error/del [post]
// @Summary 监控-错误列删除
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param Id body number false "错误id"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_error/del [post]
func (hd *MonitorErrorHandler) Del(c *gin.Context) {
var delReq MonitorErrorDelReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
@@ -126,14 +141,14 @@ func (hd *MonitorErrorHandler) Del(c *gin.Context) {
response.CheckAndResp(c, MonitorErrorService.Del(delReq.Id))
}
// @Summary 监控-错误列删除-批量
// @Tags monitor_error-监控-错误列
// @Summary 监控-错误列删除-批量
// @Tags monitor_error-监控-错误列
//
// @Produce json
// @Param Token header string true "token"
// @Param Ids body string false "逗号分割的id"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_error/delBatch [post]
// @Produce json
// @Param Token header string true "token"
// @Param Ids body string false "逗号分割的id"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_error/delBatch [post]
func (hd *MonitorErrorHandler) DelBatch(c *gin.Context) {
var delReq MonitorErrorDelBatchReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
@@ -148,19 +163,19 @@ func (hd *MonitorErrorHandler) DelBatch(c *gin.Context) {
response.CheckAndResp(c, MonitorErrorService.DelBatch(Ids))
}
// @Summary 监控-错误列导出
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param ProjectKey query string false "项目key"
// @Param EventType query string false "事件类型"
// @Param Path query string false "URL地址"
// @Param Message query string false "错误消息"
// @Param Stack query string false "错误堆栈"
// @Param Md5 query string false "md5"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Router /api/admin/monitor_error/ExportFile [get]
// @Summary 监控-错误列导出
// @Tags monitor_error-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param ProjectKey query string false "项目key"
// @Param EventType query string false "事件类型"
// @Param Path query string false "URL地址"
// @Param Message query string false "错误消息"
// @Param Stack query string false "错误堆栈"
// @Param Md5 query string false "md5"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Router /api/admin/monitor_error/ExportFile [get]
func (hd *MonitorErrorHandler) ExportFile(c *gin.Context) {
var listReq MonitorErrorListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
@@ -179,10 +194,10 @@ func (hd *MonitorErrorHandler) ExportFile(c *gin.Context) {
excel2.DownLoadExcel("监控-错误列"+time.Now().Format("20060102-150405"), c.Writer, f)
}
// @Summary 监控-错误列导入
// @Tags monitor_error-监控-错误列
// @Produce json
// @Router /api/admin/monitor_error/ImportFile [post]
// @Summary 监控-错误列导入
// @Tags monitor_error-监控-错误列
// @Produce json
// @Router /api/admin/monitor_error/ImportFile [post]
func (hd *MonitorErrorHandler) ImportFile(c *gin.Context) {
file, _, err := c.Request.FormFile("file")
if err != nil {

View File

@@ -1,13 +1,16 @@
package monitor_error
import (
"errors"
"strconv"
"x_admin/admin/monitor_client"
"x_admin/admin/monitor_error_list"
"x_admin/core"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"x_admin/util/convert_util"
"x_admin/util/excel2"
"gorm.io/gorm"
@@ -83,7 +86,7 @@ func (service monitorErrorService) List(page request.PageReq, listReq MonitorErr
return
}
result := []MonitorErrorResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -102,7 +105,7 @@ func (service monitorErrorService) ListAll(listReq MonitorErrorListReq) (res []M
if e = response.CheckErr(err, "查询全部失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, modelList)
convert_util.Copy(&res, modelList)
return res, nil
}
@@ -121,7 +124,7 @@ func (service monitorErrorService) Detail(Id int) (res MonitorErrorResp, e error
cacheUtil.SetCache(obj.Id, obj)
}
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
@@ -140,41 +143,47 @@ func (service monitorErrorService) DetailByMD5(md5 string) (res MonitorErrorResp
cacheUtil.SetCache("md5:"+md5, obj)
}
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
// Add 监控-错误列新增
func (service monitorErrorService) Add(addReq MonitorErrorAddReq) (createId int, e error) {
func (service monitorErrorService) Add(addReq MonitorErrorAddReq) (createId int, err error) {
var obj model.MonitorError
util.ConvertUtil.StructToStruct(addReq, &obj)
convert_util.StructToStruct(addReq, &obj)
Md5 := util.ToolsUtil.MakeMd5(obj.ProjectKey + obj.Path + obj.Stack)
Md5 := util.ToolsUtil.MakeMd5(obj.ProjectKey + obj.EventType + obj.Message + obj.Path + obj.Stack)
errorDetails, e := service.DetailByMD5(Md5)
if e != nil {
errorDetails, err := service.DetailByMD5(Md5)
if err != nil {
obj.Md5 = Md5
err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err)
if e != nil {
return 0, e
err = response.CheckMysqlErr(err)
if err != nil {
return 0, err
}
createId = obj.Id
cacheUtil.SetCache(createId, obj)
cacheUtil.SetCache("md5:"+Md5, obj)
} else {
createId = errorDetails.Id
}
client, err := monitor_client.MonitorClientService.DetailByClientId(addReq.ClientId)
if err != nil {
return 0, err
}
monitor_error_list.MonitorErrorListService.Add(monitor_error_list.MonitorErrorListAddReq{
ErrorId: strconv.Itoa(createId),
ClientId: addReq.ClientId,
ProjectKey: addReq.ProjectKey,
_, err = monitor_error_list.MonitorErrorListService.Add(monitor_error_list.MonitorErrorListAddReq{
Eid: strconv.Itoa(createId),
Cid: strconv.Itoa(client.Id),
// ClientId: addReq.ClientId,
// ProjectKey: addReq.ProjectKey,
})
return
return createId, err
}
// Del 监控-错误列删除
@@ -192,20 +201,33 @@ func (service monitorErrorService) Del(Id int) (e error) {
err = service.db.Delete(&obj).Error
e = response.CheckErr(err, "删除失败")
cacheUtil.RemoveCache(obj.Id)
cacheUtil.RemoveCache("md5:" + obj.Md5)
return
}
// DelBatch 用户协议-批量删除
func (service monitorErrorService) DelBatch(Ids []string) (e error) {
var obj model.MonitorError
err := service.db.Where("id in (?)", Ids).Delete(&obj).Error
var obj []model.MonitorError
// 查询Ids对应的数据
err := service.db.Where("id in (?)", Ids).Find(&obj).Error
if err != nil {
return err
}
// 删除缓存
for _, v := range Ids {
cacheUtil.RemoveCache(v)
if len(obj) == 0 {
return errors.New("数据不存在")
}
err = service.db.Where("id in (?)", Ids).Delete(model.MonitorError{}).Error
if err != nil {
return err
}
// md5集合
var md5s []string
for _, v := range obj {
md5s = append(md5s, "md5:"+v.Md5)
}
// 删除缓存
cacheUtil.RemoveCache(Ids)
cacheUtil.RemoveCache(md5s)
return nil
}
@@ -237,14 +259,14 @@ func (service monitorErrorService) ExportFile(listReq MonitorErrorListReq) (res
return
}
result := []MonitorErrorResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return result, nil
}
// 导入
func (service monitorErrorService) ImportFile(importReq []MonitorErrorResp) (e error) {
var importData []model.MonitorError
util.ConvertUtil.Copy(&importData, importReq)
convert_util.Copy(&importData, importReq)
err := service.db.Create(&importData).Error
e = response.CheckErr(err, "添加失败")
return e

View File

@@ -6,16 +6,16 @@ import (
// MonitorErrorListAddReq 错误对应的用户记录新增参数
type MonitorErrorListAddReq struct {
ErrorId string // 错误id
ClientId string // 客户端id
ProjectKey string // 项目id
Eid string // 错误id
Cid string // 客户端id
// ProjectKey string // 项目id
}
// MonitorErrorListResp 错误对应的用户记录返回信息
type MonitorErrorListResp struct {
Id int // 项目id
ErrorId string // 错误id
ClientId string // 客户端id
ProjectKey string // 项目id
Id int // 项目id
Eid string // 错误id
Cid string // 客户端id
// ProjectKey string // 项目id
CreateTime core.NullTime // 创建时间
}

View File

@@ -4,7 +4,7 @@ import (
"x_admin/core"
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -28,7 +28,7 @@ type monitorErrorListService struct {
// Add 错误对应的用户记录新增
func (service monitorErrorListService) Add(addReq MonitorErrorListAddReq) (createId int, e error) {
var obj model.MonitorErrorList
util.ConvertUtil.StructToStruct(addReq, &obj)
convert_util.StructToStruct(addReq, &obj)
err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err)
if e != nil {

View File

@@ -6,6 +6,7 @@ import (
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"x_admin/util/convert_util"
"x_admin/util/excel2"
"gorm.io/gorm"
@@ -81,7 +82,7 @@ func (service monitorProjectService) List(page request.PageReq, listReq MonitorP
return
}
result := []MonitorProjectResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -100,7 +101,7 @@ func (service monitorProjectService) ListAll(listReq MonitorProjectListReq) (res
if e = response.CheckErr(err, "查询全部失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, modelList)
convert_util.Copy(&res, modelList)
return res, nil
}
@@ -119,14 +120,14 @@ func (service monitorProjectService) Detail(Id int) (res MonitorProjectResp, e e
cacheUtil.SetCache(obj.Id, obj)
}
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
// Add 监控项目新增
func (service monitorProjectService) Add(addReq MonitorProjectAddReq) (createId int, e error) {
var obj model.MonitorProject
util.ConvertUtil.StructToStruct(addReq, &obj)
convert_util.StructToStruct(addReq, &obj)
obj.ProjectKey = util.ToolsUtil.MakeUuid()
err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err)
@@ -149,7 +150,7 @@ func (service monitorProjectService) Edit(editReq MonitorProjectEditReq) (e erro
if e = response.CheckErr(err, "查询失败"); e != nil {
return
}
util.ConvertUtil.Copy(&obj, editReq)
convert_util.Copy(&obj, editReq)
err = service.db.Model(&obj).Select("*").Updates(obj).Error
if e = response.CheckErr(err, "编辑失败"); e != nil {
@@ -188,9 +189,10 @@ func (service monitorProjectService) DelBatch(Ids []string) (e error) {
return err
}
// 删除缓存
for _, v := range Ids {
cacheUtil.RemoveCache(v)
}
// for _, v := range Ids {
// cacheUtil.RemoveCache(v)
// }
cacheUtil.RemoveCache(Ids)
return nil
}
@@ -220,14 +222,14 @@ func (service monitorProjectService) ExportFile(listReq MonitorProjectListReq) (
return
}
result := []MonitorProjectResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return result, nil
}
// 导入
func (service monitorProjectService) ImportFile(importReq []MonitorProjectResp) (e error) {
var importData []model.MonitorProject
util.ConvertUtil.Copy(&importData, importReq)
convert_util.Copy(&importData, importReq)
err := service.db.Create(&importData).Error
e = response.CheckErr(err, "添加失败")
return e

View File

@@ -0,0 +1,220 @@
package monitor_slow
import (
"encoding/json"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/util"
"x_admin/util/excel2"
"x_admin/util/img_util"
"github.com/gin-gonic/gin"
"golang.org/x/sync/singleflight"
)
type MonitorSlowHandler struct {
requestGroup singleflight.Group
}
// @Summary 监控-错误列列表
// @Tags monitor_slow-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param PageNo query int true "页码"
// @Param PageSize query int true "每页数量"
// @Param ProjectKey query string false "项目key"
// @Param ClientId query string false "sdk生成的客户端id"
// @Param UserId query string false "用户id"
// @Param Path query string false "URL地址"
// @Param Time query number false "时间"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
//
// @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorSlowResp}} "成功"
// @Router /api/admin/monitor_slow/list [get]
func (hd *MonitorSlowHandler) List(c *gin.Context) {
var page request.PageReq
var listReq MonitorSlowListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &page)) {
return
}
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
return
}
res, err := MonitorSlowService.List(page, listReq)
response.CheckAndRespWithData(c, res, err)
}
// @Summary 监控-错误列列表-所有
// @Tags monitor_slow-监控-错误列
// @Produce json
// @Param ProjectKey query string false "项目key"
// @Param ClientId query string false "sdk生成的客户端id"
// @Param UserId query string false "用户id"
// @Param Path query string false "URL地址"
// @Param Time query number false "时间"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Success 200 {object} response.Response{ data=[]MonitorSlowResp} "成功"
// @Router /api/admin/monitor_slow/listAll [get]
func (hd *MonitorSlowHandler) ListAll(c *gin.Context) {
var listReq MonitorSlowListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
return
}
res, err := MonitorSlowService.ListAll(listReq)
response.CheckAndRespWithData(c, res, err)
}
// @Summary 监控-错误列详情
// @Tags monitor_slow-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param Id query number false "错误id"
// @Success 200 {object} response.Response{ data=MonitorSlowResp} "成功"
// @Router /api/admin/monitor_slow/detail [get]
func (hd *MonitorSlowHandler) Detail(c *gin.Context) {
var detailReq MonitorSlowDetailReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) {
return
}
res, err, _ := hd.requestGroup.Do("MonitorSlow:Detail:"+strconv.Itoa(detailReq.Id), func() (any, error) {
v, err := MonitorSlowService.Detail(detailReq.Id)
return v, err
})
response.CheckAndRespWithData(c, res, err)
}
// @Summary 监控-错误列新增
// @Tags monitor_slow-监控-错误列
// @Produce json
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_slow/add [get]
func (hd *MonitorSlowHandler) Add(c *gin.Context) {
data, err := url.QueryUnescape(c.Query("data"))
if err != nil {
c.Data(200, "image/gif", img_util.EmptyGif())
return
}
var addReq MonitorSlowAddReq
json.Unmarshal([]byte(data), &addReq)
MonitorSlowService.Add(addReq)
c.Data(200, "image/gif", img_util.EmptyGif())
}
// @Summary 监控-错误列编辑
// @Tags monitor_slow-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param Id body number false "错误id"
// @Param ProjectKey body string false "项目key"
// @Param ClientId body string false "sdk生成的客户端id"
// @Param UserId body string false "用户id"
// @Param Path body string false "URL地址"
// @Param Time body number false "时间"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_slow/edit [post]
func (hd *MonitorSlowHandler) Edit(c *gin.Context) {
var editReq MonitorSlowEditReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &editReq)) {
return
}
response.CheckAndRespWithData(c, editReq.Id, MonitorSlowService.Edit(editReq))
}
// @Summary 监控-错误列删除
// @Tags monitor_slow-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param Id body number false "错误id"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_slow/del [post]
func (hd *MonitorSlowHandler) Del(c *gin.Context) {
var delReq MonitorSlowDelReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
return
}
response.CheckAndResp(c, MonitorSlowService.Del(delReq.Id))
}
// @Summary 监控-错误列删除-批量
// @Tags monitor_slow-监控-错误列
//
// @Produce json
// @Param Token header string true "token"
// @Param Ids body string false "逗号分割的id"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_slow/delBatch [post]
func (hd *MonitorSlowHandler) DelBatch(c *gin.Context) {
var delReq MonitorSlowDelBatchReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
return
}
if delReq.Ids == "" {
response.FailWithMsg(c, response.SystemError, "请选择要删除的数据")
return
}
var Ids = strings.Split(delReq.Ids, ",")
response.CheckAndResp(c, MonitorSlowService.DelBatch(Ids))
}
// @Summary 监控-错误列导出
// @Tags monitor_slow-监控-错误列
// @Produce json
// @Param Token header string true "token"
// @Param ProjectKey query string false "项目key"
// @Param ClientId query string false "sdk生成的客户端id"
// @Param UserId query string false "用户id"
// @Param Path query string false "URL地址"
// @Param Time query number false "时间"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Router /api/admin/monitor_slow/ExportFile [get]
func (hd *MonitorSlowHandler) ExportFile(c *gin.Context) {
var listReq MonitorSlowListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
return
}
res, err := MonitorSlowService.ExportFile(listReq)
if err != nil {
response.FailWithMsg(c, response.SystemError, "查询信息失败")
return
}
f, err := excel2.Export(res, MonitorSlowService.GetExcelCol(), "Sheet1", "监控-错误列")
if err != nil {
response.FailWithMsg(c, response.SystemError, "导出失败")
return
}
excel2.DownLoadExcel("监控-错误列"+time.Now().Format("20060102-150405"), c.Writer, f)
}
// @Summary 监控-错误列导入
// @Tags monitor_slow-监控-错误列
// @Produce json
// @Router /api/admin/monitor_slow/ImportFile [post]
func (hd *MonitorSlowHandler) ImportFile(c *gin.Context) {
file, _, err := c.Request.FormFile("file")
if err != nil {
c.String(http.StatusInternalServerError, "文件不存在")
return
}
defer file.Close()
importList := []MonitorSlowResp{}
err = excel2.GetExcelData(file, &importList, MonitorSlowService.GetExcelCol())
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
err = MonitorSlowService.ImportFile(importList)
response.CheckAndResp(c, err)
}

View File

@@ -0,0 +1,61 @@
package monitor_slow
import (
"x_admin/core"
)
// MonitorSlowListReq 监控-错误列列表参数
type MonitorSlowListReq struct {
ProjectKey *string // 项目key
ClientId *string // sdk生成的客户端id
UserId *string // 用户id
Path *string // URL地址
Time *float64 // 时间
CreateTimeStart *string // 开始创建时间
CreateTimeEnd *string // 结束创建时间
}
// MonitorSlowAddReq 监控-错误列新增参数
type MonitorSlowAddReq struct {
ProjectKey *string // 项目key
ClientId *string // sdk生成的客户端id
UserId *string // 用户id
Path *string // URL地址
Time core.NullFloat // 时间
}
// MonitorSlowEditReq 监控-错误列编辑参数
type MonitorSlowEditReq struct {
Id int // 错误id
ProjectKey *string // 项目key
ClientId *string // sdk生成的客户端id
UserId *string // 用户id
Path *string // URL地址
Time core.NullFloat // 时间
}
// MonitorSlowDetailReq 监控-错误列详情参数
type MonitorSlowDetailReq struct {
Id int // 错误id
}
// MonitorSlowDelReq 监控-错误列删除参数
type MonitorSlowDelReq struct {
Id int // 错误id
}
// MonitorSlowDelReq 监控-错误列批量删除参数
type MonitorSlowDelBatchReq struct {
Ids string
}
// MonitorSlowResp 监控-错误列返回信息
type MonitorSlowResp struct {
Id int // 错误id
ProjectKey string // 项目key
ClientId string // sdk生成的客户端id
UserId string // 用户id
Path string // URL地址
Time core.NullFloat // 时间
CreateTime core.NullTime // 创建时间
}

View File

@@ -0,0 +1,226 @@
package monitor_slow
import (
"x_admin/core"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"x_admin/util/convert_util"
"x_admin/util/excel2"
"gorm.io/gorm"
)
var MonitorSlowService = NewMonitorSlowService()
var cacheUtil = util.CacheUtil{
Name: MonitorSlowService.Name,
}
// NewMonitorSlowService 初始化
func NewMonitorSlowService() *monitorSlowService {
return &monitorSlowService{
db: core.GetDB(),
Name: "monitorSlow",
}
}
// monitorSlowService 监控-错误列服务实现类
type monitorSlowService struct {
db *gorm.DB
Name string
}
// List 监控-错误列列表
func (service monitorSlowService) GetModel(listReq MonitorSlowListReq) *gorm.DB {
// 查询
dbModel := service.db.Model(&model.MonitorSlow{})
if listReq.ProjectKey != nil {
dbModel = dbModel.Where("project_key = ?", *listReq.ProjectKey)
}
if listReq.ClientId != nil {
dbModel = dbModel.Where("client_id = ?", *listReq.ClientId)
}
if listReq.UserId != nil {
dbModel = dbModel.Where("user_id = ?", *listReq.UserId)
}
if listReq.Path != nil {
dbModel = dbModel.Where("path = ?", *listReq.Path)
}
if listReq.Time != nil {
dbModel = dbModel.Where("time = ?", *listReq.Time)
}
if listReq.CreateTimeStart != nil {
dbModel = dbModel.Where("create_time >= ?", *listReq.CreateTimeStart)
}
if listReq.CreateTimeEnd != nil {
dbModel = dbModel.Where("create_time <= ?", *listReq.CreateTimeEnd)
}
return dbModel
}
// List 监控-错误列列表
func (service monitorSlowService) List(page request.PageReq, listReq MonitorSlowListReq) (res response.PageResp, e error) {
// 分页信息
limit := page.PageSize
offset := page.PageSize * (page.PageNo - 1)
dbModel := service.GetModel(listReq)
// 总数
var count int64
err := dbModel.Count(&count).Error
if e = response.CheckErr(err, "失败"); e != nil {
return
}
// 数据
var modelList []model.MonitorSlow
err = dbModel.Limit(limit).Offset(offset).Order("id desc").Find(&modelList).Error
if e = response.CheckErr(err, "查询失败"); e != nil {
return
}
result := []MonitorSlowResp{}
convert_util.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
Count: count,
Lists: result,
}, nil
}
// ListAll 监控-错误列列表
func (service monitorSlowService) ListAll(listReq MonitorSlowListReq) (res []MonitorSlowResp, e error) {
dbModel := service.GetModel(listReq)
var modelList []model.MonitorSlow
err := dbModel.Find(&modelList).Error
if e = response.CheckErr(err, "查询全部失败"); e != nil {
return
}
convert_util.Copy(&res, modelList)
return res, nil
}
// Detail 监控-错误列详情
func (service monitorSlowService) Detail(Id int) (res MonitorSlowResp, e error) {
var obj = model.MonitorSlow{}
err := cacheUtil.GetCache(Id, &obj)
if err != nil {
err := service.db.Where("id = ?", Id).Limit(1).First(&obj).Error
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "获取详情失败"); e != nil {
return
}
cacheUtil.SetCache(obj.Id, obj)
}
convert_util.Copy(&res, obj)
return
}
// Add 监控-错误列新增
func (service monitorSlowService) Add(addReq MonitorSlowAddReq) (createId int, e error) {
var obj model.MonitorSlow
convert_util.StructToStruct(addReq, &obj)
err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err)
if e != nil {
return 0, e
}
cacheUtil.SetCache(obj.Id, obj)
createId = obj.Id
return
}
// Edit 监控-错误列编辑
func (service monitorSlowService) Edit(editReq MonitorSlowEditReq) (e error) {
var obj model.MonitorSlow
err := service.db.Where("id = ?", editReq.Id).Limit(1).First(&obj).Error
// 校验
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "查询失败"); e != nil {
return
}
convert_util.Copy(&obj, editReq)
err = service.db.Model(&obj).Select("*").Updates(obj).Error
if e = response.CheckErr(err, "编辑失败"); e != nil {
return
}
cacheUtil.RemoveCache(obj.Id)
service.Detail(obj.Id)
return
}
// Del 监控-错误列删除
func (service monitorSlowService) Del(Id int) (e error) {
var obj model.MonitorSlow
err := service.db.Where("id = ?", Id).Limit(1).First(&obj).Error
// 校验
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "查询数据失败"); e != nil {
return
}
// 删除
err = service.db.Delete(&obj).Error
e = response.CheckErr(err, "删除失败")
cacheUtil.RemoveCache(obj.Id)
return
}
// DelBatch 用户协议-批量删除
func (service monitorSlowService) DelBatch(Ids []string) (e error) {
var obj model.MonitorSlow
err := service.db.Where("id in (?)", Ids).Delete(&obj).Error
if err != nil {
return err
}
// 删除缓存
cacheUtil.RemoveCache(Ids)
return nil
}
// 获取Excel的列
func (service monitorSlowService) GetExcelCol() []excel2.Col {
var cols = []excel2.Col{
{Name: "项目key", Key: "ProjectKey", Width: 15},
{Name: "sdk生成的客户端id", Key: "ClientId", Width: 15},
{Name: "用户id", Key: "UserId", Width: 15},
{Name: "URL地址", Key: "Path", Width: 15},
{Name: "时间", Key: "Time", Width: 15},
{Name: "创建时间", Key: "CreateTime", Width: 15, Decode: util.NullTimeUtil.DecodeTime},
}
// 还可以考虑字典,请求下来加上 Replace 实现替换导出
return cols
}
// ExportFile 监控-错误列导出
func (service monitorSlowService) ExportFile(listReq MonitorSlowListReq) (res []MonitorSlowResp, e error) {
// 查询
dbModel := service.GetModel(listReq)
// 数据
var modelList []model.MonitorSlow
err := dbModel.Order("id asc").Find(&modelList).Error
if e = response.CheckErr(err, "查询失败"); e != nil {
return
}
result := []MonitorSlowResp{}
convert_util.Copy(&result, modelList)
return result, nil
}
// 导入
func (service monitorSlowService) ImportFile(importReq []MonitorSlowResp) (e error) {
var importData []model.MonitorSlow
convert_util.Copy(&importData, importReq)
err := service.db.Create(&importData).Error
e = response.CheckErr(err, "添加失败")
return e
}

View File

@@ -6,6 +6,7 @@ import (
"x_admin/core/response"
"x_admin/model/setting_model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -58,7 +59,7 @@ func (ddSrv settingDictDataService) All(allReq SettingDictDataListReq) (res []Se
return
}
res = []SettingDictDataResp{}
util.ConvertUtil.Copy(&res, dictDatas)
convert_util.Copy(&res, dictDatas)
return
}
@@ -95,7 +96,7 @@ func (ddSrv settingDictDataService) List(page request.PageReq, listReq SettingDi
return
}
dtResp := []SettingDictDataResp{}
util.ConvertUtil.Copy(&dtResp, dds)
convert_util.Copy(&dtResp, dds)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -114,7 +115,7 @@ func (ddSrv settingDictDataService) Detail(id uint) (res SettingDictDataResp, e
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, dd)
convert_util.Copy(&res, dd)
return
}
@@ -124,7 +125,7 @@ func (ddSrv settingDictDataService) Add(addReq SettingDictDataAddReq) (e error)
return response.AssertArgumentError.SetMessage("字典数据已存在!")
}
var dd setting_model.DictData
util.ConvertUtil.Copy(&dd, addReq)
convert_util.Copy(&dd, addReq)
err := ddSrv.db.Create(&dd).Error
e = response.CheckErr(err, "添加失败")
return
@@ -144,7 +145,7 @@ func (ddSrv settingDictDataService) Edit(editReq SettingDictDataEditReq) (e erro
return response.AssertArgumentError.SetMessage("字典数据已存在!")
}
util.ConvertUtil.Copy(&dd, editReq)
convert_util.Copy(&dd, editReq)
err = ddSrv.db.Save(&dd).Error
e = response.CheckErr(err, "编辑失败")
return

View File

@@ -6,6 +6,7 @@ import (
"x_admin/core/response"
"x_admin/model/setting_model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -40,7 +41,7 @@ func (dtSrv settingDictTypeService) All() (res []SettingDictTypeResp, e error) {
return
}
res = []SettingDictTypeResp{}
util.ConvertUtil.Copy(&res, dictTypes)
convert_util.Copy(&res, dictTypes)
return
}
@@ -69,7 +70,7 @@ func (dtSrv settingDictTypeService) List(page request.PageReq, listReq SettingDi
return
}
dtResp := []SettingDictTypeResp{}
util.ConvertUtil.Copy(&dtResp, dts)
convert_util.Copy(&dtResp, dts)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -88,7 +89,7 @@ func (dtSrv settingDictTypeService) Detail(id uint) (res SettingDictTypeResp, e
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, dt)
convert_util.Copy(&res, dt)
return
}
@@ -101,7 +102,7 @@ func (dtSrv settingDictTypeService) Add(addReq SettingDictTypeAddReq) (e error)
return response.AssertArgumentError.SetMessage("字典类型已存在!")
}
var dt setting_model.DictType
util.ConvertUtil.Copy(&dt, addReq)
convert_util.Copy(&dt, addReq)
err := dtSrv.db.Create(&dt).Error
e = response.CheckErr(err, "添加失败")
return
@@ -124,7 +125,7 @@ func (dtSrv settingDictTypeService) Edit(editReq SettingDictTypeEditReq) (e erro
return response.AssertArgumentError.SetMessage("字典类型已存在!")
}
util.ConvertUtil.Copy(&dt, editReq)
convert_util.Copy(&dt, editReq)
// err = dtSrv.db.Model(&dt).Updates(&up).Error
err = dtSrv.db.Save(&dt).Error
e = response.CheckErr(err, "编辑失败")

View File

@@ -13,6 +13,7 @@ import (
"x_admin/core/response"
"x_admin/model/system_model"
"x_admin/util"
"x_admin/util/convert_util"
"github.com/fatih/structs"
"github.com/gin-gonic/gin"
@@ -78,7 +79,7 @@ func (adminSrv systemAuthAdminService) Self(adminId uint) (res SystemAuthAdminSe
auths = append(auths, "*")
}
var admin SystemAuthAdminSelfOneResp
util.ConvertUtil.Copy(&admin, sysAdmin)
convert_util.Copy(&admin, sysAdmin)
admin.Dept = strconv.FormatUint(uint64(sysAdmin.DeptId), 10)
admin.Avatar = util.UrlUtil.ToAbsoluteUrl(sysAdmin.Avatar)
return SystemAuthAdminSelfResp{User: admin, Permissions: auths}, nil
@@ -151,7 +152,7 @@ func (adminSrv systemAuthAdminService) ExportFile(listReq SystemAuthAdminListReq
// 导入
func (adminSrv systemAuthAdminService) ImportFile(importReq []SystemAuthAdminResp) (e error) {
var sysAdmin []system_model.SystemAuthAdmin
util.ConvertUtil.Copy(&sysAdmin, importReq)
convert_util.Copy(&sysAdmin, importReq)
err := adminSrv.db.Create(&sysAdmin).Error
e = response.CheckErr(err, "添加失败")
return e
@@ -254,7 +255,7 @@ func (adminSrv systemAuthAdminService) Detail(id uint) (res SystemAuthAdminResp,
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, sysAdmin)
convert_util.Copy(&res, sysAdmin)
res.Avatar = util.UrlUtil.ToAbsoluteUrl(res.Avatar)
if res.Dept == "" {
res.Dept = strconv.FormatUint(uint64(res.DeptId), 10)
@@ -295,7 +296,7 @@ func (adminSrv systemAuthAdminService) Add(addReq SystemAuthAdminAddReq) (e erro
return response.Failed.SetMessage("密码格式不正确")
}
salt := util.ToolsUtil.RandomString(5)
util.ConvertUtil.Copy(&sysAdmin, addReq)
convert_util.Copy(&sysAdmin, addReq)
sysAdmin.Role = strconv.FormatUint(uint64(addReq.Role), 10)
sysAdmin.Salt = salt
sysAdmin.Password = util.ToolsUtil.MakeMd5(strings.Trim(addReq.Password, " ") + salt)

View File

@@ -4,7 +4,7 @@ import (
"x_admin/core"
"x_admin/core/response"
"x_admin/model/system_model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -39,7 +39,7 @@ func (service systemAuthDeptService) All() (res []SystemAuthDeptResp, e error) {
return
}
res = []SystemAuthDeptResp{}
util.ConvertUtil.Copy(&res, depts)
convert_util.Copy(&res, depts)
return
}
@@ -57,7 +57,7 @@ func (service systemAuthDeptService) List(listReq SystemAuthDeptListReq) (deptRe
if e = response.CheckErr(err, "列表获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&deptResps, depts)
convert_util.Copy(&deptResps, depts)
return
}
@@ -71,7 +71,7 @@ func (service systemAuthDeptService) Detail(id uint) (res SystemAuthDeptResp, e
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, dept)
convert_util.Copy(&res, dept)
return
}
@@ -87,7 +87,7 @@ func (service systemAuthDeptService) Add(addReq SystemAuthDeptAddReq) (e error)
}
}
var dept system_model.SystemAuthDept
util.ConvertUtil.Copy(&dept, addReq)
convert_util.Copy(&dept, addReq)
err := service.db.Create(&dept).Error
e = response.CheckErr(err, "添加失败")
return
@@ -111,7 +111,7 @@ func (service systemAuthDeptService) Edit(editReq SystemAuthDeptEditReq) (e erro
return response.AssertArgumentError.SetMessage("上级部门不能是自己!")
}
// 更新
util.ConvertUtil.Copy(&dept, editReq)
convert_util.Copy(&dept, editReq)
err = service.db.Model(&dept).Select("*").Updates(dept).Error
e = response.CheckErr(err, "编辑失败")
return

View File

@@ -7,6 +7,7 @@ import (
"x_admin/core/response"
"x_admin/model/system_model"
"x_admin/util"
"x_admin/util/convert_util"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
@@ -57,9 +58,9 @@ func (menuSrv systemAuthMenuService) SelectMenuByRoleId(c *gin.Context, roleId u
return
}
var menuResps []SystemAuthMenuResp
util.ConvertUtil.Copy(&menuResps, menus)
convert_util.Copy(&menuResps, menus)
mapList = util.ArrayUtil.ListToTree(
util.ConvertUtil.StructsToMaps(menuResps), "id", "pid", "children")
convert_util.StructsToMaps(menuResps), "id", "pid", "children")
return
}
@@ -71,7 +72,7 @@ func (menuSrv systemAuthMenuService) List() (res interface{}, e error) {
return
}
var menuResps []SystemAuthMenuResp
util.ConvertUtil.Copy(&menuResps, menus)
convert_util.Copy(&menuResps, menus)
return menuResps, nil
}
@@ -85,13 +86,13 @@ func (menuSrv systemAuthMenuService) Detail(id uint) (res SystemAuthMenuResp, e
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, menu)
convert_util.Copy(&res, menu)
return
}
func (menuSrv systemAuthMenuService) Add(addReq SystemAuthMenuAddReq) (e error) {
var menu system_model.SystemAuthMenu
util.ConvertUtil.Copy(&menu, addReq)
convert_util.Copy(&menu, addReq)
err := menuSrv.db.Create(&menu).Error
if e = response.CheckErr(err, "添加失败"); e != nil {
return
@@ -109,7 +110,7 @@ func (menuSrv systemAuthMenuService) Edit(editReq SystemAuthMenuEditReq) (e erro
if e = response.CheckErr(err, "Edit Find err"); e != nil {
return
}
util.ConvertUtil.Copy(&menu, editReq)
convert_util.Copy(&menu, editReq)
err = menuSrv.db.Model(&menu).Select("*").Updates(menu).Error
if e = response.CheckErr(err, "编辑失败"); e != nil {

View File

@@ -5,7 +5,7 @@ import (
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model/system_model"
"x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm"
)
@@ -40,7 +40,7 @@ func (service systemAuthPostService) All() (res []SystemAuthPostResp, e error) {
return
}
res = []SystemAuthPostResp{}
util.ConvertUtil.Copy(&res, posts)
convert_util.Copy(&res, posts)
return
}
@@ -73,7 +73,7 @@ func (service systemAuthPostService) List(page request.PageReq, listReq SystemAu
return
}
postResps := []SystemAuthPostResp{}
util.ConvertUtil.Copy(&postResps, posts)
convert_util.Copy(&postResps, posts)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -92,7 +92,7 @@ func (service systemAuthPostService) Detail(id uint) (res SystemAuthPostResp, e
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, post)
convert_util.Copy(&res, post)
return
}
@@ -106,7 +106,7 @@ func (service systemAuthPostService) Add(addReq SystemAuthPostAddReq) (e error)
return response.AssertArgumentError.SetMessage("该岗位已存在!")
}
var post system_model.SystemAuthPost
util.ConvertUtil.Copy(&post, addReq)
convert_util.Copy(&post, addReq)
err := service.db.Create(&post).Error
e = response.CheckErr(err, "添加失败")
return
@@ -131,7 +131,7 @@ func (service systemAuthPostService) Edit(editReq SystemAuthPostEditReq) (e erro
return response.AssertArgumentError.SetMessage("该岗位已存在!")
}
// 更新
util.ConvertUtil.Copy(&post, editReq)
convert_util.Copy(&post, editReq)
err = service.db.Model(&post).Select("*").Updates(post).Error
e = response.CheckErr(err, "编辑失败")
return

View File

@@ -9,6 +9,7 @@ import (
"x_admin/core/response"
"x_admin/model/system_model"
"x_admin/util"
"x_admin/util/convert_util"
"github.com/fatih/structs"
"gorm.io/gorm"
@@ -43,7 +44,7 @@ func (roleSrv systemAuthRoleService) All() (res []SystemAuthRoleSimpleResp, e er
if e = response.CheckErr(err, "All Find err"); e != nil {
return
}
util.ConvertUtil.Copy(&res, roles)
convert_util.Copy(&res, roles)
return
}
@@ -63,7 +64,7 @@ func (roleSrv systemAuthRoleService) List(page request.PageReq) (res response.Pa
return
}
var roleResp []SystemAuthRoleResp
util.ConvertUtil.Copy(&roleResp, roles)
convert_util.Copy(&roleResp, roles)
for i := 0; i < len(roleResp); i++ {
roleResp[i].Menus = []uint{}
roleResp[i].Member = roleSrv.getMemberCnt(roleResp[i].ID)
@@ -86,7 +87,7 @@ func (roleSrv systemAuthRoleService) Detail(id uint) (res SystemAuthRoleResp, e
if e = response.CheckErr(err, "详情获取失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, role)
convert_util.Copy(&res, role)
res.Member = roleSrv.getMemberCnt(role.ID)
res.Menus, _ = PermService.SelectMenuIdsByRoleId(role.ID)
return
@@ -105,7 +106,7 @@ func (roleSrv systemAuthRoleService) Add(addReq SystemAuthRoleAddReq) (e error)
if r := roleSrv.db.Where("name = ?", strings.Trim(addReq.Name, " ")).Limit(1).First(&role); r.RowsAffected > 0 {
return response.AssertArgumentError.SetMessage("角色名称已存在!")
}
util.ConvertUtil.Copy(&role, addReq)
convert_util.Copy(&role, addReq)
role.Name = strings.Trim(addReq.Name, " ")
// 事务
err := roleSrv.db.Transaction(func(tx *gorm.DB) error {

View File

@@ -18,22 +18,22 @@ type UserProtocolHandler struct {
requestGroup singleflight.Group
}
// @Summary 用户协议列表
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param PageNo query int true "页码"
// @Param PageSize query int true "每页数量"
// @Param Title query string false "标题"
// @Param Content query string false "协议内容"
// @Param Sort query number false "排序"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Param UpdateTimeStart query string false "更新时间"
// @Param UpdateTimeEnd query string false "更新时间"
// @Summary 用户协议列表
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param PageNo query int true "页码"
// @Param PageSize query int true "每页数量"
// @Param Title query string false "标题"
// @Param Content query string false "协议内容"
// @Param Sort query number false "排序"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Param UpdateTimeStart query string false "更新时间"
// @Param UpdateTimeEnd query string false "更新时间"
//
// @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]UserProtocolResp}} "成功"
// @Router /api/admin/user_protocol/list [get]
// @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]UserProtocolResp}} "成功"
// @Router /api/admin/user_protocol/list [get]
func (hd *UserProtocolHandler) List(c *gin.Context) {
var page request.PageReq
var listReq UserProtocolListReq
@@ -47,18 +47,18 @@ func (hd *UserProtocolHandler) List(c *gin.Context) {
response.CheckAndRespWithData(c, res, err)
}
// @Summary 用户协议列表-所有
// @Tags user_protocol-用户协议
// @Produce json
// @Param Title query string false "标题"
// @Param Content query string false "协议内容"
// @Param Sort query number false "排序"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Param UpdateTimeStart query string false "更新时间"
// @Param UpdateTimeEnd query string false "更新时间"
// @Success 200 {object} response.Response{ data=[]UserProtocolResp} "成功"
// @Router /api/admin/user_protocol/listAll [get]
// @Summary 用户协议列表-所有
// @Tags user_protocol-用户协议
// @Produce json
// @Param Title query string false "标题"
// @Param Content query string false "协议内容"
// @Param Sort query number false "排序"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Param UpdateTimeStart query string false "更新时间"
// @Param UpdateTimeEnd query string false "更新时间"
// @Success 200 {object} response.Response{ data=[]UserProtocolResp} "成功"
// @Router /api/admin/user_protocol/listAll [get]
func (hd *UserProtocolHandler) ListAll(c *gin.Context) {
var listReq UserProtocolListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
@@ -68,13 +68,13 @@ func (hd *UserProtocolHandler) ListAll(c *gin.Context) {
response.CheckAndRespWithData(c, res, err)
}
// @Summary 用户协议详情
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Id query number false ""
// @Success 200 {object} response.Response{ data=UserProtocolResp} "成功"
// @Router /api/admin/user_protocol/detail [get]
// @Summary 用户协议详情
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Id query number false "Id"
// @Success 200 {object} response.Response{ data=UserProtocolResp} "成功"
// @Router /api/admin/user_protocol/detail [get]
func (hd *UserProtocolHandler) Detail(c *gin.Context) {
var detailReq UserProtocolDetailReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) {
@@ -88,15 +88,15 @@ func (hd *UserProtocolHandler) Detail(c *gin.Context) {
response.CheckAndRespWithData(c, res, err)
}
// @Summary 用户协议新增
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Title body string false "标题"
// @Param Content body string false "协议内容"
// @Param Sort body number false "排序"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/user_protocol/add [post]
// @Summary 用户协议新增
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Title body string false "标题"
// @Param Content body string false "协议内容"
// @Param Sort body number false "排序"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/user_protocol/add [post]
func (hd *UserProtocolHandler) Add(c *gin.Context) {
var addReq UserProtocolAddReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
@@ -106,16 +106,16 @@ func (hd *UserProtocolHandler) Add(c *gin.Context) {
response.CheckAndRespWithData(c, createId, e)
}
// @Summary 用户协议编辑
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Id body number false ""
// @Param Title body string false "标题"
// @Param Content body string false "协议内容"
// @Param Sort body number false "排序"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/user_protocol/edit [post]
// @Summary 用户协议编辑
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Id body number false "Id"
// @Param Title body string false "标题"
// @Param Content body string false "协议内容"
// @Param Sort body number false "排序"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/user_protocol/edit [post]
func (hd *UserProtocolHandler) Edit(c *gin.Context) {
var editReq UserProtocolEditReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &editReq)) {
@@ -124,13 +124,13 @@ func (hd *UserProtocolHandler) Edit(c *gin.Context) {
response.CheckAndRespWithData(c, editReq.Id, UserProtocolService.Edit(editReq))
}
// @Summary 用户协议删除
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Id body number false ""
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/user_protocol/del [post]
// @Summary 用户协议删除
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Id body number false "Id"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/user_protocol/del [post]
func (hd *UserProtocolHandler) Del(c *gin.Context) {
var delReq UserProtocolDelReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
@@ -139,14 +139,14 @@ func (hd *UserProtocolHandler) Del(c *gin.Context) {
response.CheckAndResp(c, UserProtocolService.Del(delReq.Id))
}
// @Summary 用户协议删除-批量
// @Tags user_protocol-用户协议
// @Summary 用户协议删除-批量
// @Tags user_protocol-用户协议
//
// @Produce json
// @Param Token header string true "token"
// @Param Ids body string false "逗号分割的id"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/user_protocol/delBatch [post]
// @Produce json
// @Param Token header string true "token"
// @Param Ids body string false "逗号分割的id"
// @Success 200 {object} response.Response "成功"
// @Router /api/admin/user_protocol/delBatch [post]
func (hd *UserProtocolHandler) DelBatch(c *gin.Context) {
var delReq UserProtocolDelBatchReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
@@ -161,18 +161,18 @@ func (hd *UserProtocolHandler) DelBatch(c *gin.Context) {
response.CheckAndResp(c, UserProtocolService.DelBatch(Ids))
}
// @Summary 用户协议导出
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Title query string false "标题"
// @Param Content query string false "协议内容"
// @Param Sort query number false "排序"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Param UpdateTimeStart query string false "更新时间"
// @Param UpdateTimeEnd query string false "更新时间"
// @Router /api/admin/user_protocol/ExportFile [get]
// @Summary 用户协议导出
// @Tags user_protocol-用户协议
// @Produce json
// @Param Token header string true "token"
// @Param Title query string false "标题"
// @Param Content query string false "协议内容"
// @Param Sort query number false "排序"
// @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间"
// @Param UpdateTimeStart query string false "更新时间"
// @Param UpdateTimeEnd query string false "更新时间"
// @Router /api/admin/user_protocol/ExportFile [get]
func (hd *UserProtocolHandler) ExportFile(c *gin.Context) {
var listReq UserProtocolListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
@@ -191,10 +191,10 @@ func (hd *UserProtocolHandler) ExportFile(c *gin.Context) {
excel2.DownLoadExcel("用户协议"+time.Now().Format("20060102-150405"), c.Writer, f)
}
// @Summary 用户协议导入
// @Tags user_protocol-用户协议
// @Produce json
// @Router /api/admin/user_protocol/ImportFile [post]
// @Summary 用户协议导入
// @Tags user_protocol-用户协议
// @Produce json
// @Router /api/admin/user_protocol/ImportFile [post]
func (hd *UserProtocolHandler) ImportFile(c *gin.Context) {
file, _, err := c.Request.FormFile("file")
if err != nil {

View File

@@ -6,6 +6,7 @@ import (
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"x_admin/util/convert_util"
"x_admin/util/excel2"
"gorm.io/gorm"
@@ -78,7 +79,7 @@ func (service userProtocolService) List(page request.PageReq, listReq UserProtoc
return
}
result := []UserProtocolResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
@@ -97,7 +98,7 @@ func (service userProtocolService) ListAll(listReq UserProtocolListReq) (res []U
if e = response.CheckErr(err, "查询全部失败"); e != nil {
return
}
util.ConvertUtil.Copy(&res, modelList)
convert_util.Copy(&res, modelList)
return res, nil
}
@@ -116,14 +117,14 @@ func (service userProtocolService) Detail(Id int) (res UserProtocolResp, e error
cacheUtil.SetCache(obj.Id, obj)
}
util.ConvertUtil.Copy(&res, obj)
convert_util.Copy(&res, obj)
return
}
// Add 用户协议新增
func (service userProtocolService) Add(addReq UserProtocolAddReq) (createId int, e error) {
var obj model.UserProtocol
util.ConvertUtil.StructToStruct(addReq, &obj)
convert_util.StructToStruct(addReq, &obj)
err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err)
if e != nil {
@@ -145,7 +146,7 @@ func (service userProtocolService) Edit(editReq UserProtocolEditReq) (e error) {
if e = response.CheckErr(err, "查询失败"); e != nil {
return
}
util.ConvertUtil.Copy(&obj, editReq)
convert_util.Copy(&obj, editReq)
err = service.db.Model(&obj).Select("*").Updates(obj).Error
if e = response.CheckErr(err, "编辑失败"); e != nil {
@@ -215,14 +216,14 @@ func (service userProtocolService) ExportFile(listReq UserProtocolListReq) (res
return
}
result := []UserProtocolResp{}
util.ConvertUtil.Copy(&result, modelList)
convert_util.Copy(&result, modelList)
return result, nil
}
// 导入
func (service userProtocolService) ImportFile(importReq []UserProtocolResp) (e error) {
var importData []model.UserProtocol
util.ConvertUtil.Copy(&importData, importReq)
convert_util.Copy(&importData, importReq)
err := service.db.Create(&importData).Error
e = response.CheckErr(err, "添加失败")
return e

View File

@@ -4,6 +4,7 @@ import (
"database/sql/driver"
"encoding/json"
"strconv"
"x_admin/util/convert_util"
)
// Float类型别名支持前端传递nullfloat64, string类型
@@ -13,64 +14,78 @@ type NullFloat struct {
Valid bool
}
// func EncodeFloat(value any) any {
// switch v := value.(type) {
// case map[string]any:
// if v["Float"] != nil {
// val := v["Float"]
// switch f := val.(type) {
// case *float32:
// return float64(*f)
// case *float64:
// return *f
// case *int:
// return float64(*f)
// case *int64:
// return float64(*f)
// case *string:
// return *f
// default:
// return nil
// }
// }
// }
// return nil
// }
func DecodeFloat(value any) (any, error) {
switch v := value.(type) {
case float64:
f := v
return NullFloat{Float: &f, Valid: true}, nil
case int:
f := float64(v)
return NullFloat{Float: &f, Valid: true}, nil
case int64:
f := float64(v)
return NullFloat{Float: &f, Valid: true}, nil
case string:
if v == "" {
return NullFloat{Float: nil, Valid: false}, nil
}
f, err := strconv.ParseFloat(v, 64)
return NullFloat{Float: &f, Valid: true}, err
// case float64:
// f := v
// return NullFloat{Float: &f, Valid: true}, nil
// case float32:
// f := float64(v)
// return NullFloat{Float: &f, Valid: true}, nil
// case int:
// f := float64(v)
// return NullFloat{Float: &f, Valid: true}, nil
// case int64:
// f := float64(v)
// return NullFloat{Float: &f, Valid: true}, nil
// case string:
// if v == "" {
// return NullFloat{Float: nil, Valid: false}, nil
// }
// f, err := strconv.ParseFloat(v, 64)
// return NullFloat{Float: &f, Valid: true}, err
case nil:
return NullFloat{Float: nil, Valid: false}, nil
case NullFloat:
return v, nil
default:
result, err := convert_util.ToFloat64(value)
if err != nil {
return NullFloat{Float: nil, Valid: false}, err
}
return NullFloat{Float: &result, Valid: true}, nil
}
return NullFloat{Float: nil, Valid: false}, nil
}
// gorm实现Scanner
func (f *NullFloat) Scan(value interface{}) error {
f.Valid = false
if value == nil {
return nil
result, err := convert_util.ToFloat64(value)
if err != nil {
return err
}
v := value.(float64)
f.Float, f.Valid = &v, true
f.Float, f.Valid = &result, true
return nil
// switch v := value.(type) {
// case float64:
// f.Float, f.Valid = &v, true
// case float32:
// // 直接用float64(float32(v)), 会丢失精度
// val, _ := strconv.ParseFloat(fmt.Sprintf("%f", v), 64)
// f.Float, f.Valid = &val, true
// // 匹配所有int
// case uint, uint8, uint16, uint32, uint64, int8, int16, int, int32, int64:
// val := float64(v)
// f.Float, f.Valid = &val, true
// case string:
// if v == "" {
// f.Float, f.Valid = nil, false
// return nil
// }
// val, err := strconv.ParseFloat(v, 64)
// if err != nil {
// f.Float, f.Valid = nil, false
// return err
// }
// f.Float, f.Valid = &val, true
// return err
// case nil:
// f.Float, f.Valid = nil, false
// return nil
// }
// return nil
}
// gorm实现 Valuer

View File

@@ -4,6 +4,7 @@ import (
"database/sql/driver"
"encoding/json"
"strconv"
"x_admin/util/convert_util"
)
// int类型别名支持前端传递nullintstring类型
@@ -41,23 +42,29 @@ type NullInt struct {
// }
func DecodeInt(value any) (any, error) {
switch v := value.(type) {
case int:
i := int64(v)
return NullInt{Int: &i, Valid: true}, nil
case int64:
return NullInt{Int: &v, Valid: true}, nil
case string:
if v == "" {
return NullInt{Int: nil, Valid: false}, nil
}
i, err := strconv.ParseInt(v, 10, 64)
return NullInt{Int: &i, Valid: true}, err
// case int:
// i := int64(v)
// return NullInt{Int: &i, Valid: true}, nil
// case int64:
// return NullInt{Int: &v, Valid: true}, nil
// case string:
// if v == "" {
// return NullInt{Int: nil, Valid: false}, nil
// }
// i, err := strconv.ParseInt(v, 10, 64)
// return NullInt{Int: &i, Valid: true}, err
case nil:
return NullInt{Int: nil, Valid: false}, nil
case NullInt:
return v, nil
default:
result, err := convert_util.ToInt64(value)
if err != nil {
return NullInt{Int: nil, Valid: false}, err
}
return NullInt{Int: &result, Valid: true}, nil
}
return NullInt{Int: nil, Valid: false}, nil
}
// gorm实现Scanner

View File

@@ -7,12 +7,3 @@ type PageResp struct {
PageSize int `json:"pageSize"` // 每页Size
Lists interface{} `json:"lists"` // 数据
}
// Copy 拷贝结构体
// func Copy(toValue interface{}, fromValue interface{}) interface{} {
// if err := copier.Copy(toValue, fromValue); err != nil {
// core.Logger.Errorf("Copy err: err=[%+v]", err)
// panic(SystemError)
// }
// return toValue
// }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -65,9 +65,11 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20240510055607-89e20ab7b6c6 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect

View File

@@ -114,6 +114,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20240510055607-89e20ab7b6c6 h1:YeIGErDiB/fhmNsJy0cfjoT8XnRNT9hb19xZ4MvWQDU=
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20240510055607-89e20ab7b6c6/go.mod h1:C5LA5UO2ZXJrLaPLYtE1wUJMiyd/nwWaCO5cw/2pSHs=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -125,6 +127,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.3 h1:j7a/xn1U6TKA/PHHxqZuzh64CdtRc7rU9M+AvkOl5bA=
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=

View File

@@ -12,7 +12,11 @@ type MonitorClient struct {
UserId string `gorm:"comment:'用户id'"` // 用户id
Os string `gorm:"comment:'系统'"` // 系统
Browser string `gorm:"comment:'浏览器'"` // 浏览器
Country string `gorm:"comment:'国家'"` // 国家
Province string `gorm:"comment:'省份'"` // 省份
City string `gorm:"comment:'城市'"` // 城市
Operator string `gorm:"comment:'电信运营商'"` // 电信运营商
Ip string `gorm:"comment:'ip'"` // ip
Width core.NullInt `gorm:"comment:'屏幕'"` // 屏幕
Height core.NullInt `gorm:"comment:'屏幕高度'"` // 屏幕高度
Ua string `gorm:"comment:'ua记录'"` // ua记录

View File

@@ -6,9 +6,8 @@ import (
// MonitorErrorList 错误对应的用户记录实体
type MonitorErrorList struct {
Id int `gorm:"primarykey;comment:'项目id'"` // 项目id
ErrorId string `gorm:"comment:'错误id'"` // 错误id
ClientId string `gorm:"comment:'客户端id'"` // 客户端id
ProjectKey string `gorm:"comment:'项目key'"` // 项目id
Id int `gorm:"primarykey;comment:'id'"`
Eid string `gorm:"comment:'错误id'"` // 错误id
Cid string `gorm:"comment:'客户端id'"` // 客户端id
CreateTime core.NullTime `gorm:"autoCreateTime;comment:'创建时间'"` // 创建时间
}

View File

@@ -0,0 +1,16 @@
package model
import (
"x_admin/core"
)
// MonitorSlow 监控-错误列实体
type MonitorSlow struct {
Id int `gorm:"primarykey;comment:'错误id'"` // 错误id
ProjectKey string `gorm:"comment:'项目key'"` // 项目key
ClientId string `gorm:"comment:'sdk生成的客户端id'"` // sdk生成的客户端id
UserId string `gorm:"comment:'用户id'"` // 用户id
Path string `gorm:"comment:'URL地址'"` // URL地址
Time core.NullFloat `gorm:"comment:'时间'"` // 时间
CreateTime core.NullTime `gorm:"autoCreateTime;comment:'创建时间'"` // 创建时间
}

Binary file not shown.

View File

@@ -60,6 +60,7 @@ func RegisterGroup(rg *gin.RouterGroup) {
MonitorProjectRoute(rg)
MonitorClientRoute(rg)
MonitorErrorRoute(rg)
MonitorSlowRoute(rg)
UserProtocolRoute(rg)
}

View File

@@ -45,6 +45,7 @@ INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_sh
// MonitorClientRoute(rg)
func MonitorClientRoute(rg *gin.RouterGroup) {
handle := monitor_client.MonitorClientHandler{}
rg.GET("/monitor_client/add", middleware.RecordLog("监控-客户端信息新增"), handle.Add)
r := rg.Group("/", middleware.TokenAuth())
r.GET("/monitor_client/list", handle.List)
@@ -52,7 +53,6 @@ func MonitorClientRoute(rg *gin.RouterGroup) {
r.GET("/monitor_client/detail", handle.Detail)
r.GET("/monitor_client/errorUsers", handle.ErrorUsers)
r.POST("/monitor_client/add", middleware.RecordLog("监控-客户端信息新增"), handle.Add)
// r.POST("/monitor_client/edit",middleware.RecordLog("监控-客户端信息编辑"), handle.Edit)
r.POST("/monitor_client/del", middleware.RecordLog("监控-客户端信息删除"), handle.Del)

View File

@@ -45,14 +45,13 @@ INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_sh
// MonitorErrorRoute(rg)
func MonitorErrorRoute(rg *gin.RouterGroup) {
handle := monitor_error.MonitorErrorHandler{}
rg.GET("/monitor_error/add", middleware.RecordLog("监控-错误列新增"), handle.Add)
r := rg.Group("/", middleware.TokenAuth())
r.GET("/monitor_error/list", handle.List)
r.GET("/monitor_error/listAll", handle.ListAll)
r.GET("/monitor_error/detail", handle.Detail)
r.POST("/monitor_error/add", middleware.RecordLog("监控-错误列新增"), handle.Add)
r.POST("/monitor_error/del", middleware.RecordLog("监控-错误列删除"), handle.Del)
r.POST("/monitor_error/delBatch", middleware.RecordLog("监控-错误列删除-批量"), handle.DelBatch)

View File

@@ -0,0 +1,59 @@
package admin
import (
"x_admin/admin/monitor_slow"
"x_admin/middleware"
"github.com/gin-gonic/gin"
)
/**
集成
1. 导入
- 请先提交git避免文件覆盖!!!
- 下载并解压压缩包后直接复制server、admin文件夹到项目根目录即可
2. 注册路由
请在 router/admin/entry.go 文件引入 MonitorSlowRoute 注册路由
3. 后台手动添加菜单和按钮
admin:monitor_slow:add
admin:monitor_slow:edit
admin:monitor_slow:del
admin:monitor_slow:delBatch
admin:monitor_slow:list
admin:monitor_slow:listAll
admin:monitor_slow:detail
admin:monitor_slow:ExportFile
admin:monitor_slow:ImportFile
// 列表-先添加菜单获取菜单id
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, paths, component, is_cache, is_show, is_disable, create_time, update_time) VALUES (0, 'C', '慢接口', 'monitor/slow/index', 'monitor/slow/index', 0, 1, 0, now(), now());
按钮-替换pid参数为菜单id
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (834, 'A', '慢接口添加','admin:monitor_slow:add', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (834, 'A', '慢接口编辑','admin:monitor_slow:edit', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (834, 'A', '慢接口删除','admin:monitor_slow:del', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (834, 'A', '慢接口删除-批量','admin:monitor_slow:delBatch', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (834, 'A', '慢接口列表','admin:monitor_slow:list', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (834, 'A', '慢接口全部列表','admin:monitor_slow:listAll', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (834, 'A', '慢接口详情','admin:monitor_slow:detail', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (834, 'A', '慢接口导出excel','admin:monitor_slow:ExportFile', 0, 1, 0, now(), now());
INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_show, is_disable, create_time, update_time) VALUES (834, 'A', '慢接口导入excel','admin:monitor_slow:ImportFile', 0, 1, 0, now(), now());
*/
// MonitorSlowRoute(rg)
func MonitorSlowRoute(rg *gin.RouterGroup) {
handle := monitor_slow.MonitorSlowHandler{}
rg.GET("/monitor_slow/add", middleware.RecordLog("慢接口新增"), handle.Add)
r := rg.Group("/", middleware.TokenAuth())
r.GET("/monitor_slow/list", handle.List)
r.GET("/monitor_slow/listAll", handle.ListAll)
r.GET("/monitor_slow/detail", handle.Detail)
r.POST("/monitor_slow/del", middleware.RecordLog("慢接口删除"), handle.Del)
r.POST("/monitor_slow/delBatch", middleware.RecordLog("慢接口删除-批量"), handle.DelBatch)
r.GET("/monitor_slow/ExportFile", middleware.RecordLog("慢接口导出"), handle.ExportFile)
// r.POST("/monitor_slow/ImportFile", handle.ImportFile)
}

View File

@@ -52,16 +52,23 @@ func (c CacheUtil) GetCache(key interface{}, obj interface{}) error {
return nil
}
// 删除缓存
// 删除缓存-支持批量删除
func (c CacheUtil) RemoveCache(key interface{}) bool {
var cacheKey string
var cacheKey []string
switch k := key.(type) {
case int:
cacheKey = strconv.Itoa(k)
cacheKey = append(cacheKey, strconv.Itoa(k))
case string:
cacheKey = append(cacheKey, k)
// 判断是slice
case []int:
for _, v := range k {
cacheKey = append(cacheKey, strconv.Itoa(v))
}
case []string:
cacheKey = k
default:
return false
}
return RedisUtil.HDel(c.Name, cacheKey)
return RedisUtil.HDel(c.Name, cacheKey...)
}

View File

@@ -9,7 +9,7 @@ import (
var ConfigUtil = configUtil{}
// convertUtil 数据库配置操作工具
// 数据库配置操作工具
type configUtil struct{}
// Get 根据类型和名称获取配置字典

View File

@@ -2,7 +2,6 @@ package util
import (
"reflect"
"x_admin/core"
"github.com/fatih/structs"
"github.com/jinzhu/copier"
@@ -28,7 +27,7 @@ func (c convertUtil) StructsToMaps(from interface{}) (data []map[string]interfac
var objList []interface{}
err := copier.Copy(&objList, from)
if err != nil {
core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err)
// core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err)
return nil
}
for _, v := range objList {
@@ -57,7 +56,7 @@ func (c convertUtil) ShallowStructsToMaps(from interface{}) (data []map[string]i
var objList []interface{}
err := copier.Copy(&objList, from)
if err != nil {
core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err)
// core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err)
return nil
}
for _, v := range objList {
@@ -82,7 +81,7 @@ func (c convertUtil) StructToStruct(from interface{}, to interface{}) (err error
func (c convertUtil) Copy(toValue interface{}, fromValue interface{}) interface{} {
if err := copier.Copy(toValue, fromValue); err != nil {
core.Logger.Errorf("Copy err: err=[%+v]", err)
// core.Logger.Errorf("Copy err: err=[%+v]", err)
panic("SystemError")
}
return toValue

View File

@@ -0,0 +1,100 @@
package convert_util
import (
"fmt"
"strconv"
"reflect"
"github.com/duke-git/lancet/v2/convertor"
"github.com/fatih/structs"
"github.com/jinzhu/copier"
"github.com/mitchellh/mapstructure"
)
func ToFloat64(value interface{}) (float64, error) {
switch v := value.(type) {
case float32:
return strconv.ParseFloat(fmt.Sprintf("%f", v), 64)
default:
return convertor.ToFloat(value)
}
}
func ToInt64(value interface{}) (int64, error) {
return convertor.ToInt(value)
}
// StructToMap 结构体转换成map,深度转换
func StructToMap(from interface{}) map[string]interface{} {
// var m = map[string]interface{}{}
// mapstructure.Decode(from, &m) //深度转换所有结构体
m := structs.Map(from) // 需要tag:structs深度转换
return m
}
// StructsToMaps 将结构体转换成Map列表
func StructsToMaps(from interface{}) (data []map[string]interface{}) {
var objList []interface{}
err := copier.Copy(&objList, from)
if err != nil {
// core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err)
return nil
}
for _, v := range objList {
data = append(data, StructToMap(v))
}
return data
}
// ShallowStructToMap 将结构体转换成map,浅转换
func ShallowStructToMap(from interface{}) map[string]interface{} {
m := make(map[string]interface{})
v := reflect.ValueOf(from)
t := v.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i).Interface()
m[field.Name] = value
}
return m
}
// ShallowStructsToMaps 将结构体列表转换成Map列表,浅转换
func ShallowStructsToMaps(from interface{}) (data []map[string]interface{}) {
var objList []interface{}
err := copier.Copy(&objList, from)
if err != nil {
// core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err)
return nil
}
for _, v := range objList {
data = append(data, ShallowStructToMap(v))
}
return data
}
// MapToStruct 将map弱类型转换成结构体
func MapToStruct(from interface{}, to interface{}) (err error) {
err = mapstructure.WeakDecode(from, to) // 需要tag:mapstructure
return err
}
// StructToStruct 将结构体from弱类型转换成结构体to
func StructToStruct(from interface{}, to interface{}) (err error) {
m := StructToMap(from)
err = MapToStruct(m, to)
return err
}
func Copy(toValue interface{}, fromValue interface{}) interface{} {
if err := copier.Copy(toValue, fromValue); err != nil {
// core.Logger.Errorf("Copy err: err=[%+v]", err)
panic("SystemError")
}
return toValue
}

View File

@@ -2,7 +2,7 @@ package excel2
import (
"fmt"
"x_admin/util"
"x_admin/util/convert_util"
"github.com/xuri/excelize/v2"
)
@@ -26,7 +26,7 @@ func GetExcelColumnName(columnNumber int) string {
func Export(lists any, cols []Col, sheet string, title string) (file *excelize.File, err error) {
e := ExcelInit()
data := util.ConvertUtil.ShallowStructsToMaps(lists)
data := convert_util.ShallowStructsToMaps(lists)
err = ExportExcel(sheet, title, data, cols, e)
if err != nil {

View File

@@ -6,7 +6,7 @@ import (
"fmt"
"io"
"mime/multipart"
"x_admin/util"
"x_admin/util/convert_util"
"github.com/xuri/excelize/v2"
)
@@ -99,7 +99,7 @@ func importData(f *excelize.File, dst interface{}, sheetName string, startRow in
data = append(data, rowMap)
}
util.ConvertUtil.MapToStruct(data, dst)
convert_util.MapToStruct(data, dst)
// fmt.Println("Type.Name:", field.Type.Name(), field.Type.Kind())
// // 根据字段类型设置值

View 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
}

View File

@@ -1,23 +1,83 @@
package util
import (
"fmt"
"net"
"x_admin/core"
"strings"
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
)
var IpUtil = ipUtil{}
var IpUtil = initIpUtil()
// serverUtil IP工具类
type ipUtil struct{}
type ipUtil struct {
Searcher *xdb.Searcher
}
// GetHostIp 获取本地主机名
func (su ipUtil) GetHostIp() (ip string) {
conn, err := net.Dial("udp", "114.114.114.114:80")
if err != nil {
core.Logger.Errorf("GetHostIp Dial err: err=[%+v]", err)
// core.Logger.Errorf("GetHostIp Dial err: err=[%+v]", err)
return
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP.String()
}
type Region struct {
Country string
Province string
City string
Operator string
}
func (ipUtils *ipUtil) Parse(ip string) Region {
if ip == "" {
fmt.Println("输入ip为空")
return Region{}
}
region, err := ipUtils.Searcher.SearchByStr(ip)
if err != nil {
fmt.Printf("解析ip(%s)错误: %s\n", ip, err)
return Region{}
}
// 中国|0|四川省|成都市|电信
parts := strings.Split(region, "|")
if len(parts) != 5 {
fmt.Println("解析ip返回错误")
return Region{}
}
country := parts[0]
province := parts[2]
city := parts[3]
operator := parts[4]
regionInfo := Region{Country: country, Province: province, City: city, Operator: operator}
fmt.Println(regionInfo)
return regionInfo
}
func initIpUtil() *ipUtil {
ip_util := ipUtil{}
var dbPath = "resources/ip/ip2region.xdb"
// 创建完全基于内存的查询对象。
cBuff, err := xdb.LoadContentFromFile(dbPath)
if err != nil {
fmt.Printf("failed to load content from `%s`: %s\n", dbPath, err)
return &ip_util
}
// 并发使用,用整个 xdb 缓存创建的 searcher 对象可以安全用于并发。
searcher, err := xdb.NewWithBuffer(cBuff)
if err != nil {
fmt.Printf("failed to create searcher: %s\n", err.Error())
return &ip_util
}
fmt.Printf("创建完全基于内存的查询对象。")
ip_util.Searcher = searcher
return &ip_util
}

16
x_err_sdk/.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
pnpm-lock.yaml
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local

26
x_err_sdk/package.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "@adtkcn/x_err_sdk",
"version": "1.0.0",
"description": "错误监控sdk",
"main": "dist/web/XErr.umd.js",
"private": false,
"file": [
"dist"
],
"scripts": {
"build": "vite build&&npm run build:ts",
"build:ts": "tsc --emitDeclarationOnly",
"outdated": "pnpm outdated"
},
"keywords": [
"x_err_sdk",
"X_admin"
],
"author": "adtkcn",
"license": "ISC",
"devDependencies": {
"typescript": "^5.6.3",
"uuid": "^11.0.2",
"vite": "^5.4.10"
}
}

15
x_err_sdk/tsconfig.json Normal file
View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"declaration": true, // 生成声明文件,开启后会自动生成声明文件
"target": "esnext", // 最新的ES标准
"lib": [
"esnext",
"dom"
], // TS需要引用的库即声明文件es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性通常都需要配置如es8的数组新特性需要引入"ES2019.Array"
"strict": true, // 开启所有严格的类型检查
"noImplicitAny": true, // 不允许隐式的any类型
"esModuleInterop": true, // 允许export=导出由import from 导入
"moduleResolution": "node", // 模块解析策略ts默认用node的解析策略即相对的方式导入
"outDir": "dist" // 指定输出目录
}
}

33
x_err_sdk/types.ts Normal file
View File

@@ -0,0 +1,33 @@
export type LogWithEnv = {
Type: "env";
ScreenHeight?: number;
ScreenWidth?: number;
};
export type LogWithError = {
Type: "error"|"event"|"resources"|'click';
EventType: string;
Path:string;
Message?: string;
Stack?: string;
};
export type ISlow = {
Type: "onloadTime"
Path:string;
Time: number;
};
// 扩展必须实现的接口
export interface IErrorEvent {
upload(url: string, data: object): Promise<void>;
setCache(key: string, info: any): void;
getCache(key: string): any;
delCache(key: string): void;
getEnvInfo(): LogWithEnv;
listen(callback: ListenCallbackFn): void;
unListen(): void;
}
export type ListenCallbackFn = (params: LogWithError|ISlow) => void;

21
x_err_sdk/vite.config.js Normal file
View 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'
}
}
}
}
})

175
x_err_sdk/web/base.ts Normal file
View File

@@ -0,0 +1,175 @@
import { v1 as uuid_v1 } from "uuid";
import type { LogWithError, IErrorEvent,ISlow, LogWithEnv } from "../types";
type Uid = string | number;
type Props = {
Dns: string; // 域名
Pid: string; // 项目标识
Uid?: Uid; //用户标识
};
class Base {
private Dns: string = "";
private client_id: string = "";
private Pid: string = "";
private Uid: Uid = "";
private platform: IErrorEvent | null = null;
private MessageList: any[] = [];
private timer: number = 0;
constructor(props: Props, platform: IErrorEvent) {
if (!props) {
console.error("props is null");
return;
}
if (!platform) {
console.error("platform is null");
return;
}
this.platform = platform;
if (props.Dns && props.Pid) {
this.Dns = props.Dns;
this.Pid = props.Pid;
} else {
console.error("props.Dns and props.Pid cannot be null");
return;
}
if (props.Uid) {
this.Uid = String(props.Uid);
}
this.setClientID();
this.SetUid();
this.getLocalMessage();
// 监听错误
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.timer = setInterval(() => {
this.upload();
}, 1000 * 10);
}
// 设置用户id
public SetUid(uid?: Uid) {
if (uid) {
this.Uid =String(uid) ;
this.platform?.setCache("x_err_uid", this.Uid);
} else {
const u_id = this.platform?.getCache("x_err_uid");
if (u_id) {
this.Uid = u_id;
}
}
this.initEnv();
}
// 初始化环境信息并上传
private initEnv() {
let envInfo = this.platform?.getEnvInfo();
if (envInfo) {
this.uploadInfo(envInfo);
}
}
// 设置错误ID
private setClientID() {
const client_id = this.platform?.getCache("x_err_client_id");
if (client_id) {
this.client_id = client_id;
} else {
this.client_id = uuid_v1();
this.platform?.setCache("x_err_client_id", this.client_id);
}
}
// 获取本地缓存消息
private getLocalMessage() {
let x_err_message_list = this.platform?.getCache("x_err_message_list");
if (x_err_message_list) {
this.MessageList = x_err_message_list;
} else {
this.MessageList = [];
}
}
// 记录错误超出5条时立即上报否则缓存到本地(等待定时器上报)
public Push=(data: LogWithError) =>{
this.MessageList.push({
...data,
ProjectKey: this.Pid,
ClientId: this.client_id,
});
if (this.MessageList.length > 5) {
this.upload(); //上传
} else {
this.platform?.setCache("x_err_message_list", this.MessageList);
}
}
public uploadInfo=(envInfo: LogWithEnv) =>{
if (!this.Dns) return; //未设置Dns服务器不上传
try {
this.platform
?.upload(this.Dns + `/admin/monitor_client/add`, {
ProjectKey: this.Pid,
ClientId: this.client_id,
UserId: this.Uid,
Width: envInfo.ScreenWidth,
Height: envInfo.ScreenHeight,
})
.catch((err: any) => {
// 上传失败
});
} 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() {
if (!this.Dns) return; //未设置Dns服务器不上传
if (!this.MessageList.length) {
return;
}
try {
this.platform
?.upload(this.Dns + `/admin/monitor_error/add`, this.MessageList)
.catch((err: any) => {
// 上传失败
});
this.MessageList = [];
this.platform?.delCache("x_err_message_list");
} catch (error) {}
}
public unListen() {
clearInterval(this.timer);
this.platform?.unListen();
}
}
export default Base;

4
x_err_sdk/web/index.ts Normal file
View File

@@ -0,0 +1,4 @@
import Base from "./base";
import Web from "./web";
export { Base, Web };

179
x_err_sdk/web/web.ts Normal file
View File

@@ -0,0 +1,179 @@
import type {
LogWithError,
LogWithEnv,
ListenCallbackFn,
IErrorEvent,ISlow
} from "../types";
interface LoggerProps {
// timeout:number
onloadTimeOut?: number;
}
class Web implements IErrorEvent {
props: LoggerProps;
constructor(props?: LoggerProps) {
this.props = {
onloadTimeOut: 5000,
...props,
};
}
public upload(url: string, data: any): Promise<void> {
return new Promise((resolve) => {
try {
let h = new Image();
h.onload = function (event) {
var e = event as Event;
e.preventDefault();
};
h.onerror = function () {};
h.src = url + "?data=" + encodeURIComponent(JSON.stringify(data));
resolve();
} catch (error) {
resolve();
}
});
}
public setCache(key: string, info: any): void {
localStorage.setItem(key, JSON.stringify(info));
}
public getCache(key: string): any {
try {
let list = localStorage.getItem(key);
if (list) {
return JSON.parse(list);
} else {
return null;
}
} catch (error) {
return null;
}
}
public delCache(key: string): void {
localStorage.removeItem(key);
}
public getEnvInfo(): LogWithEnv {
const env: LogWithEnv = {
Type: "env",
ScreenHeight: 0,
ScreenWidth: 0,
};
if (window) {
env.ScreenHeight = window.innerHeight || 0; // 获取显示屏信息
env.ScreenWidth = window.innerWidth || 0;
}
return env;
}
private callback(err: LogWithError|ISlow): void {}
private listenError = (err: any) => {
console.error([err]);
let target = err.target;
if (target?.localName) {
if (target?.localName === "img" || target?.localName === "script") {
this.callback({
Type: "resources",
EventType: target?.localName,
Path: target.src,
Message: "",
Stack: "",
});
} else if (target?.localName === "link") {
this.callback({
Type: "resources",
EventType: target?.localName,
Path: target.href,
});
}
} else {
this.callback({
Type: "error",
EventType: err.type,
Path: window.location.href,
Message: err.message,
Stack: this.handleStack(err.error?.stack || ""),
});
}
};
private unhandledrejection = (err: any): void => {
console.error(err);
if (err && typeof err.reason === "string") {
this.callback({
Type: "error",
EventType: err.type,
Path: window.location.href,
Message: err.reason,
Stack: "",
});
} else if (err && typeof err.reason === "object") {
this.callback({
Type: "error",
EventType: err.type,
Path: window.location.href,
Message: err.reason?.message || "",
Stack: this.handleStack(err.reason?.stack || ""),
});
}
};
private handleStack(stack: string): string {
let newStack: string[] = [];
if (stack) {
stack.split("\n").map((item, index) => {
if (index < 4) {
newStack.push(item);
}
});
}
return newStack.join("\n");
}
private onLoad = () => {
// 获取性能数据
const entries = performance.getEntriesByType("navigation");
if (entries.length > 0) {
const performanceData = entries[0] as PerformanceNavigationTiming;
console.log("performanceData", performanceData);
// 计算页面onload时间
let onloadTime =
performanceData.loadEventStart - performanceData.startTime;
if (
this.props.onloadTimeOut &&
onloadTime > this.props.onloadTimeOut
) {
// 页面加载时间5s以上
this.callback({
Type: "onloadTime",
Path: window.location.href,
Time:onloadTime
});
}
}
};
public listen(callback: ListenCallbackFn): void {
this.callback = callback;
window.addEventListener("unhandledrejection", this.unhandledrejection);
window.addEventListener("error", this.listenError, true);
// window.addEventListener("click", this.listenClick);
// window.addEventListener("hashchange", this.listenHashRouterChange);
// window.addEventListener("popstate", this.listenHistoryRouterChange);
window.addEventListener("load", this.onLoad);
}
public unListen(): void {
this.callback = () => {};
window.removeEventListener("error", this.listenError);
window.removeEventListener("unhandledrejection", this.unhandledrejection);
// window.removeEventListener("click", this.listenClick);
// window.removeEventListener("hashchange", this.listenHashRouterChange);
// window.removeEventListener("popstate", this.listenHistoryRouterChange);
}
}
export default Web;