未完成的监控

This commit is contained in:
xiangheng
2024-04-21 21:51:20 +08:00
parent e8f52ce6f1
commit 4479c60ac4
49 changed files with 2899 additions and 173 deletions

View File

@@ -0,0 +1,22 @@
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /usr/share/nginx/html;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
try_files $uri $uri/ /index.html;
}
location /api {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
rewrite ^/api/(.*)$ /$1 break; #重写
proxy_pass http://127.0.0.1:8888; # 设置代理服务器的协议和地址
}
}

8
admin/.dockerignore Normal file
View File

@@ -0,0 +1,8 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
package-lock.json
pnpm-lock.yaml
.vscode

3
admin/.npmrc Normal file
View File

@@ -0,0 +1,3 @@
registry=https://registry.npmmirror.com
sharp_binary_host=https://npmmirror.com/mirrors/sharp
sharp_libvips_binary_host=https://npmmirror.com/mirrors/sharp-libvips

View File

@@ -8,5 +8,5 @@
"css.validate": false,
"less.validate": false,
"scss.validate": false,
"cSpell.words": ["nprogress", "pinia", "vform"]
"cSpell.words": ["datetimerange", "nprogress", "pinia", "vform"]
}

34
admin/Dockerfile Normal file
View File

@@ -0,0 +1,34 @@
FROM node:18-alpine as build
# 设置工作目录为/app
WORKDIR /app
# 提前提高编译速度
COPY package.json .npmrc ./
# 安装依赖
RUN npm i
# 清理不需要的依赖项和文件
# RUN npm prune --production
COPY . /app
RUN npm run prod
FROM nginx:alpine
# 从.docker-compose/nginx/conf.d/目录拷贝my.conf到容器内的/etc/nginx/conf.d/my.conf
COPY .docker-compose/my.conf /etc/nginx/conf.d/my.conf
# 从第一阶段进行拷贝文件
COPY --from=0 /app/dist /usr/share/nginx/html
# 查看/etc/nginx/nginx.conf文件
RUN cat /etc/nginx/nginx.conf
# 查看 /etc/nginx/conf.d/my.conf
RUN cat /etc/nginx/conf.d/my.conf
# 查看 文件是否拷贝成功
RUN ls -al /usr/share/nginx/html
EXPOSE 8080

View File

@@ -14,9 +14,9 @@
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@highlightjs/vue-plugin": "^2.1.0",
"@logicflow/core": "^1.2.24",
"@logicflow/extension": "^1.2.24",
"@vue/shared": "^3.4.21",
"@logicflow/core": "^1.2.26",
"@logicflow/extension": "^1.2.26",
"@vue/shared": "^3.4.23",
"@vueuse/core": "^10.9.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
@@ -25,24 +25,24 @@
"crypto-js": "^4.2.0",
"css-color-function": "^1.3.3",
"echarts": "^5.5.0",
"element-plus": "^2.6.3",
"element-plus": "^2.7.0",
"highlight.js": "^11.9.0",
"lodash-es": "^4.17.21",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",
"query-string": "^9.0.0",
"vform3-builds": "^3.0.10",
"vue": "^3.4.21",
"vue": "^3.4.23",
"vue-clipboard3": "^2.0.0",
"vue-echarts": "^6.6.9",
"vue-router": "^4.3.0",
"vue-router": "^4.3.2",
"vue3-video-play": "^1.3.2",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.10.1",
"@rushstack/eslint-patch": "^1.10.2",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.12.3",
"@types/node": "^20.12.7",
"@types/nprogress": "^0.2.3",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
@@ -51,21 +51,21 @@
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.19",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.24.0",
"eslint-plugin-vue": "^9.25.0",
"execa": "^8.0.1",
"fs-extra": "^11.2.0",
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.72.0",
"sass": "^1.75.0",
"tailwindcss": "^3.4.3",
"typescript": "~5.4.3",
"typescript": "~5.4.5",
"unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0",
"vite": "^5.2.7",
"vite": "^5.2.9",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^2.0.7"
"vue-tsc": "^2.0.13"
}
}

2
admin/public/robots.txt Normal file
View File

@@ -0,0 +1,2 @@
User-agent: *
Allow: /

View File

@@ -0,0 +1,30 @@
import request from '@/utils/request'
// 客户端信息列表
export function monitor_client_list(params?: Record<string, any>) {
return request.get({ url: '/monitor_client/list', params })
}
// 客户端信息列表-所有
export function monitor_client_list_all(params?: Record<string, any>) {
return request.get({ url: '/monitor_client/listAll', params })
}
// 客户端信息详情
export function monitor_client_detail(params: Record<string, any>) {
return request.get({ url: '/monitor_client/detail', params })
}
// 客户端信息新增
export function monitor_client_add(params: Record<string, any>) {
return request.post({ url: '/monitor_client/add', params })
}
// 客户端信息编辑
export function monitor_client_edit(params: Record<string, any>) {
return request.post({ url: '/monitor_client/edit', params })
}
// 客户端信息删除
export function monitor_client_delete(params: Record<string, any>) {
return request.post({ url: '/monitor_client/del', params })
}

View File

@@ -0,0 +1,30 @@
import request from '@/utils/request'
// 错误项目列表
export function monitor_project_list(params?: Record<string, any>) {
return request.get({ url: '/monitor_project/list', params })
}
// 错误项目列表-所有
export function monitor_project_list_all(params?: Record<string, any>) {
return request.get({ url: '/monitor_project/listAll', params })
}
// 错误项目详情
export function monitor_project_detail(params: Record<string, any>) {
return request.get({ url: '/monitor_project/detail', params })
}
// 错误项目新增
export function monitor_project_add(params: Record<string, any>) {
return request.post({ url: '/monitor_project/add', params })
}
// 错误项目编辑
export function monitor_project_edit(params: Record<string, any>) {
return request.post({ url: '/monitor_project/edit', params })
}
// 错误项目删除
export function monitor_project_delete(params: Record<string, any>) {
return request.post({ url: '/monitor_project/del', params })
}

View File

@@ -0,0 +1,43 @@
import request from '@/utils/request'
import config from '@/config'
import queryString from 'query-string'
import { getToken } from '@/utils/auth'
// 错误收集error列表
export function monitor_web_list(params?: Record<string, any>) {
return request.get({ url: '/monitor_web/list', params })
}
// 错误收集error列表-所有
export function monitor_web_list_all(params?: Record<string, any>) {
return request.get({ url: '/monitor_web/listAll', params })
}
// 错误收集error详情
export function monitor_web_detail(params: Record<string, any>) {
return request.get({ url: '/monitor_web/detail', params })
}
// 错误收集error新增
export function monitor_web_add(params: Record<string, any>) {
return request.post({ url: '/monitor_web/add', params })
}
// 错误收集error编辑
export function monitor_web_edit(params: Record<string, any>) {
return request.post({ url: '/monitor_web/edit', params })
}
// 错误收集error删除
export function monitor_web_delete(params: Record<string, any>) {
return request.post({ url: '/monitor_web/del', params })
}
// 错误收集error导入
export const monitor_web_import_file = '/monitor_web/ImportFile'
// 错误收集error导出
export function monitor_web_export_file(params: any) {
return (window.location.href =
`${config.baseUrl}${config.urlPrefix}/monitor_web/ExportFile?token=${getToken()}&` +
queryString.stringify(params))
}

View File

@@ -1,13 +1,13 @@
<template>
<el-date-picker
v-model="content"
type="daterange"
type="datetimerange"
range-separator="-"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
:default-time="defaultTime"
@change="changeDate"
></el-date-picker>
</template>
@@ -24,9 +24,11 @@ const props = defineProps({
default: ''
}
})
const defaultTime: [Date, Date] = [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] // '12:00:00', '08:00:00'
const emit = defineEmits(['update:startTime', 'update:endTime'])
const content = ref<[string, string]>([props.startTime, props.endTime])
function changeDate(value: any) {
console.log('change', value)
if (value === null) {
@@ -37,6 +39,11 @@ function changeDate(value: any) {
emit('update:endTime', value[1])
}
}
watch([() => props.startTime, () => props.endTime], () => {
console.log('watch', props)
content.value = [props.startTime, props.endTime]
})
// const content = computed<any>({
// get: () => {
// return [props.startTime, props.endTime]

View File

@@ -105,44 +105,6 @@ export function objectToQuery(params: Record<string, any>): string {
return query.slice(0, -1)
}
/**
* @description 时间格式化
* @param dateTime { number } 时间戳
* @param fmt { string } 时间格式
* @return { string }
*/
// yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合
export const timeFormat = (dateTime: number, fmt = 'yyyy-mm-dd') => {
// 如果为null,则格式化当前时间
if (!dateTime) {
dateTime = Number(new Date())
}
// 如果dateTime长度为10或者13则为秒和毫秒的时间戳如果超过13位则为其他的时间格式
if (dateTime.toString().length == 10) {
dateTime *= 1000
}
const date = new Date(dateTime)
let ret
const opt: any = {
'y+': date.getFullYear().toString(), // 年
'm+': (date.getMonth() + 1).toString(), // 月
'd+': date.getDate().toString(), // 日
'h+': date.getHours().toString(), // 时
'M+': date.getMinutes().toString(), // 分
's+': date.getSeconds().toString() // 秒
}
for (const k in opt) {
ret = new RegExp('(' + k + ')').exec(fmt)
if (ret) {
fmt = fmt.replace(
ret[1],
ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0')
)
}
}
return fmt
}
/**
* @description 获取不重复的id
* @param length { Number } id的长度

View File

@@ -0,0 +1,208 @@
<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="客户端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="系统" prop="os">
<el-input v-model="formData.os" placeholder="请输入系统" />
</el-form-item>
<el-form-item label="浏览器" prop="browser">
<el-input v-model="formData.browser" placeholder="请输入浏览器" />
</el-form-item>
<el-form-item label="城市" prop="city">
<el-input v-model="formData.city" placeholder="请输入城市" />
</el-form-item>
<el-form-item label="屏幕" prop="width">
<el-input v-model.number="formData.width" placeholder="请输入屏幕" />
</el-form-item>
<el-form-item label="屏幕高度" prop="height">
<el-input v-model.number="formData.height" placeholder="请输入屏幕高度" />
</el-form-item>
<el-form-item label="ua记录" prop="ua">
<el-input v-model="formData.ua" placeholder="请输入ua记录" />
</el-form-item>
<el-form-item label="时间" prop="clientTime">
<el-input v-model="formData.clientTime" placeholder="请输入客户端时间" />
</el-form-item>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import {
monitor_client_edit,
monitor_client_add,
monitor_client_detail
} from '@/api/monitor_client'
import Popup from '@/components/popup/index.vue'
import feedback from '@/utils/feedback'
import type { PropType } from 'vue'
defineProps({
dictData: {
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: '',
projectKey: '',
clientId: '',
userId: '',
os: '',
browser: '',
city: '',
width: '',
height: '',
ua: '',
clientTime: ''
})
const formRules = {
id: [
{
required: true,
message: '请输入uuid',
trigger: ['blur']
}
],
projectKey: [
{
required: true,
message: '请输入项目key',
trigger: ['blur']
}
],
clientId: [
{
// required: true,
message: '请输入sdk生成的客户端id',
trigger: ['blur']
}
],
userId: [
{
required: true,
message: '请输入用户id',
trigger: ['blur']
}
],
os: [
{
required: true,
message: '请输入系统',
trigger: ['blur']
}
],
browser: [
{
required: true,
message: '请输入浏览器',
trigger: ['blur']
}
],
city: [
{
required: true,
message: '请输入城市',
trigger: ['blur']
}
],
width: [
{
required: true,
message: '请输入屏幕',
trigger: ['blur']
}
],
height: [
{
required: true,
message: '请输入屏幕高度',
trigger: ['blur']
}
],
ua: [
{
required: true,
message: '请输入ua记录',
trigger: ['blur']
}
],
clientTime: [
{
required: true,
message: '请输入客户端时间',
trigger: ['blur']
}
]
}
const handleSubmit = async () => {
try {
await formRef.value?.validate()
const data: any = { ...formData }
mode.value == 'edit' ? await monitor_client_edit(data) : await monitor_client_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_client_detail({
id: row.id
})
setFormData(data)
} catch (error) {}
}
const handleClose = () => {
emit('close')
}
defineExpose({
open,
setFormData,
getDetail
})
</script>

View File

@@ -0,0 +1,124 @@
<template>
<div class="index-lists">
<el-card class="!border-none" shadow="never">
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
<el-form-item label="项目key" prop="projectKey" class="w-[280px]">
<el-input v-model="queryParams.projectKey" />
</el-form-item>
<el-form-item label="客户端id" prop="clientId" class="w-[280px]">
<el-input v-model="queryParams.clientId" />
</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="city" class="w-[280px]">
<el-input v-model="queryParams.city" />
</el-form-item>
<el-form-item label="时间" prop="clientTime" class="w-[280px]">
<el-input v-model="queryParams.clientTime" />
</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>
<el-button
v-perms="['admin:monitor_client:add']"
type="primary"
@click="handleAdd()"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
</div>
<el-table class="mt-4" size="large" v-loading="pager.loading" :data="pager.lists">
<el-table-column label="项目key" prop="projectKey" 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="系统" prop="os" min-width="130" />
<el-table-column label="浏览器" prop="browser" min-width="130" />
<el-table-column label="城市" prop="city" min-width="130" />
<el-table-column label="屏幕" prop="width" min-width="130" />
<el-table-column label="屏幕高度" prop="height" min-width="130" />
<el-table-column label="ua记录" prop="ua" min-width="130" />
<el-table-column label="客户端时间" prop="clientTime" min-width="130" />
<!-- <el-table-column label="创建时间" prop="createTime" min-width="130" /> -->
<el-table-column label="操作" width="160" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="to_monitor_web(row)">日志</el-button>
<el-button
v-perms="['admin:monitor_client: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 { monitor_client_delete, monitor_client_list } from '@/api/monitor_client'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
const router = useRouter()
defineOptions({
name: 'monitor_client'
})
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const queryParams = reactive({
projectKey: '',
clientId: '',
userId: '',
os: '',
browser: '',
city: '',
width: '',
height: '',
ua: '',
clientTime: ''
})
const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: monitor_client_list,
params: queryParams
})
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add')
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await monitor_client_delete({ id })
feedback.msgSuccess('删除成功')
getLists()
}
const to_monitor_web = async (data: any) => {
router.push(
`/setting/monitor_web/index?clientId=${data.clientId}&projectKey=${data.projectKey}`
)
}
getLists()
</script>

View File

@@ -0,0 +1,7 @@
<template>
<div></div>
</template>
<script setup lang="ts"></script>
<style scoped></style>

View File

@@ -0,0 +1,144 @@
<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="请输入项目uuid" />
</el-form-item>
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="formData.projectName" placeholder="请输入项目名称" />
</el-form-item>
<el-form-item label="项目类型" prop="projectType">
<el-select
class="flex-1"
v-model="formData.projectType"
placeholder="请选择项目类型"
>
<el-option
v-for="(item, index) in dictData.project_type"
:key="index"
:label="item.name"
:value="item.value"
clearable
:disabled="!item.status"
/>
</el-select>
</el-form-item>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import {
monitor_project_edit,
monitor_project_add,
monitor_project_detail
} from '@/api/monitor_project'
import Popup from '@/components/popup/index.vue'
import feedback from '@/utils/feedback'
import type { PropType } from 'vue'
defineProps({
dictData: {
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: '',
projectKey: '',
projectName: '',
projectType: ''
})
const formRules = {
id: [
{
required: true,
message: '请输入项目id',
trigger: ['blur']
}
],
projectKey: [
{
required: true,
message: '请输入项目Key',
trigger: ['blur']
}
],
projectName: [
{
required: true,
message: '请输入项目名称',
trigger: ['blur']
}
],
projectType: [
{
required: true,
message: '请选择项目类型go java web node php 等',
trigger: ['blur']
}
]
}
const handleSubmit = async () => {
try {
await formRef.value?.validate()
const data: any = { ...formData }
mode.value == 'edit' ? await monitor_project_edit(data) : await monitor_project_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_project_detail({
id: row.id
})
setFormData(data)
} catch (error) {}
}
const handleClose = () => {
emit('close')
}
defineExpose({
open,
setFormData,
getDetail
})
</script>

View File

@@ -0,0 +1,139 @@
<template>
<div class="index-lists">
<el-card class="!border-none" shadow="never">
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
<el-form-item label="项目Key" prop="projectKey">
<el-input v-model="queryParams.projectKey" />
</el-form-item>
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="queryParams.projectName" />
</el-form-item>
<el-form-item label="项目类型" prop="projectType" class="w-[280px]">
<el-select v-model="queryParams.projectType" clearable>
<el-option label="全部" value="" />
<el-option
v-for="(item, index) in dictData.project_type"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</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>
<el-button
v-perms="['admin:monitor_project:add']"
type="primary"
@click="handleAdd()"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
</div>
<el-table class="mt-4" size="large" v-loading="pager.loading" :data="pager.lists">
<el-table-column label="项目Key" prop="projectKey" min-width="130" />
<el-table-column label="项目名称" prop="projectName" min-width="130" />
<el-table-column label="项目类型" prop="projectType" min-width="100">
<template #default="{ row }">
<dict-value :options="dictData.project_type" :value="row.projectType" />
</template>
</el-table-column>
<el-table-column label="更新时间" prop="updateTime" min-width="130" />
<!-- <el-table-column label="创建时间" prop="createTime" min-width="130" /> -->
<el-table-column label="操作" width="240" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="to_monitor_web(row)">日志</el-button>
<el-button
v-perms="['admin:monitor_project:edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
<el-button
v-perms="['admin:monitor_project: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"
:dict-data="dictData"
@success="getLists"
@close="showEdit = false"
/>
</div>
</template>
<script lang="ts" setup>
import { monitor_project_delete, monitor_project_list } from '@/api/monitor_project'
import { useDictData } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
defineOptions({
name: 'monitor_project'
})
const router = useRouter()
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const queryParams = reactive({
projectKey: '',
projectName: '',
projectType: ''
})
const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: monitor_project_list,
params: queryParams
})
const { dictData } = useDictData<{
project_type: any[]
}>(['project_type'])
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add')
}
const handleEdit = async (data: any) => {
showEdit.value = true
await nextTick()
editRef.value?.open('edit')
editRef.value?.getDetail(data)
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await monitor_project_delete({ id })
feedback.msgSuccess('删除成功')
getLists()
}
const to_monitor_web = async (data: any) => {
router.push('/setting/monitor_web/index?projectKey=' + data.projectKey)
}
getLists()
</script>

View File

@@ -0,0 +1,189 @@
<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="事件类型" prop="eventType">
<el-select class="flex-1" v-model="formData.eventType" placeholder="请选择事件类型">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
<el-form-item label="URL地址" prop="page">
<el-input
v-model="formData.page"
placeholder="请输入URL地址"
type="textarea"
:autosize="{ minRows: 4, maxRows: 6 }"
/>
</el-form-item>
<el-form-item label="错误消息" prop="message">
<el-input
v-model="formData.message"
placeholder="请输入错误消息"
type="textarea"
:autosize="{ minRows: 4, maxRows: 6 }"
/>
</el-form-item>
<el-form-item label="错误堆栈" prop="stack">
<el-input
v-model="formData.stack"
placeholder="请输入错误堆栈"
type="textarea"
:autosize="{ minRows: 4, maxRows: 6 }"
/>
</el-form-item>
<el-form-item label="客户端时间" prop="clientTime">
<el-input v-model="formData.clientTime" placeholder="请输入客户端时间" />
</el-form-item>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import { monitor_web_edit, monitor_web_add, monitor_web_detail } from '@/api/monitor_web'
import Popup from '@/components/popup/index.vue'
import feedback from '@/utils/feedback'
import type { PropType } from 'vue'
defineProps({
dictData: {
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' ? '编辑错误收集error' : '新增错误收集error'
})
const formData = reactive({
id: '',
projectKey: '',
clientId: '',
eventType: '',
page: '',
message: '',
stack: '',
clientTime: '',
})
const formRules = {
id: [
{
required: true,
message: '请输入uuid',
trigger: ['blur']
}
],
projectKey: [
{
required: true,
message: '请输入项目key',
trigger: ['blur']
}
],
clientId: [
{
required: true,
message: '请输入sdk生成的客户端id',
trigger: ['blur']
}
],
eventType: [
{
required: true,
message: '请选择事件类型',
trigger: ['blur']
}
],
page: [
{
required: true,
message: '请输入URL地址',
trigger: ['blur']
}
],
message: [
{
required: true,
message: '请输入错误消息',
trigger: ['blur']
}
],
stack: [
{
required: true,
message: '请输入错误堆栈',
trigger: ['blur']
}
],
clientTime: [
{
required: true,
message: '请输入客户端时间',
trigger: ['blur']
}
],
}
const handleSubmit = async () => {
try {
await formRef.value?.validate()
const data: any = { ...formData }
mode.value == 'edit' ? await monitor_web_edit(data) : await monitor_web_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_web_detail({
id: row.id
})
setFormData(data)
} catch (error) {}
}
const handleClose = () => {
emit('close')
}
defineExpose({
open,
setFormData,
getDetail
})
</script>

View File

@@ -0,0 +1,157 @@
<template>
<div class="index-lists">
<el-card class="!border-none" shadow="never">
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
<el-form-item label="项目Key" prop="projectKey" class="w-[280px]">
<el-input v-model="queryParams.projectKey" />
</el-form-item>
<el-form-item label="客户端id" prop="clientId" class="w-[280px]">
<el-input v-model="queryParams.clientId" />
</el-form-item>
<!-- <el-form-item label="事件类型" prop="eventType" class="w-[280px]">
<el-select v-model="queryParams.eventType" clearable>
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item> -->
<el-form-item label="时间" prop="clientTime" class="w-[400px]">
<daterange-picker
v-model:startTime="queryParams.clientTimeStart"
v-model:endTime="queryParams.clientTimeEnd"
/>
</el-form-item>
<!-- <el-form-item label="创建时间" prop="createTime" class="w-[400px]">
<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>
<el-button v-perms="['admin:monitor_web:add']" type="primary" @click="handleAdd()">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
<upload
class="ml-3 mr-3"
:url="monitor_web_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 type="primary" @click="exportFile">
<template #icon>
<icon name="el-icon-Download" />
</template>
导出
</el-button>
</div>
<el-table class="mt-4" size="large" v-loading="pager.loading" :data="pager.lists">
<el-table-column type="expand">
<template #default="props">
<el-alert :title="props.row.stack" type="error" :closable="false" />
</template>
</el-table-column>
<el-table-column label="项目key" prop="projectKey" min-width="130" />
<el-table-column label="客户端id" prop="clientId" min-width="130" />
<el-table-column label="事件类型" prop="eventType" min-width="130" />
<el-table-column label="URL地址" prop="page" min-width="130" />
<el-table-column label="错误消息" prop="message" min-width="130" />
<el-table-column label="时间" prop="clientTime" min-width="130" />
<!-- <el-table-column label="创建时间" prop="createTime" min-width="130" /> -->
<el-table-column label="操作" width="100" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['admin:monitor_web: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 {
monitor_web_delete,
monitor_web_list,
monitor_web_import_file,
monitor_web_export_file
} from '@/api/monitor_web'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
const route = useRoute()
defineOptions({
name: 'monitor_web'
})
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const queryParams = reactive({
projectKey: route.query?.projectKey as string,
clientId: route.query?.clientId as string,
eventType: '',
page: '',
message: '',
stack: '',
clientTimeStart: '',
clientTimeEnd: '',
createTimeStart: '',
createTimeEnd: ''
})
const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: monitor_web_list,
params: queryParams
})
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add')
}
const handleDelete = async (id: number) => {
try {
await feedback.confirm('确定要删除?')
await monitor_web_delete({ id })
feedback.msgSuccess('删除成功')
getLists()
} catch (error) {}
}
const exportFile = async () => {
try {
await feedback.confirm('确定要导出?')
await monitor_web_export_file(queryParams)
} catch (error) {
console.error(error)
}
}
getLists()
</script>

View File

@@ -171,12 +171,13 @@ const handleEdit = async (data: any) => {
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await adminDelete({ id })
feedback.msgSuccess('删除成功')
getLists()
try {
await feedback.confirm('确定要删除?')
await adminDelete({ id })
feedback.msgSuccess('删除成功')
getLists()
} catch (error) {}
}
const { optionsData } = useDictOptions<{
role: any[]
}>({

View File

@@ -42,18 +42,6 @@
<icon-picker class="flex-1" v-model="formData.menuIcon" />
</el-form-item>
<el-form-item
v-if="formData.menuType != MenuEnum.BUTTON"
label="路由路径"
prop="paths"
>
<div class="flex-1">
<el-input v-model="formData.paths" placeholder="请输入路由路径" clearable />
<div class="form-tips">
访问的路由地址`admin`如外网地址需内链访问则以`http(s)://`开头
</div>
</div>
</el-form-item>
<el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="组件路径"
@@ -73,6 +61,38 @@
</div>
</div>
</el-form-item>
<el-form-item
v-if="formData.menuType != MenuEnum.BUTTON"
label="路由路径"
prop="paths"
>
<div class="flex-1">
<el-input v-model="formData.paths" placeholder="请输入路由路径" clearable />
<div class="form-tips">
访问的路由地址`admin`如外网地址需内链访问则以`http(s)://`开头
</div>
</div>
</el-form-item>
<el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="路由参数"
prop="params"
>
<div>
<div class="flex-1">
<el-input
v-model="formData.params"
placeholder="请输入路由参数"
clearable
/>
</div>
<div class="form-tips">
访问路由的默认传递参数`{"id": 1, "name":
"admin"}``id=1&name=admin`
</div>
</div>
</el-form-item>
<el-form-item
label="选中菜单"
prop="selected"
@@ -98,9 +118,8 @@
<!-- {{ formData.permsArr }} -->
<!-- <el-input v-model="formData.perms" placeholder="请输入接口权限" clearable /> -->
<el-select
v-model="formData.permsArr"
v-model="formData.perms"
clearable
multiple
filterable
placeholder="请选择接口权限"
:style="{ width: '100%' }"
@@ -119,25 +138,7 @@
</div>
</div>
</el-form-item>
<el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="路由参数"
prop="params"
>
<div>
<div class="flex-1">
<el-input
v-model="formData.params"
placeholder="请输入路由参数"
clearable
/>
</div>
<div class="form-tips">
访问路由的默认传递参数`{"id": 1, "name":
"admin"}``id=1&name=admin`
</div>
</div>
</el-form-item>
<el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="是否缓存"
@@ -237,7 +238,7 @@ const formData = reactive({
paths: '',
//权限链接
perms: '',
permsArr: [],
// permsArr: [],
//前端组件
component: '',
//选中路径
@@ -311,11 +312,11 @@ function getApiListFn() {
const handleSubmit = async () => {
await formRef.value?.validate()
const data = { ...formData }
if (data.permsArr) {
data.perms = data.permsArr.join(',')
} else {
data.perms = ''
}
// if (data.permsArr) {
// data.perms = data.permsArr.join(',')
// } else {
// data.perms = ''
// }
mode.value == 'edit' ? await menuEdit(data) : await menuAdd(data)
popupRef.value?.close()
@@ -332,11 +333,12 @@ const setFormData = (data: Record<any, any>) => {
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
if (key == 'perms') {
formData['permsArr'] = data[key].split(',')
} else {
formData[key] = data[key]
}
// if (key == 'perms') {
// formData['permsArr'] = data[key].split(',')
// } else {
// formData[key] = data[key]
// }
formData[key] = data[key]
}
}
}

View File

@@ -61,12 +61,14 @@
<el-table-column label="记录ID" prop="id" />
<el-table-column label="操作" prop="title" min-width="120" />
<el-table-column label="管理员" prop="username" min-width="120" />
<el-table-column label="访问链接" prop="url" min-width="160" />
<el-table-column label="访问方式" prop="type" min-width="100" />
<el-table-column label="访问链接" prop="url" min-width="240">
<template #default="{ row }"> {{ row.type }}{{ row.url }} </template>
</el-table-column>
<!-- <el-table-column label="访问方式" prop="type" min-width="100" /> -->
<el-table-column label="来源IP" prop="ip" min-width="160" />
<el-table-column label="错误信息" prop="error" min-width="160" />
<el-table-column label="执行耗时(毫秒)" prop="taskTime" min-width="100" />
<el-table-column label="日志时间" prop="createTime" min-width="180" />
<el-table-column label="日志时间" prop="createTime" width="170" />
</el-table>
</div>
<div class="flex mt-4 justify-end">

View File

@@ -25,6 +25,7 @@ export default ({ mode }) => {
server: {
open: true,
host: '0.0.0.0',
port: 5174,
proxy: {
'/api': {
target: env.VITE_APP_BASE_URL,

5
server/.dockerignore Normal file
View File

@@ -0,0 +1,5 @@
### Go ###
# Binaries for programs and plugins
*.exe
.vscode
dist

View File

@@ -41,7 +41,7 @@ func (iSrv indexService) Console() (res map[string]interface{}, e error) {
"website": "x.adtk.cn",
"based": "Vue3.x、ElementUI、MySQL",
"channel": map[string]string{
"gitee": "https://gitee.com/x_admin/x_admin_python",
"gitee": "https://gitee.com/xiangheng/x_admin",
"website": "https://x.adtk.cn",
},
}

View File

@@ -56,4 +56,8 @@ func RegisterGroup(rg *gin.RouterGroup) {
flow.FlowHistoryRoute(rg)
generator.RegisterGroup(rg)
MonitorProjectRoute(rg)
MonitorClientRoute(rg)
MonitorWebRoute(rg)
}

View File

@@ -132,7 +132,7 @@ func (tu templateUtil) PrepareVars(table gen_model.GenTable, columns []gen_model
GenTpl: table.GenTpl,
TableName: table.TableName,
AuthorName: table.AuthorName,
PackageName: table.ModuleName, //config.GenConfig.PackageName,
PackageName: table.ModuleName,
EntityName: table.EntityName,
EntitySnakeName: util.StringUtil.ToSnakeCase(table.EntityName),
ModuleName: table.ModuleName,

View File

@@ -172,11 +172,7 @@ func (gu genUtil) ToModuleName(name string) string {
func (gu genUtil) ToClassName(name string) string {
tablePrefix := config.Config.DbTablePrefix
name = strings.TrimPrefix(name, tablePrefix)
// if config.GenConfig.IsRemoveTablePrefix && tablePrefix != "" {
// if strings.HasPrefix(name, tablePrefix) {
// name = name[len(tablePrefix):]
// }
// }
return util.StringUtil.ToCamelCase(name)
}

View File

@@ -0,0 +1,197 @@
package monitor_client
import (
"net/http"
"time"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/util"
"x_admin/util/excel"
"github.com/gin-gonic/gin"
)
type MonitorClientHandler struct{}
// @Summary 客户端信息列表
// @Tags monitor_client-客户端信息
// @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 os query string false "系统."
// @Param browser query string false "浏览器."
// @Param city query string false "城市."
// @Param width query int false "屏幕."
// @Param height query int false "屏幕高度."
// @Param ua query string false "ua记录."
// @Param clientTime query int false "客户端时间."
// @Success 200 {object} []MonitorClientResp "成功"
// @Failure 400 {object} string "请求错误"
// @Router /api/admin/monitor_client/list [get]
func (hd MonitorClientHandler) List(c *gin.Context) {
var page request.PageReq
var listReq MonitorClientListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &page)) {
return
}
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
return
}
res, err := Service.List(page, listReq)
response.CheckAndRespWithData(c, res, err)
}
// @Summary 客户端信息列表-所有
// @Tags monitor_client-客户端信息
// @Produce json
// @Success 200 {object} []MonitorClientResp "成功"
// @Router /api/admin/monitor_client/listAll [get]
func (hd MonitorClientHandler) ListAll(c *gin.Context) {
//var listReq MonitorClientListReq
//if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
// return
//}
res, err := Service.ListAll()
response.CheckAndRespWithData(c, res, err)
}
// @Summary 客户端信息详情
// @Tags monitor_client-客户端信息
// @Produce json
// @Param Token header string true "token"
// @Param id query int false "uuid."
// @Success 200 {object} MonitorClientResp "成功"
// @Router /api/admin/monitor_client/detail [get]
func (hd MonitorClientHandler) Detail(c *gin.Context) {
var detailReq MonitorClientDetailReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) {
return
}
res, err := Service.Detail(detailReq.Id)
response.CheckAndRespWithData(c, res, err)
}
// @Summary 客户端信息新增
// @Tags monitor_client-客户端信息
// @Produce json
// @Param Token header string true "token"
// @Param projectKey body string false "项目key."
// @Param clientId body string false "sdk生成的客户端id."
// @Param userId body string false "用户id."
// @Param os body string false "系统."
// @Param browser body string false "浏览器."
// @Param city body string false "城市."
// @Param width body int false "屏幕."
// @Param height body int false "屏幕高度."
// @Param ua body string false "ua记录."
// @Param clientTime body int false "客户端时间."
// @Success 200 {object} response.RespType "成功"
// @Router /api/admin/monitor_client/add [post]
func (hd MonitorClientHandler) Add(c *gin.Context) {
var addReq MonitorClientAddReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
return
}
response.CheckAndResp(c, Service.Add(addReq))
}
// @Summary 客户端信息编辑
// @Tags monitor_client-客户端信息
// @Produce json
// @Param Token header string true "token"
// @Param id body int false "uuid."
// @Param projectKey body string false "项目key."
// @Param clientId body string false "sdk生成的客户端id."
// @Param userId body string false "用户id."
// @Param os body string false "系统."
// @Param browser body string false "浏览器."
// @Param city body string false "城市."
// @Param width body int false "屏幕."
// @Param height body int false "屏幕高度."
// @Param ua body string false "ua记录."
// @Param clientTime body int false "客户端时间."
// @Success 200 {object} response.RespType "成功"
// @Router /api/admin/monitor_client/edit [post]
func (hd MonitorClientHandler) Edit(c *gin.Context) {
var editReq MonitorClientEditReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &editReq)) {
return
}
response.CheckAndResp(c, Service.Edit(editReq))
}
// @Summary 客户端信息删除
// @Tags monitor_client-客户端信息
// @Produce json
// @Param Token header string true "token"
// @Param id body int false "uuid."
// @Success 200 {object} response.RespType "成功"
// @Router /api/admin/monitor_client/del [post]
func (hd MonitorClientHandler) Del(c *gin.Context) {
var delReq MonitorClientDelReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
return
}
response.CheckAndResp(c, Service.Del(delReq.Id))
}
// @Summary 客户端信息导出
// @Tags monitor_client-客户端信息
// @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 os query string false "系统."
// @Param browser query string false "浏览器."
// @Param city query string false "城市."
// @Param width query int false "屏幕."
// @Param height query int false "屏幕高度."
// @Param ua query string false "ua记录."
// @Param clientTime query int false "客户端时间."
// @Router /api/admin/monitor_client/ExportFile [get]
func (hd MonitorClientHandler) ExportFile(c *gin.Context) {
var listReq MonitorClientListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
return
}
res, err := Service.ExportFile(listReq)
if err != nil {
response.FailWithMsg(c, response.SystemError, "查询信息失败")
return
}
f, err := excel.NormalDynamicExport(res, "Sheet1", "客户端信息", "", true, false, nil)
if err != nil {
response.FailWithMsg(c, response.SystemError, "导出失败")
return
}
excel.DownLoadExcel("客户端信息"+time.Now().Format("2006-01-02 15:04:05"), c.Writer, f)
}
// @Summary 客户端信息导入
// @Tags monitor_client-客户端信息
// @Produce json
func (hd MonitorClientHandler) ImportFile(c *gin.Context) {
file, _, err := c.Request.FormFile("file")
if err != nil {
c.String(http.StatusInternalServerError, "文件不存在")
return
}
defer file.Close()
importList := []MonitorClientResp{}
err = excel.GetExcelData(file, &importList)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
// for _, t := range importList {
// fmt.Printf("%#v", t)
// }
err = Service.ImportFile(importList)
response.CheckAndResp(c, err)
}

View File

@@ -0,0 +1,72 @@
package monitor_client
import "x_admin/core"
//MonitorClientListReq 客户端信息列表参数
type MonitorClientListReq struct {
ProjectKey string `form:"projectKey"` // 项目key
ClientId string `form:"clientId"` // sdk生成的客户端id
UserId string `form:"userId"` // 用户id
Os string `form:"os"` // 系统
Browser string `form:"browser"` // 浏览器
City string `form:"city"` // 城市
Width int `form:"width"` // 屏幕
Height int `form:"height"` // 屏幕高度
Ua string `form:"ua"` // ua记录
ClientTime string `form:"clientTime"` // 客户端时间
}
//MonitorClientDetailReq 客户端信息详情参数
type MonitorClientDetailReq struct {
Id int `form:"id"` // uuid
}
//MonitorClientAddReq 客户端信息新增参数
type MonitorClientAddReq struct {
ProjectKey string `form:"projectKey"` // 项目key
ClientId string `form:"clientId"` // sdk生成的客户端id
UserId string `form:"userId"` // 用户id
Os string `form:"os"` // 系统
Browser string `form:"browser"` // 浏览器
City string `form:"city"` // 城市
Width int `form:"width"` // 屏幕
Height int `form:"height"` // 屏幕高度
Ua string `form:"ua"` // ua记录
ClientTime core.TsTime `form:"clientTime"` // 客户端时间
}
//MonitorClientEditReq 客户端信息编辑参数
type MonitorClientEditReq struct {
Id int `form:"id"` // uuid
ProjectKey string `form:"projectKey"` // 项目key
ClientId string `form:"clientId"` // sdk生成的客户端id
UserId string `form:"userId"` // 用户id
Os string `form:"os"` // 系统
Browser string `form:"browser"` // 浏览器
City string `form:"city"` // 城市
Width int `form:"width"` // 屏幕
Height int `form:"height"` // 屏幕高度
Ua string `form:"ua"` // ua记录
ClientTime core.TsTime `form:"clientTime"` // 客户端时间
}
//MonitorClientDelReq 客户端信息新增参数
type MonitorClientDelReq struct {
Id int `form:"id"` // uuid
}
//MonitorClientResp 客户端信息返回信息
type MonitorClientResp struct {
Id int `json:"id" structs:"id" excel:"name:uuid;"` // uuid
ProjectKey string `json:"projectKey" structs:"projectKey" excel:"name:项目key;"` // 项目key
ClientId string `json:"clientId" structs:"clientId" excel:"name:sdk生成的客户端id;"` // sdk生成的客户端id
UserId string `json:"userId" structs:"userId" excel:"name:用户id;"` // 用户id
Os string `json:"os" structs:"os" excel:"name:系统;"` // 系统
Browser string `json:"browser" structs:"browser" excel:"name:浏览器;"` // 浏览器
City string `json:"city" structs:"city" excel:"name:城市;"` // 城市
Width int `json:"width" structs:"width" excel:"name:屏幕;"` // 屏幕
Height int `json:"height" structs:"height" excel:"name:屏幕高度;"` // 屏幕高度
Ua string `json:"ua" structs:"ua" excel:"name:ua记录;"` // ua记录
ClientTime int `json:"clientTime" structs:"clientTime" excel:"name:客户端时间;"` // 客户端时间
CreateTime core.TsTime `json:"createTime" structs:"createTime" excel:"name:创建时间;"` // 创建时间
}

View File

@@ -0,0 +1,262 @@
package monitor_client
import (
"x_admin/core"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model"
"gorm.io/gorm"
)
type IMonitorClientService interface {
List(page request.PageReq, listReq MonitorClientListReq) (res response.PageResp, e error)
ListAll() (res []MonitorClientResp, e error)
Detail(id int) (res MonitorClientResp, e error)
Add(addReq MonitorClientAddReq) (e error)
Edit(editReq MonitorClientEditReq) (e error)
Del(id int) (e error)
}
var Service = NewMonitorClientService()
// NewMonitorClientService 初始化
func NewMonitorClientService() *monitorClientService {
db := core.GetDB()
return &monitorClientService{db: db}
}
// monitorClientService 客户端信息服务实现类
type monitorClientService struct {
db *gorm.DB
}
func (service monitorClientService) GetModel(listReq MonitorClientListReq) *gorm.DB {
// 查询
dbModel := service.db.Model(&model.MonitorClient{})
if listReq.ProjectKey != "" {
dbModel = dbModel.Where("project_key = ?", listReq.ProjectKey)
}
if listReq.ClientId != "" {
dbModel = dbModel.Where("client_id = ?", listReq.ClientId)
}
if listReq.UserId != "" {
dbModel = dbModel.Where("user_id = ?", listReq.UserId)
}
if listReq.Os != "" {
dbModel = dbModel.Where("os = ?", listReq.Os)
}
if listReq.Browser != "" {
dbModel = dbModel.Where("browser = ?", listReq.Browser)
}
if listReq.City != "" {
dbModel = dbModel.Where("city = ?", listReq.City)
}
if listReq.Width > 0 {
dbModel = dbModel.Where("width = ?", listReq.Width)
}
if listReq.Height > 0 {
dbModel = dbModel.Where("height = ?", listReq.Height)
}
if listReq.Ua != "" {
dbModel = dbModel.Where("ua = ?", listReq.Ua)
}
if len(listReq.ClientTime) == 2 {
// dbModel = dbModel.Where("client_time = ?", listReq.ClientTime)
dbModel = dbModel.Where("client_time >= ?", listReq.ClientTime[0]).Where("client_time <= ?", listReq.ClientTime[1])
}
return dbModel
}
// List 客户端信息列表
func (service monitorClientService) List(page request.PageReq, listReq MonitorClientListReq) (res response.PageResp, e error) {
// 分页信息
limit := page.PageSize
offset := page.PageSize * (page.PageNo - 1)
dbModel := service.GetModel(listReq)
// 查询
// dbModel := service.db.Model(&model.MonitorClient{})
// if listReq.ProjectKey != "" {
// dbModel = dbModel.Where("project_key = ?", listReq.ProjectKey)
// }
// if listReq.ClientId != "" {
// dbModel = dbModel.Where("client_id = ?", listReq.ClientId)
// }
// if listReq.UserId != "" {
// dbModel = dbModel.Where("user_id = ?", listReq.UserId)
// }
// if listReq.Os != "" {
// dbModel = dbModel.Where("os = ?", listReq.Os)
// }
// if listReq.Browser != "" {
// dbModel = dbModel.Where("browser = ?", listReq.Browser)
// }
// if listReq.City != "" {
// dbModel = dbModel.Where("city = ?", listReq.City)
// }
// if listReq.Width > 0 {
// dbModel = dbModel.Where("width = ?", listReq.Width)
// }
// if listReq.Height > 0 {
// dbModel = dbModel.Where("height = ?", listReq.Height)
// }
// if listReq.Ua != "" {
// dbModel = dbModel.Where("ua = ?", listReq.Ua)
// }
// if listReq.ClientTime > 0 {
// dbModel = dbModel.Where("client_time = ?", listReq.ClientTime)
// }
// 总数
var count int64
err := dbModel.Count(&count).Error
if e = response.CheckErr(err, "List Count err"); e != nil {
return
}
// 数据
var objs []model.MonitorClient
err = dbModel.Limit(limit).Offset(offset).Order("id desc").Find(&objs).Error
if e = response.CheckErr(err, "List Find err"); e != nil {
return
}
resps := []MonitorClientResp{}
response.Copy(&resps, objs)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
Count: count,
Lists: resps,
}, nil
}
// ListAll 客户端信息列表
func (service monitorClientService) ListAll() (res []MonitorClientResp, e error) {
var objs []model.MonitorClient
err := service.db.Find(&objs).Error
if e = response.CheckErr(err, "ListAll Find err"); e != nil {
return
}
response.Copy(&res, objs)
return res, nil
}
// Detail 客户端信息详情
func (service monitorClientService) Detail(id int) (res MonitorClientResp, e error) {
var obj model.MonitorClient
err := service.db.Where("id = ?", id).Limit(1).First(&obj).Error
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "Detail First err"); e != nil {
return
}
response.Copy(&res, obj)
return
}
// Add 客户端信息新增
func (service monitorClientService) Add(addReq MonitorClientAddReq) (e error) {
var obj model.MonitorClient
response.Copy(&obj, addReq)
err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err)
if e != nil {
return e
}
e = response.CheckErr(err, "Add Create err")
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, "Edit First err"); e != nil {
return
}
// 更新
response.Copy(&obj, editReq)
err = service.db.Model(&obj).Updates(obj).Error
e = response.CheckErr(err, "Edit Updates err")
return
}
// Del 客户端信息删除
func (service monitorClientService) Del(id int) (e error) {
var obj model.MonitorClient
err := service.db.Where("id = ?", id).Limit(1).First(&obj).Error
// 校验
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "Del First err"); e != nil {
return
}
// 删除
err = service.db.Delete(&obj).Error
e = response.CheckErr(err, "Del Delete err")
return
}
// ExportFile 客户端信息导出
func (service monitorClientService) ExportFile(listReq MonitorClientListReq) (res []MonitorClientResp, e error) {
// 查询
dbModel := service.GetModel(listReq)
// dbModel := service.db.Model(&model.MonitorClient{})
// if listReq.ProjectKey != "" {
// dbModel = dbModel.Where("project_key = ?", listReq.ProjectKey)
// }
// if listReq.ClientId != "" {
// dbModel = dbModel.Where("client_id = ?", listReq.ClientId)
// }
// if listReq.UserId != "" {
// dbModel = dbModel.Where("user_id = ?", listReq.UserId)
// }
// if listReq.Os != "" {
// dbModel = dbModel.Where("os = ?", listReq.Os)
// }
// if listReq.Browser != "" {
// dbModel = dbModel.Where("browser = ?", listReq.Browser)
// }
// if listReq.City != "" {
// dbModel = dbModel.Where("city = ?", listReq.City)
// }
// if listReq.Width > 0 {
// dbModel = dbModel.Where("width = ?", listReq.Width)
// }
// if listReq.Height > 0 {
// dbModel = dbModel.Where("height = ?", listReq.Height)
// }
// if listReq.Ua != "" {
// dbModel = dbModel.Where("ua = ?", listReq.Ua)
// }
// if listReq.ClientTime > 0 {
// dbModel = dbModel.Where("client_time = ?", listReq.ClientTime)
// }
// 数据
var objs []model.MonitorClient
err := dbModel.Order("id asc").Find(&objs).Error
if e = response.CheckErr(err, "List Find err"); e != nil {
return
}
resps := []MonitorClientResp{}
response.Copy(&resps, objs)
return resps, nil
}
// 导入
func (service monitorClientService) ImportFile(importReq []MonitorClientResp) (e error) {
var importData []model.MonitorClient
response.Copy(&importData, importReq)
err := service.db.Create(&importData).Error
e = response.CheckErr(err, "Add Create err")
return e
}

View File

@@ -0,0 +1,41 @@
package admin
import (
"x_admin/admin/monitor_client"
"x_admin/middleware"
"github.com/gin-gonic/gin"
)
/**
集成
1. 导入
- 请先提交git避免文件覆盖!!!
- 下载并解压压缩包后直接复制server、admin文件夹到项目根目录即可
2. 注册路由
请在 admin/entry.go 文件引入MonitorClientRoute注册路由
3. 后台手动添加菜单和按钮
monitor_client:add
monitor_client:edit
monitor_client:del
monitor_client:list
monitor_client:listAll
monitor_client:detail
*/
// MonitorClientRoute(rg)
func MonitorClientRoute(rg *gin.RouterGroup) {
handle := monitor_client.MonitorClientHandler{}
rg = rg.Group("/", middleware.TokenAuth())
rg.GET("/monitor_client/list", handle.List)
rg.GET("/monitor_client/listAll", handle.ListAll)
rg.GET("/monitor_client/detail", handle.Detail)
rg.POST("/monitor_client/add", middleware.RecordLog("客户端信息新增"), handle.Add)
rg.POST("/monitor_client/edit", middleware.RecordLog("客户端信息编辑"), handle.Edit)
rg.POST("/monitor_client/del", middleware.RecordLog("客户端信息删除"), handle.Del)
rg.GET("/monitor_client/ExportFile", middleware.RecordLog("客户端信息导出"), handle.ExportFile)
rg.POST("/monitor_client/ImportFile", handle.ImportFile)
}

View File

@@ -0,0 +1,169 @@
package monitor_project
import (
"fmt"
"net/http"
"time"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/util"
"x_admin/util/excel"
"github.com/gin-gonic/gin"
)
type MonitorProjectHandler struct{}
// @Summary 错误项目列表
// @Tags monitor_project-错误项目
// @Produce json
// @Param Token header string true "token"
// @Param PageNo query int true "页码"
// @Param PageSize query int true "每页数量"
// @Param projectKey query string false "项目uuid."
// @Param projectName query string false "项目名称."
// @Param projectType query string false "项目类型go java web node php 等."
// @Success 200 {object} []MonitorProjectResp "成功"
// @Failure 400 {object} string "请求错误"
// @Router /api/admin/monitor_project/list [get]
func (hd MonitorProjectHandler) List(c *gin.Context) {
var page request.PageReq
var listReq MonitorProjectListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &page)) {
return
}
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
return
}
res, err := Service.List(page, listReq)
response.CheckAndRespWithData(c, res, err)
}
// @Summary 错误项目列表-所有
// @Tags monitor_project-错误项目
// @Produce json
// @Success 200 {object} []MonitorProjectResp "成功"
// @Router /api/admin/monitor_project/listAll [get]
func (hd MonitorProjectHandler) ListAll(c *gin.Context) {
res, err := Service.ListAll()
// var listReq MonitorProjectListReq
// if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
// return
// }
response.CheckAndRespWithData(c, res, err)
}
// @Summary 错误项目详情
// @Tags monitor_project-错误项目
// @Produce json
// @Param Token header string true "token"
// @Param id query int false "项目id."
// @Success 200 {object} MonitorProjectResp "成功"
// @Router /api/admin/monitor_project/detail [get]
func (hd MonitorProjectHandler) Detail(c *gin.Context) {
var detailReq MonitorProjectDetailReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) {
return
}
res, err := Service.Detail(detailReq.Id)
response.CheckAndRespWithData(c, res, err)
}
// @Summary 错误项目新增
// @Tags monitor_project-错误项目
// @Produce json
// @Param Token header string true "token"
// @Param projectKey body string false "项目uuid."
// @Param projectName body string false "项目名称."
// @Param projectType body string false "项目类型go java web node php 等."
// @Success 200 {object} response.RespType "成功"
// @Router /api/admin/monitor_project/add [post]
func (hd MonitorProjectHandler) Add(c *gin.Context) {
var addReq MonitorProjectAddReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
return
}
response.CheckAndResp(c, Service.Add(addReq))
}
// @Summary 错误项目编辑
// @Tags monitor_project-错误项目
// @Produce json
// @Param Token header string true "token"
// @Param id body int false "项目id."
// @Param projectKey body string false "项目uuid."
// @Param projectName body string false "项目名称."
// @Param projectType body string false "项目类型go java web node php 等."
// @Success 200 {object} response.RespType "成功"
// @Router /api/admin/monitor_project/edit [post]
func (hd MonitorProjectHandler) Edit(c *gin.Context) {
var editReq MonitorProjectEditReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &editReq)) {
return
}
response.CheckAndResp(c, Service.Edit(editReq))
}
// @Summary 错误项目删除
// @Tags monitor_project-错误项目
// @Produce json
// @Param Token header string true "token"
// @Param id body int false "项目id."
// @Success 200 {object} response.RespType "成功"
// @Router /api/admin/monitor_project/del [post]
func (hd MonitorProjectHandler) Del(c *gin.Context) {
var delReq MonitorProjectDelReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
return
}
response.CheckAndResp(c, Service.Del(delReq.Id))
}
// @Summary 错误项目导出
// @Tags monitor_project-错误项目
// @Produce json
// @Param Token header string true "token"
// @Param projectKey query string false "项目uuid."
// @Param projectName query string false "项目名称."
// @Param projectType query string false "项目类型go java web node php 等."
// @Router /api/admin/monitor_project/ExportFile [get]
func (hd MonitorProjectHandler) ExportFile(c *gin.Context) {
var listReq MonitorProjectListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
return
}
res, err := Service.ExportFile(listReq)
if err != nil {
response.FailWithMsg(c, response.SystemError, "查询信息失败")
return
}
f, err := excel.NormalDynamicExport(res, "Sheet1", "错误项目", "", true, false, nil)
if err != nil {
response.FailWithMsg(c, response.SystemError, "导出失败")
return
}
excel.DownLoadExcel("错误项目"+time.Now().Format("2006-01-02 15:04:05"), c.Writer, f)
}
// @Summary 错误项目导入
// @Tags monitor_project-错误项目
// @Produce json
func (hd MonitorProjectHandler) ImportFile(c *gin.Context) {
file, _, err := c.Request.FormFile("file")
if err != nil {
c.String(http.StatusInternalServerError, "文件不存在")
return
}
defer file.Close()
importList := []MonitorProjectResp{}
err = excel.GetExcelData(file, &importList)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
for _, t := range importList {
fmt.Printf("%#v", t)
}
err = Service.ImportFile(importList)
response.CheckAndResp(c, err)
}

View File

@@ -0,0 +1,45 @@
package monitor_project
import "x_admin/core"
//MonitorProjectListReq 错误项目列表参数
type MonitorProjectListReq struct {
ProjectKey string `form:"projectKey"` // 项目uuid
ProjectName string `form:"projectName"` // 项目名称
ProjectType string `form:"projectType"` // 项目类型go java web node php 等
}
//MonitorProjectDetailReq 错误项目详情参数
type MonitorProjectDetailReq struct {
Id int `form:"id"` // 项目id
}
//MonitorProjectAddReq 错误项目新增参数
type MonitorProjectAddReq struct {
// ProjectKey string `form:"projectKey"` // 项目uuid
ProjectName string `form:"projectName"` // 项目名称
ProjectType string `form:"projectType"` // 项目类型go java web node php 等
}
//MonitorProjectEditReq 错误项目编辑参数
type MonitorProjectEditReq struct {
Id int `form:"id"` // 项目id
// ProjectKey string `form:"projectKey"` // 项目uuid
ProjectName string `form:"projectName"` // 项目名称
ProjectType string `form:"projectType"` // 项目类型go java web node php 等
}
//MonitorProjectDelReq 错误项目新增参数
type MonitorProjectDelReq struct {
Id int `form:"id"` // 项目id
}
//MonitorProjectResp 错误项目返回信息
type MonitorProjectResp struct {
Id int `json:"id" structs:"id" excel:"name:项目id;"` // 项目id
ProjectKey string `json:"projectKey" structs:"projectKey" excel:"name:项目uuid;"` // 项目uuid
ProjectName string `json:"projectName" structs:"projectName" excel:"name:项目名称;"` // 项目名称
ProjectType string `json:"projectType" structs:"projectType" excel:"name:项目类型go java web node php 等;"` // 项目类型go java web node php 等
UpdateTime core.TsTime `json:"updateTime" structs:"updateTime" excel:"name:更新时间;"` // 更新时间
CreateTime core.TsTime `json:"createTime" structs:"createTime" excel:"name:创建时间;"` // 创建时间
}

View File

@@ -0,0 +1,184 @@
package monitor_project
import (
"x_admin/core"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model"
"x_admin/util"
"gorm.io/gorm"
)
type IMonitorProjectService interface {
List(page request.PageReq, listReq MonitorProjectListReq) (res response.PageResp, e error)
ListAll() (res []MonitorProjectResp, e error)
Detail(id int) (res MonitorProjectResp, e error)
Add(addReq MonitorProjectAddReq) (e error)
Edit(editReq MonitorProjectEditReq) (e error)
Del(id int) (e error)
}
var Service = NewMonitorProjectService()
// NewMonitorProjectService 初始化
func NewMonitorProjectService() *monitorProjectService {
db := core.GetDB()
return &monitorProjectService{db: db}
}
// monitorProjectService 错误项目服务实现类
type monitorProjectService struct {
db *gorm.DB
}
// List 错误项目列表
func (service monitorProjectService) List(page request.PageReq, listReq MonitorProjectListReq) (res response.PageResp, e error) {
// 分页信息
limit := page.PageSize
offset := page.PageSize * (page.PageNo - 1)
// 查询
dbModel := service.db.Model(&model.MonitorProject{})
if listReq.ProjectKey != "" {
dbModel = dbModel.Where("project_key = ?", listReq.ProjectKey)
}
if listReq.ProjectName != "" {
dbModel = dbModel.Where("project_name like ?", "%"+listReq.ProjectName+"%")
}
if listReq.ProjectType != "" {
dbModel = dbModel.Where("project_type = ?", listReq.ProjectType)
}
dbModel = dbModel.Where("is_delete = ?", 0)
// 总数
var count int64
err := dbModel.Count(&count).Error
if e = response.CheckErr(err, "List Count err"); e != nil {
return
}
// 数据
var objs []model.MonitorProject
err = dbModel.Limit(limit).Offset(offset).Order("id desc").Find(&objs).Error
if e = response.CheckErr(err, "List Find err"); e != nil {
return
}
resps := []MonitorProjectResp{}
response.Copy(&resps, objs)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
Count: count,
Lists: resps,
}, nil
}
// ListAll 错误项目列表
func (service monitorProjectService) ListAll() (res []MonitorProjectResp, e error) {
var objs []model.MonitorProject
err := service.db.Find(&objs).Error
if e = response.CheckErr(err, "ListAll Find err"); e != nil {
return
}
response.Copy(&res, objs)
return res, nil
}
// Detail 错误项目详情
func (service monitorProjectService) Detail(id int) (res MonitorProjectResp, e error) {
var obj model.MonitorProject
err := service.db.Where("id = ? AND is_delete = ?", id, 0).Limit(1).First(&obj).Error
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "Detail First err"); e != nil {
return
}
response.Copy(&res, obj)
return
}
// Add 错误项目新增
func (service monitorProjectService) Add(addReq MonitorProjectAddReq) (e error) {
var obj model.MonitorProject
response.Copy(&obj, addReq)
obj.ProjectKey = util.ToolsUtil.MakeUuid()
err := service.db.Create(&obj).Error
if e = response.CheckMysqlErr(err); e != nil {
return e
}
e = response.CheckErr(err, "Add Create err")
return
}
// Edit 错误项目编辑
func (service monitorProjectService) Edit(editReq MonitorProjectEditReq) (e error) {
var obj model.MonitorProject
err := service.db.Where("id = ? AND is_delete = ?", editReq.Id, 0).Limit(1).First(&obj).Error
// 校验
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "Edit First err"); e != nil {
return
}
// 更新
response.Copy(&obj, editReq)
err = service.db.Model(&obj).Updates(obj).Error
e = response.CheckErr(err, "Edit Updates err")
return
}
// Del 错误项目删除
func (service monitorProjectService) Del(id int) (e error) {
var obj model.MonitorProject
err := service.db.Where("id = ? AND is_delete = ?", id, 0).Limit(1).First(&obj).Error
// 校验
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "Del First err"); e != nil {
return
}
// 删除
obj.IsDelete = 1
err = service.db.Save(&obj).Error
e = response.CheckErr(err, "Del Save err")
return
}
// ExportFile 错误项目导出
func (service monitorProjectService) ExportFile(listReq MonitorProjectListReq) (res []MonitorProjectResp, e error) {
// 查询
dbModel := service.db.Model(&model.MonitorProject{})
if listReq.ProjectKey != "" {
dbModel = dbModel.Where("project_key = ?", listReq.ProjectKey)
}
if listReq.ProjectName != "" {
dbModel = dbModel.Where("project_name like ?", "%"+listReq.ProjectName+"%")
}
if listReq.ProjectType != "" {
dbModel = dbModel.Where("project_type = ?", listReq.ProjectType)
}
dbModel = dbModel.Where("is_delete = ?", 0)
// 数据
var objs []model.MonitorProject
err := dbModel.Order("id asc").Find(&objs).Error
if e = response.CheckErr(err, "List Find err"); e != nil {
return
}
resps := []MonitorProjectResp{}
response.Copy(&resps, objs)
return resps, nil
}
// 导入
func (service monitorProjectService) ImportFile(importReq []MonitorProjectResp) (e error) {
var importData []model.MonitorProject
response.Copy(&importData, importReq)
err := service.db.Create(&importData).Error
e = response.CheckErr(err, "Add Create err")
return e
}

View File

@@ -0,0 +1,41 @@
package admin
import (
"x_admin/admin/monitor_project"
"x_admin/middleware"
"github.com/gin-gonic/gin"
)
/**
集成
1. 导入
- 请先提交git避免文件覆盖!!!
- 下载并解压压缩包后直接复制server、admin文件夹到项目根目录即可
2. 注册路由
请在 admin/entry.go 文件引入MonitorProjectRoute注册路由
3. 后台手动添加菜单和按钮
monitor_project:add
monitor_project:edit
monitor_project:del
monitor_project:list
monitor_project:listAll
monitor_project:detail
*/
// MonitorProjectRoute(rg)
func MonitorProjectRoute(rg *gin.RouterGroup) {
handle := monitor_project.MonitorProjectHandler{}
rg = rg.Group("/", middleware.TokenAuth())
rg.GET("/monitor_project/list", handle.List)
rg.GET("/monitor_project/listAll", handle.ListAll)
rg.GET("/monitor_project/detail", handle.Detail)
rg.POST("/monitor_project/add", middleware.RecordLog("错误项目新增"), handle.Add)
rg.POST("/monitor_project/edit", middleware.RecordLog("错误项目编辑"), handle.Edit)
rg.POST("/monitor_project/del", middleware.RecordLog("错误项目删除"), handle.Del)
rg.GET("/monitor_project/ExportFile", middleware.RecordLog("错误项目导出"), handle.ExportFile)
rg.POST("/monitor_project/ImportFile", handle.ImportFile)
}

View File

@@ -0,0 +1,186 @@
package monitor_web
import (
"fmt"
"net/http"
"time"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/util"
"x_admin/util/excel"
"github.com/gin-gonic/gin"
)
type MonitorWebHandler struct{}
// @Summary 错误收集error列表
// @Tags monitor_web-错误收集error
// @Produce json
// @Param Token header string true "token"
// @Param PageNo query int true "页码"
// @Param PageSize query int true "每页数量"
// @Param projectKey query string false "项目key."
// @Param clientId query string false "sdk生成的客户端id."
// @Param eventType query string false "事件类型."
// @Param page query string false "URL地址."
// @Param message query string false "错误消息."
// @Param stack query string false "错误堆栈."
// @Param clientTime query int false "客户端时间."
// @Success 200 {object} []MonitorWebResp "成功"
// @Failure 400 {object} string "请求错误"
// @Router /api/admin/monitor_web/list [get]
func (hd MonitorWebHandler) List(c *gin.Context) {
var page request.PageReq
var listReq MonitorWebListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &page)) {
return
}
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
return
}
res, err := Service.List(page, listReq)
response.CheckAndRespWithData(c, res, err)
}
// @Summary 错误收集error列表-所有
// @Tags monitor_web-错误收集error
// @Produce json
// @Success 200 {object} []MonitorWebResp "成功"
// @Router /api/admin/monitor_web/listAll [get]
func (hd MonitorWebHandler) ListAll(c *gin.Context) {
//var listReq MonitorWebListReq
//if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
// return
//}
res, err := Service.ListAll()
response.CheckAndRespWithData(c, res, err)
}
// @Summary 错误收集error详情
// @Tags monitor_web-错误收集error
// @Produce json
// @Param Token header string true "token"
// @Param id query int false "uuid."
// @Success 200 {object} MonitorWebResp "成功"
// @Router /api/admin/monitor_web/detail [get]
func (hd MonitorWebHandler) Detail(c *gin.Context) {
var detailReq MonitorWebDetailReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) {
return
}
res, err := Service.Detail(detailReq.Id)
response.CheckAndRespWithData(c, res, err)
}
// @Summary 错误收集error新增
// @Tags monitor_web-错误收集error
// @Produce json
// @Param Token header string true "token"
// @Param projectKey body string false "项目key."
// @Param clientId body string false "sdk生成的客户端id."
// @Param eventType body string false "事件类型."
// @Param page body string false "URL地址."
// @Param message body string false "错误消息."
// @Param stack body string false "错误堆栈."
// @Param clientTime body int false "客户端时间."
// @Success 200 {object} response.RespType "成功"
// @Router /api/admin/monitor_web/add [post]
func (hd MonitorWebHandler) Add(c *gin.Context) {
var addReq MonitorWebAddReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
return
}
response.CheckAndResp(c, Service.Add(addReq))
}
// @Summary 错误收集error编辑
// @Tags monitor_web-错误收集error
// @Produce json
// @Param Token header string true "token"
// @Param id body int false "uuid."
// @Param projectKey body string false "项目key."
// @Param clientId body string false "sdk生成的客户端id."
// @Param eventType body string false "事件类型."
// @Param page body string false "URL地址."
// @Param message body string false "错误消息."
// @Param stack body string false "错误堆栈."
// @Param clientTime body int false "客户端时间."
// @Success 200 {object} response.RespType "成功"
// @Router /api/admin/monitor_web/edit [post]
func (hd MonitorWebHandler) Edit(c *gin.Context) {
var editReq MonitorWebEditReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &editReq)) {
return
}
response.CheckAndResp(c, Service.Edit(editReq))
}
// @Summary 错误收集error删除
// @Tags monitor_web-错误收集error
// @Produce json
// @Param Token header string true "token"
// @Param id body int false "uuid."
// @Success 200 {object} response.RespType "成功"
// @Router /api/admin/monitor_web/del [post]
func (hd MonitorWebHandler) Del(c *gin.Context) {
var delReq MonitorWebDelReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
return
}
response.CheckAndResp(c, Service.Del(delReq.Id))
}
// @Summary 错误收集error导出
// @Tags monitor_web-错误收集error
// @Produce json
// @Param Token header string true "token"
// @Param projectKey query string false "项目key."
// @Param clientId query string false "sdk生成的客户端id."
// @Param eventType query string false "事件类型."
// @Param page query string false "URL地址."
// @Param message query string false "错误消息."
// @Param stack query string false "错误堆栈."
// @Param clientTime query int false "客户端时间."
// @Router /api/admin/monitor_web/ExportFile [get]
func (hd MonitorWebHandler) ExportFile(c *gin.Context) {
var listReq MonitorWebListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
return
}
res, err := Service.ExportFile(listReq)
if err != nil {
response.FailWithMsg(c, response.SystemError, "查询信息失败")
return
}
f, err := excel.NormalDynamicExport(res, "Sheet1", "错误收集error", "", true, false, nil)
if err != nil {
response.FailWithMsg(c, response.SystemError, "导出失败")
return
}
excel.DownLoadExcel("错误收集error"+time.Now().Format("20060102-150405"), c.Writer, f)
}
// @Summary 错误收集error导入
// @Tags monitor_web-错误收集error
// @Produce json
func (hd MonitorWebHandler) ImportFile(c *gin.Context) {
file, _, err := c.Request.FormFile("file")
if err != nil {
c.String(http.StatusInternalServerError, "文件不存在")
return
}
defer file.Close()
importList := []MonitorWebResp{}
err = excel.GetExcelData(file, &importList)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
for _, t := range importList {
fmt.Printf("%#v", t)
}
err = Service.ImportFile(importList)
response.CheckAndResp(c, err)
}

View File

@@ -0,0 +1,63 @@
package monitor_web
import "x_admin/core"
//MonitorWebListReq 错误收集error列表参数
type MonitorWebListReq struct {
ProjectKey string `form:"projectKey"` // 项目key
ClientId string `form:"clientId"` // sdk生成的客户端id
EventType string `form:"eventType"` // 事件类型
Page string `form:"page"` // URL地址
Message string `form:"message"` // 错误消息
Stack string `form:"stack"` // 错误堆栈
ClientTimeStart string `form:"clientTimeStart"` // 开始客户端时间
ClientTimeEnd string `form:"clientTimeEnd"` // 结束客户端时间
CreateTimeStart string `form:"createTimeStart"` // 开始创建时间
CreateTimeEnd string `form:"createTimeEnd"` // 结束创建时间
}
//MonitorWebDetailReq 错误收集error详情参数
type MonitorWebDetailReq struct {
Id int `form:"id"` // uuid
}
//MonitorWebAddReq 错误收集error新增参数
type MonitorWebAddReq struct {
ProjectKey string `form:"projectKey"` // 项目key
ClientId string `form:"clientId"` // sdk生成的客户端id
EventType string `form:"eventType"` // 事件类型
Page string `form:"page"` // URL地址
Message string `form:"message"` // 错误消息
Stack string `form:"stack"` // 错误堆栈
ClientTime core.TsTime `form:"clientTime"` // 客户端时间
}
//MonitorWebEditReq 错误收集error编辑参数
type MonitorWebEditReq struct {
Id int `form:"id"` // uuid
ProjectKey string `form:"projectKey"` // 项目key
ClientId string `form:"clientId"` // sdk生成的客户端id
EventType string `form:"eventType"` // 事件类型
Page string `form:"page"` // URL地址
Message string `form:"message"` // 错误消息
Stack string `form:"stack"` // 错误堆栈
ClientTime core.TsTime `form:"clientTime"` // 客户端时间
}
//MonitorWebDelReq 错误收集error新增参数
type MonitorWebDelReq struct {
Id int `form:"id"` // uuid
}
//MonitorWebResp 错误收集error返回信息
type MonitorWebResp struct {
Id int `json:"id" structs:"id"` // uuid
ProjectKey string `json:"projectKey" structs:"projectKey" excel:"name:项目key;"` // 项目key
ClientId string `json:"clientId" structs:"clientId" excel:"name:sdk生成的客户端id;"` // sdk生成的客户端id
EventType string `json:"eventType" structs:"eventType" excel:"name:事件类型;"` // 事件类型
Page string `json:"page" structs:"page" excel:"name:URL地址;"` // URL地址
Message string `json:"message" structs:"message" excel:"name:错误消息;"` // 错误消息
Stack string `json:"stack" structs:"stack" excel:"name:错误堆栈;"` // 错误堆栈
ClientTime core.TsTime `json:"clientTime" structs:"clientTime" excel:"name:客户端时间;"` // 客户端时间
CreateTime core.TsTime `json:"createTime" structs:"createTime" excel:"name:创建时间;"` // 创建时间
}

View File

@@ -0,0 +1,217 @@
package monitor_web
import (
"x_admin/core"
"x_admin/core/request"
"x_admin/core/response"
"x_admin/model"
"gorm.io/gorm"
)
// type IMonitorWebService interface {
// List(page request.PageReq, listReq MonitorWebListReq) (res response.PageResp, e error)
// ListAll() (res []MonitorWebResp, e error)
//
// Detail(id int) (res MonitorWebResp, e error)
// Add(addReq MonitorWebAddReq) (e error)
// Edit(editReq MonitorWebEditReq) (e error)
// Del(id int) (e error)
// }
var Service = NewMonitorWebService()
// NewMonitorWebService 初始化
func NewMonitorWebService() *monitorWebService {
db := core.GetDB()
return &monitorWebService{db: db}
}
// monitorWebService 错误收集error服务实现类
type monitorWebService struct {
db *gorm.DB
}
// List 错误收集error列表
func (service monitorWebService) List(page request.PageReq, listReq MonitorWebListReq) (res response.PageResp, e error) {
// 分页信息
limit := page.PageSize
offset := page.PageSize * (page.PageNo - 1)
// 查询
dbModel := service.db.Model(&model.MonitorWeb{})
if listReq.ProjectKey != "" {
dbModel = dbModel.Where("project_key = ?", listReq.ProjectKey)
}
if listReq.ClientId != "" {
dbModel = dbModel.Where("client_id = ?", listReq.ClientId)
}
if listReq.EventType != "" {
dbModel = dbModel.Where("event_type = ?", listReq.EventType)
}
if listReq.Page != "" {
dbModel = dbModel.Where("page = ?", listReq.Page)
}
if listReq.Message != "" {
dbModel = dbModel.Where("message = ?", listReq.Message)
}
if listReq.Stack != "" {
dbModel = dbModel.Where("stack = ?", listReq.Stack)
}
if listReq.ClientTimeStart != "" {
dbModel = dbModel.Where("client_time >= UNIX_TIMESTAMP(?)", listReq.ClientTimeStart)
}
if listReq.ClientTimeEnd != "" {
dbModel = dbModel.Where("client_time <= UNIX_TIMESTAMP(?)", listReq.ClientTimeEnd)
}
if listReq.CreateTimeStart != "" {
dbModel = dbModel.Where("create_time >= UNIX_TIMESTAMP(?)", listReq.CreateTimeStart)
}
if listReq.CreateTimeEnd != "" {
dbModel = dbModel.Where("create_time <= UNIX_TIMESTAMP(?)", listReq.CreateTimeEnd)
}
// if len(listReq.ClientTime) == 2 {
// dbModel = dbModel.Where("client_time >= ?", listReq.ClientTime[0]).Where("client_time <= ?", listReq.ClientTime[1])
// }
// 总数
var count int64
err := dbModel.Count(&count).Error
if e = response.CheckErr(err, "List Count err"); e != nil {
return
}
// 数据
var objs []model.MonitorWeb
err = dbModel.Limit(limit).Offset(offset).Order("id desc").Find(&objs).Error
if e = response.CheckErr(err, "List Find err"); e != nil {
return
}
resps := []MonitorWebResp{}
response.Copy(&resps, objs)
return response.PageResp{
PageNo: page.PageNo,
PageSize: page.PageSize,
Count: count,
Lists: resps,
}, nil
}
// ListAll 错误收集error列表
func (service monitorWebService) ListAll() (res []MonitorWebResp, e error) {
var objs []model.MonitorWeb
err := service.db.Find(&objs).Error
if e = response.CheckErr(err, "ListAll Find err"); e != nil {
return
}
response.Copy(&res, objs)
return res, nil
}
// Detail 错误收集error详情
func (service monitorWebService) Detail(id int) (res MonitorWebResp, e error) {
var obj model.MonitorWeb
err := service.db.Where("id = ?", id).Limit(1).First(&obj).Error
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "Detail First err"); e != nil {
return
}
response.Copy(&res, obj)
return
}
// Add 错误收集error新增
func (service monitorWebService) Add(addReq MonitorWebAddReq) (e error) {
var obj model.MonitorWeb
response.Copy(&obj, addReq)
err := service.db.Create(&obj).Error
e = response.CheckMysqlErr(err)
if e != nil {
return e
}
e = response.CheckErr(err, "Add Create err")
return
}
// Edit 错误收集error编辑
func (service monitorWebService) Edit(editReq MonitorWebEditReq) (e error) {
var obj model.MonitorWeb
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, "Edit First err"); e != nil {
return
}
// 更新
response.Copy(&obj, editReq)
err = service.db.Model(&obj).Updates(obj).Error
e = response.CheckErr(err, "Edit Updates err")
return
}
// Del 错误收集error删除
func (service monitorWebService) Del(id int) (e error) {
var obj model.MonitorWeb
err := service.db.Where("id = ?", id).Limit(1).First(&obj).Error
// 校验
if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
return
}
if e = response.CheckErr(err, "Del First err"); e != nil {
return
}
// 删除
err = service.db.Delete(&obj).Error
e = response.CheckErr(err, "Del Delete err")
return
}
// ExportFile 错误收集error导出
func (service monitorWebService) ExportFile(listReq MonitorWebListReq) (res []MonitorWebResp, e error) {
// 查询
dbModel := service.db.Model(&model.MonitorWeb{})
if listReq.ProjectKey != "" {
dbModel = dbModel.Where("project_key = ?", listReq.ProjectKey)
}
if listReq.ClientId != "" {
dbModel = dbModel.Where("client_id = ?", listReq.ClientId)
}
if listReq.EventType != "" {
dbModel = dbModel.Where("event_type = ?", listReq.EventType)
}
if listReq.Page != "" {
dbModel = dbModel.Where("page = ?", listReq.Page)
}
if listReq.Message != "" {
dbModel = dbModel.Where("message = ?", listReq.Message)
}
if listReq.Stack != "" {
dbModel = dbModel.Where("stack = ?", listReq.Stack)
}
// if len(listReq.ClientTime) > 0 {
// dbModel = dbModel.Where("client_time = ?", listReq.ClientTime)
// }
// if len(listReq.ClientTime) == 2 {
// dbModel = dbModel.Where("client_time > ?", listReq.ClientTime[0]).Where("client_time < ?", listReq.ClientTime[1])
// }
// 数据
var objs []model.MonitorWeb
err := dbModel.Order("id asc").Find(&objs).Error
if e = response.CheckErr(err, "List Find err"); e != nil {
return
}
resps := []MonitorWebResp{}
response.Copy(&resps, objs)
return resps, nil
}
// 导入
func (service monitorWebService) ImportFile(importReq []MonitorWebResp) (e error) {
var importData []model.MonitorWeb
response.Copy(&importData, importReq)
err := service.db.Create(&importData).Error
e = response.CheckErr(err, "Add Create err")
return e
}

View File

@@ -0,0 +1,55 @@
package admin
import (
"github.com/gin-gonic/gin"
"x_admin/middleware"
"x_admin/admin/monitor_web"
)
/**
集成
1. 导入
- 请先提交git避免文件覆盖!!!
- 下载并解压压缩包后直接复制server、admin文件夹到项目根目录即可
2. 注册路由
请在 admin/entry.go 文件引入MonitorWebRoute注册路由
3. 后台手动添加菜单和按钮
admin:monitor_web:add
admin:monitor_web:edit
admin:monitor_web:del
admin:monitor_web:list
admin:monitor_web:listAll
admin:monitor_web:detail
admin:monitor_web:ExportFile
admin:monitor_web:ImportFile
// 列表
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', '错误收集error', '/monitor_web/index', 'monitor_web/index', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
按钮
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', '错误收集error添加','admin:monitor_web:add', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
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', '错误收集error编辑','admin:monitor_web:edit', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
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', '错误收集error删除','admin:monitor_web:del', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
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', '错误收集error列表','admin:monitor_web:list', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
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', '错误收集error全部列表','admin:monitor_web:listAll', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
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', '错误收集error详情','admin:monitor_web:detail', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
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', '错误收集error导出excel','admin:monitor_web:ExportFile', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
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', '错误收集error导入excel','admin:monitor_web:ImportFile', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
*/
// MonitorWebRoute(rg)
func MonitorWebRoute(rg *gin.RouterGroup) {
handle := monitor_web.MonitorWebHandler{}
rg = rg.Group("/", middleware.TokenAuth())
rg.GET("/monitor_web/list", handle.List)
rg.GET("/monitor_web/listAll", handle.ListAll)
rg.GET("/monitor_web/detail", handle.Detail)
rg.POST("/monitor_web/add",middleware.RecordLog("错误收集error新增"), handle.Add)
rg.POST("/monitor_web/edit",middleware.RecordLog("错误收集error编辑"), handle.Edit)
rg.POST("/monitor_web/del", middleware.RecordLog("错误收集error删除"), handle.Del)
rg.GET("/monitor_web/ExportFile", middleware.RecordLog("错误收集error导出"), handle.ExportFile)
rg.POST("/monitor_web/ImportFile", handle.ImportFile)
}

View File

@@ -1,26 +1,25 @@
package log
import (
"time"
"x_admin/core"
)
// //SystemLogOperateReq 操作日志列表参数
type SystemLogOperateReq struct {
Title string `form:"title"` // 操作标题
Username string `form:"username"` // 用户账号
Ip string `form:"ip"` // 请求IP
Type string `form:"type" binding:"omitempty,oneof=GET POST PUT"` // 请求类型: GET/POST/PUT
Status int `form:"status" binding:"omitempty,oneof=1 2"` // 执行状态: [1=成功, 2=失败]
Url string `form:"url"` // 请求地址
StartTime time.Time `form:"startTime" time_format:"2006-01-02"` // 开始时间
EndTime time.Time `form:"endTime" time_format:"2006-01-02"` // 结束时间
Title string `form:"title"` // 操作标题
Username string `form:"username"` // 用户账号
Ip string `form:"ip"` // 请求IP
Type string `form:"type" binding:"omitempty,oneof=GET POST PUT"` // 请求类型: GET/POST/PUT
Status int `form:"status" binding:"omitempty,oneof=1 2"` // 执行状态: [1=成功, 2=失败]
Url string `form:"url"` // 请求地址
StartTime string `form:"startTime" time_format:"2006-01-02"` // 开始时间
EndTime string `form:"endTime" time_format:"2006-01-02"` // 结束时间
}
type SystemLogLoginReq struct {
Username string `form:"username"` // 登录账号
Status int `form:"status" binding:"omitempty,oneof=1 2"` // 执行状态: [1=成功, 2=失败]
StartTime time.Time `form:"startTime" time_format:"2006-01-02"` // 开始时间
EndTime time.Time `form:"endTime" time_format:"2006-01-02"` // 结束时间
Username string `form:"username"` // 登录账号
Status int `form:"status" binding:"omitempty,oneof=1 2"` // 执行状态: [1=成功, 2=失败]
StartTime string `form:"startTime" time_format:"2006-01-02"` // 开始时间
EndTime string `form:"endTime" time_format:"2006-01-02"` // 结束时间
}
// SystemLogOperateResp 操作日志返回信息

View File

@@ -58,11 +58,11 @@ func (logSrv systemLogsServer) Operate(page request.PageReq, logReq SystemLogOpe
if logReq.Url != "" {
logModel = logModel.Where("url = ?", logReq.Url)
}
if !logReq.StartTime.IsZero() {
logModel = logModel.Where("log.create_time >= ?", logReq.StartTime.Unix())
if logReq.StartTime != "" {
logModel = logModel.Where("log.create_time >= UNIX_TIMESTAMP(?)", logReq.StartTime)
}
if !logReq.EndTime.IsZero() {
logModel = logModel.Where("log.create_time <= ?", logReq.EndTime.Unix())
if logReq.EndTime != "" {
logModel = logModel.Where("log.create_time <= UNIX_TIMESTAMP(?)", logReq.EndTime)
}
// 总数
var count int64
@@ -98,11 +98,11 @@ func (logSrv systemLogsServer) Login(page request.PageReq, logReq SystemLogLogin
if logReq.Status > 0 {
logModel = logModel.Where("status = ?", logReq.Status)
}
if !logReq.StartTime.IsZero() {
logModel = logModel.Where("create_time >= ?", logReq.StartTime.Unix())
if logReq.StartTime != "" {
logModel = logModel.Where("create_time >= UNIX_TIMESTAMP(?)", logReq.StartTime)
}
if !logReq.EndTime.IsZero() {
logModel = logModel.Where("create_time <= ?", logReq.EndTime.Unix())
if logReq.EndTime != "" {
logModel = logModel.Where("create_time <= UNIX_TIMESTAMP(?)", logReq.EndTime)
}
// 总数
var count int64

View File

@@ -51,10 +51,7 @@ func loadConfig(envPath string) envConfig {
viper.SetConfigFile(cfgPath)
}
viper.AutomaticEnv()
// var rootPath string
// if _, filename, _, ok := runtime.Caller(0); ok {
// rootPath = path.Dir(path.Dir(filename))
// }
rootPath, err := os.Getwd()
if err != nil {
log.Fatal(err)

View File

@@ -1,17 +0,0 @@
package config
//GenConfig 代码生成器公共配置
var GenConfig = genConfig{
// 基础包名
PackageName: "gencode",
// 是否去除表前缀
IsRemoveTablePrefix: true,
// 生成代码根路径
GenRootPath: "/tmp/target",
}
type genConfig struct {
PackageName string
IsRemoveTablePrefix bool
GenRootPath string
}

View File

@@ -2,34 +2,52 @@ package core
import (
"encoding/json"
"strconv"
"time"
"github.com/gin-gonic/gin"
)
const DateFormat = "2006-01-02"
const TimeFormat = "2006-01-02 15:04:05"
//TsTime 自定义时间格式
// TsTime 自定义时间格式
type TsTime int64
type OnlyRespTsTime time.Time
////TsDate 自定义日期格式
//type TsDate int64
// //TsDate 自定义日期格式
// type TsDate int64
//
//func (tsd *TsDate) UnmarshalJSON(bs []byte) error {
// var date string
// err := json.Unmarshal(bs, &date)
// if err != nil {
// return err
// func (tsd *TsDate) UnmarshalJSON(bs []byte) error {
// var date string
// err := json.Unmarshal(bs, &date)
// if err != nil {
// return err
// }
// tt, _ := time.ParseInLocation(DateFormat, date, time.Local)
// *tsd = TsDate(tt.Unix())
// return nil
// }
// tt, _ := time.ParseInLocation(DateFormat, date, time.Local)
// *tsd = TsDate(tt.Unix())
// return nil
//}
//
//func (tsd TsDate) MarshalJSON() ([]byte, error) {
// tt := time.Unix(int64(tsd), 0).Format(DateFormat)
// return json.Marshal(tt)
//}
// func (tsd TsDate) MarshalJSON() ([]byte, error) {
// tt := time.Unix(int64(tsd), 0).Format(DateFormat)
// return json.Marshal(tt)
// }
//
// 实现自定义的解析逻辑
func (t *TsTime) Bind(ctx *gin.Context) error {
// 尝试从表单中获取时间字符串
str := ctx.Query("clientTime") // 对于GET请求使用Query对于POST请求使用PostForm
// 对于POST请求中的JSON体你应该使用 ShouldBindJSON 或其他相关的ShouldBind方法
// 假设传入的是UNIX时间戳的字符串形式
i, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return err
}
*t = TsTime(i)
return nil
}
func (tst *TsTime) UnmarshalJSON(bs []byte) error {
var date string
@@ -42,6 +60,8 @@ func (tst *TsTime) UnmarshalJSON(bs []byte) error {
return nil
}
// MarshalJSON 将TsTime类型的时间转化为JSON字符串格式
// 返回转化后的JSON字符串和错误信息
func (tst TsTime) MarshalJSON() ([]byte, error) {
tt := time.Unix(int64(tst), 0).Format(TimeFormat)
return json.Marshal(tt)

View File

@@ -11,6 +11,7 @@ require (
github.com/go-playground/validator/v10 v10.16.0
github.com/go-redis/redis/v8 v8.11.5
github.com/go-redis/redis/v9 v9.0.0-rc.2
github.com/go-sql-driver/mysql v1.7.1
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/google/uuid v1.4.0
github.com/jinzhu/copier v0.4.0
@@ -43,7 +44,6 @@ require (
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/spec v0.20.9 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect

View File

@@ -0,0 +1,30 @@
package model
//MonitorClient 客户端信息实体
type MonitorClient struct {
Id int `gorm:"primarykey;comment:'uuid'" excel:"name:uuid;"` // uuid
ProjectKey string `gorm:"comment:'项目key'" excel:"name:项目key;"` // 项目key
ClientId string `gorm:"comment:'sdk生成的客户端id'" excel:"name:sdk生成的客户端id;"` // sdk生成的客户端id
UserId string `gorm:"comment:'用户id'" excel:"name:用户id;"` // 用户id
Os string `gorm:"comment:'系统'" excel:"name:系统;"` // 系统
Browser string `gorm:"comment:'浏览器'" excel:"name:浏览器;"` // 浏览器
City string `gorm:"comment:'城市'" excel:"name:城市;"` // 城市
Width int `gorm:"comment:'屏幕'" excel:"name:屏幕;"` // 屏幕
Height int `gorm:"comment:'屏幕高度'" excel:"name:屏幕高度;"` // 屏幕高度
Ua string `gorm:"comment:'ua记录'" excel:"name:ua记录;"` // ua记录
ClientTime int `gorm:"comment:'客户端时间'" excel:"name:客户端时间;"` // 客户端时间
CreateTime int64 `gorm:"autoCreateTime;comment:'创建时间'" excel:"name:创建时间;"` // 创建时间
}

View File

@@ -0,0 +1,21 @@
package model
//MonitorProject 错误项目实体
type MonitorProject struct {
Id int `gorm:"primarykey;comment:'项目id'" excel:"name:项目id;"` // 项目id
ProjectKey string `gorm:"comment:'项目uuid'" excel:"name:项目uuid;"` // 项目uuid
ProjectName string `gorm:"comment:'项目名称'" excel:"name:项目名称;"` // 项目名称
ProjectType string `gorm:"comment:'项目类型go java web node php 等'" excel:"name:项目类型"` // 项目类型go java web node php 等
IsDelete int `gorm:"comment:'是否删除: 0=否, 1=是'" excel:"name:是否删除: 0=否, 1=是;"` // 是否删除: 0=否, 1=是
UpdateTime int64 `gorm:"autoUpdateTime;comment:'更新时间'" excel:"name:更新时间;"` // 更新时间
CreateTime int64 `gorm:"autoCreateTime;comment:'创建时间'" excel:"name:创建时间;"` // 创建时间
DeleteTime int64 `gorm:"comment:'删除时间'" excel:"name:删除时间;"` // 删除时间
}

View File

@@ -0,0 +1,24 @@
package model
//MonitorWeb 错误收集error实体
type MonitorWeb struct {
Id int `gorm:"primarykey;comment:'uuid'" excel:"name:uuid;"` // uuid
ProjectKey string `gorm:"comment:'项目key'" excel:"name:项目key;"` // 项目key
ClientId string `gorm:"comment:'sdk生成的客户端id'" excel:"name:sdk生成的客户端id;"` // sdk生成的客户端id
EventType string `gorm:"comment:'事件类型'" excel:"name:事件类型;"` // 事件类型
Page string `gorm:"comment:'URL地址'" excel:"name:URL地址;"` // URL地址
Message string `gorm:"comment:'错误消息'" excel:"name:错误消息;"` // 错误消息
Stack string `gorm:"comment:'错误堆栈'" excel:"name:错误堆栈;"` // 错误堆栈
ClientTime int `gorm:"comment:'客户端时间'" excel:"name:客户端时间;"` // 客户端时间
CreateTime int64 `gorm:"autoCreateTime;comment:'创建时间'" excel:"name:创建时间;"` // 创建时间
}