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; padding: 0;
} }
</style> </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" /> <link rel="stylesheet" href="/src/styles/loading.css" />
</head> </head>
<body> <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 UserId?: string
Os?: string Os?: string
Browser?: string Browser?: string
Country?: string
Province?: string
City?: string City?: string
Operator?: string
Ip?: string
Width?: number Width?: number
Height?: number Height?: number
Ua?: string Ua?: string
@@ -26,14 +30,16 @@ export type type_monitor_client_query = {
UserId?: string UserId?: string
Os?: string Os?: string
Browser?: string Browser?: string
Country?: string
Province?: string
City?: string City?: string
Operator?: string
Ip?: string
Width?: number Width?: number
Height?: number Height?: number
Ua?: string Ua?: string
CreateTimeStart?: string CreateTimeStart?: string
CreateTimeEnd?: string CreateTimeEnd?: string
ClientTimeStart?: string
ClientTimeEnd?: string
} }
// 添加编辑 // 添加编辑
export type type_monitor_client_edit = { export type type_monitor_client_edit = {
@@ -43,7 +49,11 @@ export type type_monitor_client_edit = {
UserId?: string UserId?: string
Os?: string Os?: string
Browser?: string Browser?: string
Country?: string
Province?: string
City?: string City?: string
Operator?: string
Ip?: string
Width?: number Width?: number
Height?: number Height?: number
Ua?: string 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> <template>
<div> <template v-for="(item, index) in getOptions" :key="index">
<template v-for="(item, index) in getOptions" :key="index"> <span :style="{ color: item.color }"
<span :style="{ color: item.color }" >{{ index != 0 ? '、' : '' }}{{ item[props.labelKey] }}</span
>{{ index != 0 ? '、' : '' }}{{ item[props.labelKey] }}</span >
> </template>
</template>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, withDefaults } from 'vue' import { computed } from 'vue'
defineOptions({ defineOptions({
name: 'dict-value' name: 'dict-value'
}) })

View File

@@ -29,7 +29,7 @@ import type { IEditorConfig, IToolbarConfig } from '@wangeditor/editor'
import MaterialPicker from '@/components/material/picker.vue' import MaterialPicker from '@/components/material/picker.vue'
import { addUnit } from '@/utils/util' 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' import type { CSSProperties } from 'vue'
const props = withDefaults( 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> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, withDefaults } from 'vue' import { ref } from 'vue'
import { computed, nextTick, onMounted, reactive, shallowRef, watch } from 'vue' import { computed, nextTick, onMounted, reactive, shallowRef, watch } from 'vue'
import { useEventListener } from '@vueuse/core' import { useEventListener } from '@vueuse/core'
import { ElInput } from 'element-plus' import { ElInput } from 'element-plus'

View File

@@ -11,6 +11,19 @@ import ElementPlus from 'element-plus'
import VForm3 from 'vform3-builds' //引入VForm3库 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) const app = createApp(App)
app.use(install) app.use(install)
app.use(ElementPlus) app.use(ElementPlus)

View File

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

View File

@@ -35,11 +35,15 @@
<div class="flex-1 overflow-auto"> <div class="flex-1 overflow-auto">
<div style="height: calc(100vh - 200px)"> <div style="height: calc(100vh - 200px)">
<highlightjs <highlight-code
:code="showItem.value"
lang="javascript"
></highlight-code>
<!-- <highlightjs
autodetect autodetect
:code="showItem.value" :code="showItem.value"
language="javascript" language="javascript"
/> /> -->
</div> </div>
</div> </div>
</div> </div>
@@ -66,17 +70,17 @@ import { onMounted, ref, computed } from 'vue'
import feedback from '@/utils/feedback' import feedback from '@/utils/feedback'
import useClipboard from 'vue-clipboard3' import useClipboard from 'vue-clipboard3'
import 'highlight.js/styles/monokai.min.css' // import 'highlight.js/styles/monokai.min.css'
import hljs from 'highlight.js/lib/common' // import hljs from 'highlight.js/lib/common'
import javascript from 'highlight.js/lib/languages/javascript' // import javascript from 'highlight.js/lib/languages/javascript'
import go from 'highlight.js/lib/languages/go' // import go from 'highlight.js/lib/languages/go'
// Then register the languages you need // Then register the languages you need
hljs.registerLanguage('javascript', javascript) // hljs.registerLanguage('javascript', javascript)
hljs.registerLanguage('go', go) // hljs.registerLanguage('go', go)
import hljsVuePlugin from '@highlightjs/vue-plugin' // import hljsVuePlugin from '@highlightjs/vue-plugin'
const highlightjs = hljsVuePlugin.component // const highlightjs = hljsVuePlugin.component
const props = defineProps<{ const props = defineProps<{
modelValue: boolean 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> </div>
</template> </template>
<script lang="ts" setup> <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_apply_detail } from '@/api/flow/flow_apply'
import { flow_history_list, flow_history_edit } from '@/api/flow/flow_history' import { flow_history_list, flow_history_edit } from '@/api/flow/flow_history'
import type { type_flow_history } 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> <script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router' 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 type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback' import feedback from '@/utils/feedback'
import { noticeDetail, setNoticeConfig } from '@/api/message' import { noticeDetail, setNoticeConfig } from '@/api/message'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,14 +4,14 @@
ref="popupRef" ref="popupRef"
:title="popupTitle" :title="popupTitle"
:async="true" :async="true"
width="550px" width="700px"
:clickModalClose="true" :clickModalClose="true"
@confirm="handleSubmit" @confirm="handleSubmit"
@close="handleClose" @close="handleClose"
> >
<el-form ref="formRef" :model="formData" label-width="84px" :rules="formRules"> <el-form ref="formRef" :model="formData" label-width="84px" :rules="formRules">
<el-form-item label="项目uuid" prop="ProjectKey"> <el-form-item label="项目uuid" prop="ProjectKey" v-if="mode === 'edit'">
<el-input v-model="formData.ProjectKey" placeholder="请输入项目uuid" /> {{ formData.ProjectKey }}
</el-form-item> </el-form-item>
<el-form-item label="项目名称" prop="ProjectName"> <el-form-item label="项目名称" prop="ProjectName">
<el-input v-model="formData.ProjectName" placeholder="请输入项目名称" /> <el-input v-model="formData.ProjectName" placeholder="请输入项目名称" />
@@ -48,6 +48,9 @@
/> />
</el-select> </el-select>
</el-form-item> </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> </el-form>
</popup> </popup>
</div> </div>
@@ -73,6 +76,7 @@ defineProps({
default: () => ({}) default: () => ({})
} }
}) })
const emit = defineEmits(['success', 'close']) const emit = defineEmits(['success', 'close'])
const formRef = shallowRef<FormInstance>() const formRef = shallowRef<FormInstance>()
const popupRef = shallowRef<InstanceType<typeof Popup>>() const popupRef = shallowRef<InstanceType<typeof Popup>>()
@@ -88,7 +92,19 @@ const formData = reactive({
ProjectType: null, ProjectType: null,
Status: 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 = { const formRules = {
Id: [ Id: [
{ {

View File

@@ -37,13 +37,13 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="创建时间" prop="CreateTime" class="w-[280px]"> <el-form-item label="创建时间" prop="CreateTime" class="w-[430px]">
<daterange-picker <daterange-picker
v-model:startTime="queryParams.CreateTimeStart" v-model:startTime="queryParams.CreateTimeStart"
v-model:endTime="queryParams.CreateTimeEnd" v-model:endTime="queryParams.CreateTimeEnd"
/> />
</el-form-item> </el-form-item>
<el-form-item label="更新时间" prop="UpdateTime" class="w-[280px]"> <el-form-item label="更新时间" prop="UpdateTime" class="w-[420px]">
<daterange-picker <daterange-picker
v-model:startTime="queryParams.UpdateTimeStart" v-model:startTime="queryParams.UpdateTimeStart"
v-model:endTime="queryParams.UpdateTimeEnd" 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'] include: ['@wangeditor/editor-for-vue', 'vuedraggable', 'vue-echarts', 'crypto-js']
}, },
base: '/', base: '/',
build: { build: {
sourcemap: true, sourcemap: true,
rollupOptions: { rollupOptions: {
external: ['XErr'],
output: { output: {
manualChunks: { manualChunks: {
vue: ['vue'], vue: ['vue'],

View File

@@ -4,8 +4,13 @@
## 前端页面使用history模式需要重定向 ## 前端页面使用history模式需要重定向
```nginx ```nginx
location / { location / {
index /index.html; index /index.html;
try_files $uri $uri/ /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": ".workflow"
},
{
"path": "x_err_sdk"
} }
], ],
"settings": { "settings": {

View File

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

View File

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

View File

@@ -8,14 +8,6 @@ import (
) )
func IndexRoute(rg *gin.RouterGroup) { 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{} handle := indexHandler{}
rg = rg.Group("/common", middleware.TokenAuth()) rg = rg.Group("/common", middleware.TokenAuth())

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,19 +26,17 @@ admin:{{{.ModuleName }}}:detail
admin:{{{.ModuleName }}}:ExportFile admin:{{{.ModuleName }}}:ExportFile
admin:{{{.ModuleName }}}:ImportFile 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()); 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) SELECT id, 'A', '{{{ .FunctionName }}}导入excel','admin:{{{ .ModuleName }}}:ImportFile', 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) 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());
*/ */

View File

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

View File

@@ -173,7 +173,7 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <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 { {{{ .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 }}}"; import type { type_{{{ .ModuleName }}},type_{{{.ModuleName}}}_query } from "@/api/{{{nameToPath .ModuleName }}}";

View File

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

View File

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

View File

@@ -1,11 +1,13 @@
package monitor_client package monitor_client
import ( import (
"errors"
"x_admin/core" "x_admin/core"
"x_admin/core/request" "x_admin/core/request"
"x_admin/core/response" "x_admin/core/response"
"x_admin/model" "x_admin/model"
"x_admin/util" "x_admin/util"
"x_admin/util/convert_util"
"x_admin/util/excel2" "x_admin/util/excel2"
"gorm.io/gorm" "gorm.io/gorm"
@@ -49,9 +51,21 @@ func (service monitorClientService) GetModel(listReq MonitorClientListReq) *gorm
if listReq.Browser != nil { if listReq.Browser != nil {
dbModel = dbModel.Where("browser = ?", *listReq.Browser) 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 { if listReq.City != nil {
dbModel = dbModel.Where("city = ?", *listReq.City) 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 { if listReq.Width != nil {
dbModel = dbModel.Where("width = ?", *listReq.Width) dbModel = dbModel.Where("width = ?", *listReq.Width)
} }
@@ -90,35 +104,7 @@ func (service monitorClientService) List(page request.PageReq, listReq MonitorCl
return return
} }
result := []MonitorClientResp{} result := []MonitorClientResp{}
util.ConvertUtil.Copy(&result, modelList) convert_util.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)
return response.PageResp{ return response.PageResp{
PageNo: page.PageNo, PageNo: page.PageNo,
PageSize: page.PageSize, PageSize: page.PageSize,
@@ -137,10 +123,32 @@ func (service monitorClientService) ListAll(listReq MonitorClientListReq) (res [
if e = response.CheckErr(err, "查询全部失败"); e != nil { if e = response.CheckErr(err, "查询全部失败"); e != nil {
return return
} }
util.ConvertUtil.Copy(&res, modelList) convert_util.Copy(&res, modelList)
return res, nil 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 监控-客户端信息详情 // Detail 监控-客户端信息详情
func (service monitorClientService) Detail(Id int) (res MonitorClientResp, e error) { func (service monitorClientService) Detail(Id int) (res MonitorClientResp, e error) {
var obj = model.MonitorClient{} var obj = model.MonitorClient{}
@@ -154,65 +162,37 @@ func (service monitorClientService) Detail(Id int) (res MonitorClientResp, e err
return return
} }
cacheUtil.SetCache(obj.Id, obj) cacheUtil.SetCache(obj.Id, obj)
cacheUtil.SetCache("ClientId:"+obj.ClientId, obj)
} }
util.ConvertUtil.Copy(&res, obj) convert_util.Copy(&res, obj)
return return
} }
// ErrorUser 监控-客户端信息详情 // ErrorUser 监控-客户端信息详情
func (service monitorClientService) ErrorUsers(error_id int) (res []MonitorClientResp, e error) { func (service monitorClientService) ErrorUsers(error_id int) (res []MonitorClientResp, e error) {
var obj = []model.MonitorClient{} 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 { convert_util.Copy(&res, obj)
// return
// }
// if e = response.CheckErr(err, "获取失败"); e != nil {
// return
// }
// cacheUtil.SetCache(obj.Id, obj)
util.ConvertUtil.Copy(&res, obj)
return return
} }
// Add 监控-客户端信息新增 // Add 监控-客户端信息新增
func (service monitorClientService) Add(addReq MonitorClientAddReq) (createId int, e error) { func (service monitorClientService) Add(addReq MonitorClientAddReq) (createId int, e error) {
var obj model.MonitorClient var obj model.MonitorClient
util.ConvertUtil.StructToStruct(addReq, &obj) convert_util.StructToStruct(addReq, &obj)
err := service.db.Create(&obj).Error err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err) e = response.CheckMysqlErr(err)
if e != nil { if e != nil {
return 0, e return 0, e
} }
cacheUtil.SetCache(obj.Id, obj) cacheUtil.SetCache(obj.Id, obj)
cacheUtil.SetCache("ClientId:"+obj.ClientId, obj)
createId = obj.Id createId = obj.Id
return 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 监控-客户端信息删除 // Del 监控-客户端信息删除
func (service monitorClientService) Del(Id int) (e error) { func (service monitorClientService) Del(Id int) (e error) {
var obj model.MonitorClient var obj model.MonitorClient
@@ -228,20 +208,34 @@ func (service monitorClientService) Del(Id int) (e error) {
err = service.db.Delete(&obj).Error err = service.db.Delete(&obj).Error
e = response.CheckErr(err, "删除失败") e = response.CheckErr(err, "删除失败")
cacheUtil.RemoveCache(obj.Id) cacheUtil.RemoveCache(obj.Id)
cacheUtil.RemoveCache("ClientId:" + obj.ClientId)
return return
} }
// DelBatch 用户协议-批量删除 // DelBatch 用户协议-批量删除
func (service monitorClientService) DelBatch(Ids []string) (e error) { func (service monitorClientService) DelBatch(Ids []string) (e error) {
var obj model.MonitorClient var obj []model.MonitorClient
err := service.db.Where("id in (?)", Ids).Delete(&obj).Error // 查询Ids对应的数据
err := service.db.Where("id in (?)", Ids).Find(&obj).Error
if err != nil { if err != nil {
return err return err
} }
// 删除缓存 if len(obj) == 0 {
for _, v := range Ids { return errors.New("数据不存在")
cacheUtil.RemoveCache(v)
} }
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 return nil
} }
@@ -275,14 +269,14 @@ func (service monitorClientService) ExportFile(listReq MonitorClientListReq) (re
return return
} }
result := []MonitorClientResp{} result := []MonitorClientResp{}
util.ConvertUtil.Copy(&result, modelList) convert_util.Copy(&result, modelList)
return result, nil return result, nil
} }
// 导入 // 导入
func (service monitorClientService) ImportFile(importReq []MonitorClientResp) (e error) { func (service monitorClientService) ImportFile(importReq []MonitorClientResp) (e error) {
var importData []model.MonitorClient var importData []model.MonitorClient
util.ConvertUtil.Copy(&importData, importReq) convert_util.Copy(&importData, importReq)
err := service.db.Create(&importData).Error err := service.db.Create(&importData).Error
e = response.CheckErr(err, "添加失败") e = response.CheckErr(err, "添加失败")
return e return e

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,6 +6,7 @@ import (
"x_admin/core/response" "x_admin/core/response"
"x_admin/model" "x_admin/model"
"x_admin/util" "x_admin/util"
"x_admin/util/convert_util"
"x_admin/util/excel2" "x_admin/util/excel2"
"gorm.io/gorm" "gorm.io/gorm"
@@ -81,7 +82,7 @@ func (service monitorProjectService) List(page request.PageReq, listReq MonitorP
return return
} }
result := []MonitorProjectResp{} result := []MonitorProjectResp{}
util.ConvertUtil.Copy(&result, modelList) convert_util.Copy(&result, modelList)
return response.PageResp{ return response.PageResp{
PageNo: page.PageNo, PageNo: page.PageNo,
PageSize: page.PageSize, PageSize: page.PageSize,
@@ -100,7 +101,7 @@ func (service monitorProjectService) ListAll(listReq MonitorProjectListReq) (res
if e = response.CheckErr(err, "查询全部失败"); e != nil { if e = response.CheckErr(err, "查询全部失败"); e != nil {
return return
} }
util.ConvertUtil.Copy(&res, modelList) convert_util.Copy(&res, modelList)
return res, nil return res, nil
} }
@@ -119,14 +120,14 @@ func (service monitorProjectService) Detail(Id int) (res MonitorProjectResp, e e
cacheUtil.SetCache(obj.Id, obj) cacheUtil.SetCache(obj.Id, obj)
} }
util.ConvertUtil.Copy(&res, obj) convert_util.Copy(&res, obj)
return return
} }
// Add 监控项目新增 // Add 监控项目新增
func (service monitorProjectService) Add(addReq MonitorProjectAddReq) (createId int, e error) { func (service monitorProjectService) Add(addReq MonitorProjectAddReq) (createId int, e error) {
var obj model.MonitorProject var obj model.MonitorProject
util.ConvertUtil.StructToStruct(addReq, &obj) convert_util.StructToStruct(addReq, &obj)
obj.ProjectKey = util.ToolsUtil.MakeUuid() obj.ProjectKey = util.ToolsUtil.MakeUuid()
err := service.db.Create(&obj).Error err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err) e = response.CheckMysqlErr(err)
@@ -149,7 +150,7 @@ func (service monitorProjectService) Edit(editReq MonitorProjectEditReq) (e erro
if e = response.CheckErr(err, "查询失败"); e != nil { if e = response.CheckErr(err, "查询失败"); e != nil {
return return
} }
util.ConvertUtil.Copy(&obj, editReq) convert_util.Copy(&obj, editReq)
err = service.db.Model(&obj).Select("*").Updates(obj).Error err = service.db.Model(&obj).Select("*").Updates(obj).Error
if e = response.CheckErr(err, "编辑失败"); e != nil { if e = response.CheckErr(err, "编辑失败"); e != nil {
@@ -188,9 +189,10 @@ func (service monitorProjectService) DelBatch(Ids []string) (e error) {
return err return err
} }
// 删除缓存 // 删除缓存
for _, v := range Ids { // for _, v := range Ids {
cacheUtil.RemoveCache(v) // cacheUtil.RemoveCache(v)
} // }
cacheUtil.RemoveCache(Ids)
return nil return nil
} }
@@ -220,14 +222,14 @@ func (service monitorProjectService) ExportFile(listReq MonitorProjectListReq) (
return return
} }
result := []MonitorProjectResp{} result := []MonitorProjectResp{}
util.ConvertUtil.Copy(&result, modelList) convert_util.Copy(&result, modelList)
return result, nil return result, nil
} }
// 导入 // 导入
func (service monitorProjectService) ImportFile(importReq []MonitorProjectResp) (e error) { func (service monitorProjectService) ImportFile(importReq []MonitorProjectResp) (e error) {
var importData []model.MonitorProject var importData []model.MonitorProject
util.ConvertUtil.Copy(&importData, importReq) convert_util.Copy(&importData, importReq)
err := service.db.Create(&importData).Error err := service.db.Create(&importData).Error
e = response.CheckErr(err, "添加失败") e = response.CheckErr(err, "添加失败")
return e 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/core/response"
"x_admin/model/setting_model" "x_admin/model/setting_model"
"x_admin/util" "x_admin/util"
"x_admin/util/convert_util"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -58,7 +59,7 @@ func (ddSrv settingDictDataService) All(allReq SettingDictDataListReq) (res []Se
return return
} }
res = []SettingDictDataResp{} res = []SettingDictDataResp{}
util.ConvertUtil.Copy(&res, dictDatas) convert_util.Copy(&res, dictDatas)
return return
} }
@@ -95,7 +96,7 @@ func (ddSrv settingDictDataService) List(page request.PageReq, listReq SettingDi
return return
} }
dtResp := []SettingDictDataResp{} dtResp := []SettingDictDataResp{}
util.ConvertUtil.Copy(&dtResp, dds) convert_util.Copy(&dtResp, dds)
return response.PageResp{ return response.PageResp{
PageNo: page.PageNo, PageNo: page.PageNo,
PageSize: page.PageSize, PageSize: page.PageSize,
@@ -114,7 +115,7 @@ func (ddSrv settingDictDataService) Detail(id uint) (res SettingDictDataResp, e
if e = response.CheckErr(err, "详情获取失败"); e != nil { if e = response.CheckErr(err, "详情获取失败"); e != nil {
return return
} }
util.ConvertUtil.Copy(&res, dd) convert_util.Copy(&res, dd)
return return
} }
@@ -124,7 +125,7 @@ func (ddSrv settingDictDataService) Add(addReq SettingDictDataAddReq) (e error)
return response.AssertArgumentError.SetMessage("字典数据已存在!") return response.AssertArgumentError.SetMessage("字典数据已存在!")
} }
var dd setting_model.DictData var dd setting_model.DictData
util.ConvertUtil.Copy(&dd, addReq) convert_util.Copy(&dd, addReq)
err := ddSrv.db.Create(&dd).Error err := ddSrv.db.Create(&dd).Error
e = response.CheckErr(err, "添加失败") e = response.CheckErr(err, "添加失败")
return return
@@ -144,7 +145,7 @@ func (ddSrv settingDictDataService) Edit(editReq SettingDictDataEditReq) (e erro
return response.AssertArgumentError.SetMessage("字典数据已存在!") return response.AssertArgumentError.SetMessage("字典数据已存在!")
} }
util.ConvertUtil.Copy(&dd, editReq) convert_util.Copy(&dd, editReq)
err = ddSrv.db.Save(&dd).Error err = ddSrv.db.Save(&dd).Error
e = response.CheckErr(err, "编辑失败") e = response.CheckErr(err, "编辑失败")
return return

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,7 @@ import (
"database/sql/driver" "database/sql/driver"
"encoding/json" "encoding/json"
"strconv" "strconv"
"x_admin/util/convert_util"
) )
// Float类型别名支持前端传递nullfloat64, string类型 // Float类型别名支持前端传递nullfloat64, string类型
@@ -13,64 +14,78 @@ type NullFloat struct {
Valid bool 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) { func DecodeFloat(value any) (any, error) {
switch v := value.(type) { switch v := value.(type) {
case float64: // case float64:
f := v // f := v
return NullFloat{Float: &f, Valid: true}, nil // return NullFloat{Float: &f, Valid: true}, nil
case int: // case float32:
f := float64(v) // f := float64(v)
return NullFloat{Float: &f, Valid: true}, nil // return NullFloat{Float: &f, Valid: true}, nil
case int64: // case int:
f := float64(v) // f := float64(v)
return NullFloat{Float: &f, Valid: true}, nil // return NullFloat{Float: &f, Valid: true}, nil
case string: // case int64:
if v == "" { // f := float64(v)
return NullFloat{Float: nil, Valid: false}, nil // return NullFloat{Float: &f, Valid: true}, nil
} // case string:
f, err := strconv.ParseFloat(v, 64) // if v == "" {
return NullFloat{Float: &f, Valid: true}, err // return NullFloat{Float: nil, Valid: false}, nil
// }
// f, err := strconv.ParseFloat(v, 64)
// return NullFloat{Float: &f, Valid: true}, err
case nil: case nil:
return NullFloat{Float: nil, Valid: false}, nil return NullFloat{Float: nil, Valid: false}, nil
case NullFloat: case NullFloat:
return v, nil 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 // gorm实现Scanner
func (f *NullFloat) Scan(value interface{}) error { func (f *NullFloat) Scan(value interface{}) error {
f.Valid = false 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 = &result, true
f.Float, f.Valid = &v, true
return nil 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 // gorm实现 Valuer

View File

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

View File

@@ -7,12 +7,3 @@ type PageResp struct {
PageSize int `json:"pageSize"` // 每页Size PageSize int `json:"pageSize"` // 每页Size
Lists interface{} `json:"lists"` // 数据 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/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // 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/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // 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/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // 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/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 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= 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 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 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-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 h1:j7a/xn1U6TKA/PHHxqZuzh64CdtRc7rU9M+AvkOl5bA=
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= 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 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 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= 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 UserId string `gorm:"comment:'用户id'"` // 用户id
Os string `gorm:"comment:'系统'"` // 系统 Os string `gorm:"comment:'系统'"` // 系统
Browser string `gorm:"comment:'浏览器'"` // 浏览器 Browser string `gorm:"comment:'浏览器'"` // 浏览器
Country string `gorm:"comment:'国家'"` // 国家
Province string `gorm:"comment:'省份'"` // 省份
City string `gorm:"comment:'城市'"` // 城市 City string `gorm:"comment:'城市'"` // 城市
Operator string `gorm:"comment:'电信运营商'"` // 电信运营商
Ip string `gorm:"comment:'ip'"` // ip
Width core.NullInt `gorm:"comment:'屏幕'"` // 屏幕 Width core.NullInt `gorm:"comment:'屏幕'"` // 屏幕
Height core.NullInt `gorm:"comment:'屏幕高度'"` // 屏幕高度 Height core.NullInt `gorm:"comment:'屏幕高度'"` // 屏幕高度
Ua string `gorm:"comment:'ua记录'"` // ua记录 Ua string `gorm:"comment:'ua记录'"` // ua记录

View File

@@ -6,9 +6,8 @@ import (
// MonitorErrorList 错误对应的用户记录实体 // MonitorErrorList 错误对应的用户记录实体
type MonitorErrorList struct { type MonitorErrorList struct {
Id int `gorm:"primarykey;comment:'项目id'"` // 项目id Id int `gorm:"primarykey;comment:'id'"`
ErrorId string `gorm:"comment:'错误id'"` // 错误id Eid string `gorm:"comment:'错误id'"` // 错误id
ClientId string `gorm:"comment:'客户端id'"` // 客户端id Cid string `gorm:"comment:'客户端id'"` // 客户端id
ProjectKey string `gorm:"comment:'项目key'"` // 项目id
CreateTime core.NullTime `gorm:"autoCreateTime;comment:'创建时间'"` // 创建时间 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) MonitorProjectRoute(rg)
MonitorClientRoute(rg) MonitorClientRoute(rg)
MonitorErrorRoute(rg) MonitorErrorRoute(rg)
MonitorSlowRoute(rg)
UserProtocolRoute(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) // MonitorClientRoute(rg)
func MonitorClientRoute(rg *gin.RouterGroup) { func MonitorClientRoute(rg *gin.RouterGroup) {
handle := monitor_client.MonitorClientHandler{} handle := monitor_client.MonitorClientHandler{}
rg.GET("/monitor_client/add", middleware.RecordLog("监控-客户端信息新增"), handle.Add)
r := rg.Group("/", middleware.TokenAuth()) r := rg.Group("/", middleware.TokenAuth())
r.GET("/monitor_client/list", handle.List) 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/detail", handle.Detail)
r.GET("/monitor_client/errorUsers", handle.ErrorUsers) 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/edit",middleware.RecordLog("监控-客户端信息编辑"), handle.Edit)
r.POST("/monitor_client/del", middleware.RecordLog("监控-客户端信息删除"), handle.Del) 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) // MonitorErrorRoute(rg)
func MonitorErrorRoute(rg *gin.RouterGroup) { func MonitorErrorRoute(rg *gin.RouterGroup) {
handle := monitor_error.MonitorErrorHandler{} handle := monitor_error.MonitorErrorHandler{}
rg.GET("/monitor_error/add", middleware.RecordLog("监控-错误列新增"), handle.Add)
r := rg.Group("/", middleware.TokenAuth()) r := rg.Group("/", middleware.TokenAuth())
r.GET("/monitor_error/list", handle.List) r.GET("/monitor_error/list", handle.List)
r.GET("/monitor_error/listAll", handle.ListAll) r.GET("/monitor_error/listAll", handle.ListAll)
r.GET("/monitor_error/detail", handle.Detail) 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/del", middleware.RecordLog("监控-错误列删除"), handle.Del)
r.POST("/monitor_error/delBatch", middleware.RecordLog("监控-错误列删除-批量"), handle.DelBatch) 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 return nil
} }
// 删除缓存 // 删除缓存-支持批量删除
func (c CacheUtil) RemoveCache(key interface{}) bool { func (c CacheUtil) RemoveCache(key interface{}) bool {
var cacheKey string var cacheKey []string
switch k := key.(type) { switch k := key.(type) {
case int: case int:
cacheKey = strconv.Itoa(k) cacheKey = append(cacheKey, strconv.Itoa(k))
case string: case string:
cacheKey = append(cacheKey, k)
// 判断是slice
case []int:
for _, v := range k {
cacheKey = append(cacheKey, strconv.Itoa(v))
}
case []string:
cacheKey = k cacheKey = k
default: default:
return false return false
} }
return RedisUtil.HDel(c.Name, cacheKey) return RedisUtil.HDel(c.Name, cacheKey...)
} }

View File

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

View File

@@ -2,7 +2,6 @@ package util
import ( import (
"reflect" "reflect"
"x_admin/core"
"github.com/fatih/structs" "github.com/fatih/structs"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
@@ -28,7 +27,7 @@ func (c convertUtil) StructsToMaps(from interface{}) (data []map[string]interfac
var objList []interface{} var objList []interface{}
err := copier.Copy(&objList, from) err := copier.Copy(&objList, from)
if err != nil { if err != nil {
core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err) // core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err)
return nil return nil
} }
for _, v := range objList { for _, v := range objList {
@@ -57,7 +56,7 @@ func (c convertUtil) ShallowStructsToMaps(from interface{}) (data []map[string]i
var objList []interface{} var objList []interface{}
err := copier.Copy(&objList, from) err := copier.Copy(&objList, from)
if err != nil { if err != nil {
core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err) // core.Logger.Errorf("convertUtil.StructsToMaps err: err=[%+v]", err)
return nil return nil
} }
for _, v := range objList { 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{} { func (c convertUtil) Copy(toValue interface{}, fromValue interface{}) interface{} {
if err := copier.Copy(toValue, fromValue); err != nil { 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") panic("SystemError")
} }
return toValue 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 ( import (
"fmt" "fmt"
"x_admin/util" "x_admin/util/convert_util"
"github.com/xuri/excelize/v2" "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) { func Export(lists any, cols []Col, sheet string, title string) (file *excelize.File, err error) {
e := ExcelInit() e := ExcelInit()
data := util.ConvertUtil.ShallowStructsToMaps(lists) data := convert_util.ShallowStructsToMaps(lists)
err = ExportExcel(sheet, title, data, cols, e) err = ExportExcel(sheet, title, data, cols, e)
if err != nil { if err != nil {

View File

@@ -6,7 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"mime/multipart" "mime/multipart"
"x_admin/util" "x_admin/util/convert_util"
"github.com/xuri/excelize/v2" "github.com/xuri/excelize/v2"
) )
@@ -99,7 +99,7 @@ func importData(f *excelize.File, dst interface{}, sheetName string, startRow in
data = append(data, rowMap) data = append(data, rowMap)
} }
util.ConvertUtil.MapToStruct(data, dst) convert_util.MapToStruct(data, dst)
// fmt.Println("Type.Name:", field.Type.Name(), field.Type.Kind()) // 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 package util
import ( import (
"fmt"
"net" "net"
"x_admin/core" "strings"
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
) )
var IpUtil = ipUtil{} var IpUtil = initIpUtil()
// serverUtil IP工具类 // serverUtil IP工具类
type ipUtil struct{} type ipUtil struct {
Searcher *xdb.Searcher
}
// GetHostIp 获取本地主机名 // GetHostIp 获取本地主机名
func (su ipUtil) GetHostIp() (ip string) { func (su ipUtil) GetHostIp() (ip string) {
conn, err := net.Dial("udp", "114.114.114.114:80") conn, err := net.Dial("udp", "114.114.114.114:80")
if err != nil { if err != nil {
core.Logger.Errorf("GetHostIp Dial err: err=[%+v]", err) // core.Logger.Errorf("GetHostIp Dial err: err=[%+v]", err)
return return
} }
defer conn.Close() defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr) localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP.String() 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;