diff --git a/admin/.docker-compose/my.conf b/admin/.docker-compose/my.conf new file mode 100644 index 0000000..94b4c24 --- /dev/null +++ b/admin/.docker-compose/my.conf @@ -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; # 设置代理服务器的协议和地址 + } +} diff --git a/admin/.dockerignore b/admin/.dockerignore new file mode 100644 index 0000000..43664d1 --- /dev/null +++ b/admin/.dockerignore @@ -0,0 +1,8 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local +package-lock.json +pnpm-lock.yaml +.vscode \ No newline at end of file diff --git a/admin/.npmrc b/admin/.npmrc new file mode 100644 index 0000000..def9d9e --- /dev/null +++ b/admin/.npmrc @@ -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 \ No newline at end of file diff --git a/admin/.vscode/settings.json b/admin/.vscode/settings.json index 80a0a21..cd5c1aa 100644 --- a/admin/.vscode/settings.json +++ b/admin/.vscode/settings.json @@ -8,5 +8,5 @@ "css.validate": false, "less.validate": false, "scss.validate": false, - "cSpell.words": ["nprogress", "pinia", "vform"] + "cSpell.words": ["datetimerange", "nprogress", "pinia", "vform"] } diff --git a/admin/Dockerfile b/admin/Dockerfile new file mode 100644 index 0000000..9b4f82f --- /dev/null +++ b/admin/Dockerfile @@ -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 diff --git a/admin/package.json b/admin/package.json index 3d2ef67..889105f 100644 --- a/admin/package.json +++ b/admin/package.json @@ -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" } } diff --git a/admin/public/robots.txt b/admin/public/robots.txt new file mode 100644 index 0000000..c2a49f4 --- /dev/null +++ b/admin/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Allow: / diff --git a/admin/src/api/monitor_client.ts b/admin/src/api/monitor_client.ts new file mode 100644 index 0000000..818c9f0 --- /dev/null +++ b/admin/src/api/monitor_client.ts @@ -0,0 +1,30 @@ +import request from '@/utils/request' + +// 客户端信息列表 +export function monitor_client_list(params?: Record) { + return request.get({ url: '/monitor_client/list', params }) +} +// 客户端信息列表-所有 +export function monitor_client_list_all(params?: Record) { + return request.get({ url: '/monitor_client/listAll', params }) +} + +// 客户端信息详情 +export function monitor_client_detail(params: Record) { + return request.get({ url: '/monitor_client/detail', params }) +} + +// 客户端信息新增 +export function monitor_client_add(params: Record) { + return request.post({ url: '/monitor_client/add', params }) +} + +// 客户端信息编辑 +export function monitor_client_edit(params: Record) { + return request.post({ url: '/monitor_client/edit', params }) +} + +// 客户端信息删除 +export function monitor_client_delete(params: Record) { + return request.post({ url: '/monitor_client/del', params }) +} diff --git a/admin/src/api/monitor_project.ts b/admin/src/api/monitor_project.ts new file mode 100644 index 0000000..20e403b --- /dev/null +++ b/admin/src/api/monitor_project.ts @@ -0,0 +1,30 @@ +import request from '@/utils/request' + +// 错误项目列表 +export function monitor_project_list(params?: Record) { + return request.get({ url: '/monitor_project/list', params }) +} +// 错误项目列表-所有 +export function monitor_project_list_all(params?: Record) { + return request.get({ url: '/monitor_project/listAll', params }) +} + +// 错误项目详情 +export function monitor_project_detail(params: Record) { + return request.get({ url: '/monitor_project/detail', params }) +} + +// 错误项目新增 +export function monitor_project_add(params: Record) { + return request.post({ url: '/monitor_project/add', params }) +} + +// 错误项目编辑 +export function monitor_project_edit(params: Record) { + return request.post({ url: '/monitor_project/edit', params }) +} + +// 错误项目删除 +export function monitor_project_delete(params: Record) { + return request.post({ url: '/monitor_project/del', params }) +} diff --git a/admin/src/api/monitor_web.ts b/admin/src/api/monitor_web.ts new file mode 100644 index 0000000..e6beafb --- /dev/null +++ b/admin/src/api/monitor_web.ts @@ -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) { + return request.get({ url: '/monitor_web/list', params }) +} +// 错误收集error列表-所有 +export function monitor_web_list_all(params?: Record) { + return request.get({ url: '/monitor_web/listAll', params }) +} + +// 错误收集error详情 +export function monitor_web_detail(params: Record) { + return request.get({ url: '/monitor_web/detail', params }) +} + +// 错误收集error新增 +export function monitor_web_add(params: Record) { + return request.post({ url: '/monitor_web/add', params }) +} + +// 错误收集error编辑 +export function monitor_web_edit(params: Record) { + return request.post({ url: '/monitor_web/edit', params }) +} + +// 错误收集error删除 +export function monitor_web_delete(params: Record) { + 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)) +} diff --git a/admin/src/components/daterange-picker/index.vue b/admin/src/components/daterange-picker/index.vue index 1c5fe2a..e6659ba 100644 --- a/admin/src/components/daterange-picker/index.vue +++ b/admin/src/components/daterange-picker/index.vue @@ -1,13 +1,13 @@ @@ -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({ // get: () => { // return [props.startTime, props.endTime] diff --git a/admin/src/utils/util.ts b/admin/src/utils/util.ts index 8948a6b..a3106c8 100644 --- a/admin/src/utils/util.ts +++ b/admin/src/utils/util.ts @@ -105,44 +105,6 @@ export function objectToQuery(params: Record): 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的长度 diff --git a/admin/src/views/monitor_client/edit.vue b/admin/src/views/monitor_client/edit.vue new file mode 100644 index 0000000..fad55ea --- /dev/null +++ b/admin/src/views/monitor_client/edit.vue @@ -0,0 +1,208 @@ + + diff --git a/admin/src/views/monitor_client/index.vue b/admin/src/views/monitor_client/index.vue new file mode 100644 index 0000000..c4f8ffd --- /dev/null +++ b/admin/src/views/monitor_client/index.vue @@ -0,0 +1,124 @@ + + diff --git a/admin/src/views/monitor_project/components/Sdk.vue b/admin/src/views/monitor_project/components/Sdk.vue new file mode 100644 index 0000000..4c44202 --- /dev/null +++ b/admin/src/views/monitor_project/components/Sdk.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/admin/src/views/monitor_project/edit.vue b/admin/src/views/monitor_project/edit.vue new file mode 100644 index 0000000..956f28b --- /dev/null +++ b/admin/src/views/monitor_project/edit.vue @@ -0,0 +1,144 @@ + + diff --git a/admin/src/views/monitor_project/index.vue b/admin/src/views/monitor_project/index.vue new file mode 100644 index 0000000..1f012f1 --- /dev/null +++ b/admin/src/views/monitor_project/index.vue @@ -0,0 +1,139 @@ + + diff --git a/admin/src/views/monitor_web/edit.vue b/admin/src/views/monitor_web/edit.vue new file mode 100644 index 0000000..a675e15 --- /dev/null +++ b/admin/src/views/monitor_web/edit.vue @@ -0,0 +1,189 @@ + + diff --git a/admin/src/views/monitor_web/index.vue b/admin/src/views/monitor_web/index.vue new file mode 100644 index 0000000..2de4fab --- /dev/null +++ b/admin/src/views/monitor_web/index.vue @@ -0,0 +1,157 @@ + + diff --git a/admin/src/views/setting/permission/admin/index.vue b/admin/src/views/setting/permission/admin/index.vue index dd052bd..8cb3707 100644 --- a/admin/src/views/setting/permission/admin/index.vue +++ b/admin/src/views/setting/permission/admin/index.vue @@ -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[] }>({ diff --git a/admin/src/views/setting/permission/menu/edit.vue b/admin/src/views/setting/permission/menu/edit.vue index fcb751d..459c42b 100644 --- a/admin/src/views/setting/permission/menu/edit.vue +++ b/admin/src/views/setting/permission/menu/edit.vue @@ -42,18 +42,6 @@ - -
- -
- 访问的路由地址,如:`admin`,如外网地址需内链访问则以`http(s)://`开头 -
-
-
+ + +
+ +
+ 访问的路由地址,如:`admin`,如外网地址需内链访问则以`http(s)://`开头 +
+
+
+ +
+
+ +
+
+ 访问路由的默认传递参数,如:`{"id": 1, "name": + "admin"}`或`id=1&name=admin` +
+
+
- -
-
- -
-
- 访问路由的默认传递参数,如:`{"id": 1, "name": - "admin"}`或`id=1&name=admin` -
-
-
+ { 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) => { 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] } } } diff --git a/admin/src/views/setting/system/journal.vue b/admin/src/views/setting/system/journal.vue index 63b385a..9b2d850 100644 --- a/admin/src/views/setting/system/journal.vue +++ b/admin/src/views/setting/system/journal.vue @@ -61,12 +61,14 @@ - - + + + + - +
diff --git a/admin/vite.config.ts b/admin/vite.config.ts index 4ddbf52..190707e 100644 --- a/admin/vite.config.ts +++ b/admin/vite.config.ts @@ -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, diff --git a/server/.dockerignore b/server/.dockerignore new file mode 100644 index 0000000..c984231 --- /dev/null +++ b/server/.dockerignore @@ -0,0 +1,5 @@ +### Go ### +# Binaries for programs and plugins +*.exe +.vscode +dist diff --git a/server/admin/common/index/service.go b/server/admin/common/index/service.go index bbb7a11..6e49404 100644 --- a/server/admin/common/index/service.go +++ b/server/admin/common/index/service.go @@ -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", }, } diff --git a/server/admin/entry.go b/server/admin/entry.go index 6ced290..6482ef7 100644 --- a/server/admin/entry.go +++ b/server/admin/entry.go @@ -56,4 +56,8 @@ func RegisterGroup(rg *gin.RouterGroup) { flow.FlowHistoryRoute(rg) generator.RegisterGroup(rg) + + MonitorProjectRoute(rg) + MonitorClientRoute(rg) + MonitorWebRoute(rg) } diff --git a/server/admin/generator/tpl_utils/tpl.go b/server/admin/generator/tpl_utils/tpl.go index 34dcab9..0cef6ba 100644 --- a/server/admin/generator/tpl_utils/tpl.go +++ b/server/admin/generator/tpl_utils/tpl.go @@ -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, diff --git a/server/admin/generator/tpl_utils/utils.go b/server/admin/generator/tpl_utils/utils.go index 9acfaba..89f087b 100644 --- a/server/admin/generator/tpl_utils/utils.go +++ b/server/admin/generator/tpl_utils/utils.go @@ -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) } diff --git a/server/admin/monitor_client/monitor_client_ctl.go b/server/admin/monitor_client/monitor_client_ctl.go new file mode 100644 index 0000000..d653da8 --- /dev/null +++ b/server/admin/monitor_client/monitor_client_ctl.go @@ -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) +} diff --git a/server/admin/monitor_client/monitor_client_schema.go b/server/admin/monitor_client/monitor_client_schema.go new file mode 100644 index 0000000..864cc82 --- /dev/null +++ b/server/admin/monitor_client/monitor_client_schema.go @@ -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:创建时间;"` // 创建时间 +} diff --git a/server/admin/monitor_client/monitor_client_service.go b/server/admin/monitor_client/monitor_client_service.go new file mode 100644 index 0000000..e90ce23 --- /dev/null +++ b/server/admin/monitor_client/monitor_client_service.go @@ -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 +} diff --git a/server/admin/monitor_client_route.go b/server/admin/monitor_client_route.go new file mode 100644 index 0000000..b00f00d --- /dev/null +++ b/server/admin/monitor_client_route.go @@ -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) +} diff --git a/server/admin/monitor_project/monitor_project_ctl.go b/server/admin/monitor_project/monitor_project_ctl.go new file mode 100644 index 0000000..da5f7ad --- /dev/null +++ b/server/admin/monitor_project/monitor_project_ctl.go @@ -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) +} diff --git a/server/admin/monitor_project/monitor_project_schema.go b/server/admin/monitor_project/monitor_project_schema.go new file mode 100644 index 0000000..005f227 --- /dev/null +++ b/server/admin/monitor_project/monitor_project_schema.go @@ -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:创建时间;"` // 创建时间 +} diff --git a/server/admin/monitor_project/monitor_project_service.go b/server/admin/monitor_project/monitor_project_service.go new file mode 100644 index 0000000..9e2e717 --- /dev/null +++ b/server/admin/monitor_project/monitor_project_service.go @@ -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 +} diff --git a/server/admin/monitor_project_route.go b/server/admin/monitor_project_route.go new file mode 100644 index 0000000..fc546d6 --- /dev/null +++ b/server/admin/monitor_project_route.go @@ -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) +} diff --git a/server/admin/monitor_web/monitor_web_ctl.go b/server/admin/monitor_web/monitor_web_ctl.go new file mode 100644 index 0000000..bfe1088 --- /dev/null +++ b/server/admin/monitor_web/monitor_web_ctl.go @@ -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) +} diff --git a/server/admin/monitor_web/monitor_web_schema.go b/server/admin/monitor_web/monitor_web_schema.go new file mode 100644 index 0000000..257af73 --- /dev/null +++ b/server/admin/monitor_web/monitor_web_schema.go @@ -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:创建时间;"` // 创建时间 +} diff --git a/server/admin/monitor_web/monitor_web_service.go b/server/admin/monitor_web/monitor_web_service.go new file mode 100644 index 0000000..3e0cce0 --- /dev/null +++ b/server/admin/monitor_web/monitor_web_service.go @@ -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 +} diff --git a/server/admin/monitor_web_route.go b/server/admin/monitor_web_route.go new file mode 100644 index 0000000..63eb173 --- /dev/null +++ b/server/admin/monitor_web_route.go @@ -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) +} \ No newline at end of file diff --git a/server/admin/system/log/schema.go b/server/admin/system/log/schema.go index 9efe996..657bd93 100644 --- a/server/admin/system/log/schema.go +++ b/server/admin/system/log/schema.go @@ -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 操作日志返回信息 diff --git a/server/admin/system/log/service.go b/server/admin/system/log/service.go index 2b048f7..b08b2d3 100644 --- a/server/admin/system/log/service.go +++ b/server/admin/system/log/service.go @@ -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 diff --git a/server/config/config.go b/server/config/config.go index 8bc1b2c..7326ea0 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -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) diff --git a/server/config/gen.go b/server/config/gen.go deleted file mode 100644 index a414316..0000000 --- a/server/config/gen.go +++ /dev/null @@ -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 -} diff --git a/server/core/time.go b/server/core/time.go index 2f3af8d..becc13b 100644 --- a/server/core/time.go +++ b/server/core/time.go @@ -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) diff --git a/server/go.mod b/server/go.mod index 7522f7b..f95433b 100644 --- a/server/go.mod +++ b/server/go.mod @@ -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 diff --git a/server/model/monitor_client.go b/server/model/monitor_client.go new file mode 100644 index 0000000..680b7af --- /dev/null +++ b/server/model/monitor_client.go @@ -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:创建时间;"` // 创建时间 + +} diff --git a/server/model/monitor_project.go b/server/model/monitor_project.go new file mode 100644 index 0000000..2565105 --- /dev/null +++ b/server/model/monitor_project.go @@ -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:删除时间;"` // 删除时间 + +} diff --git a/server/model/monitor_web.go b/server/model/monitor_web.go new file mode 100644 index 0000000..40aa175 --- /dev/null +++ b/server/model/monitor_web.go @@ -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:创建时间;"` // 创建时间 + +}