27 Commits
Author SHA1 Message Date
新亮andGitHub 8fd9a005d1 Update README.md 2023-12-23 08:57:01 +08:00
新亮andGitHub 4530dab87b Merge pull request #82 from zhoumengkang/master
日志目录稍做屏蔽
2022-07-31 09:28:47 +08:00
mengkang.zmk bf4a413bd0 清空 logs 目录 2022-07-24 09:03:27 +08:00
周梦康andGitHub 79aa86f278 Merge branch 'xinliangnote:master' into master 2022-07-24 08:53:42 +08:00
mengkang.zmk 866bed5522 清空 logs 目录 2022-07-21 15:55:42 +08:00
新亮 61cc349cb4 fix(1.2.8): 修复生成 swagger doc 后,服务无法启动的问题 2022-07-03 13:23:53 +08:00
mengkang.zmk 6825b4e5b1 Changes 2022-06-24 14:11:41 +08:00
mengkang.zmk 62d7ac5cd9 Merge remote-tracking branch 'origin/master' 2022-06-24 13:57:34 +08:00
mengkang.zmk b630456b90 屏蔽日志文件提交 2022-06-24 13:57:12 +08:00
新亮andGitHub bbe181817c Merge pull request #79 from zhoumengkang/master
与上次类似的登录窗口打开的 js 兼容性调整
2022-06-18 17:46:15 +08:00
周梦康andGitHub 15e99398cb Merge branch 'xinliangnote:master' into master 2022-06-16 14:32:28 +08:00
mengkang.zmk dd19eab5d5 同上 2022-06-16 14:09:09 +08:00
新亮andGitHub 7cdb8ee6b4 Merge pull request #78 from zhoumengkang/master
解决 chrome 打开新窗口被拦截的问题
2022-06-13 16:48:48 +08:00
周梦康andGitHub 400e0bb3f2 解决父窗口和子窗口跳转的问题 2022-06-12 22:10:17 +08:00
周梦康andGitHub 14f6853c2b Update httpclient.js
解决 chrome 打开新创被拦截的问题
参考 https://blog.csdn.net/oscar999/article/details/124505724
2022-06-12 18:44:37 +08:00
新亮 4c37a7e6b5 feature(1.2.8): swagger 接口文档新增 Security
- 将 middleware 命名为 interceptor
- 将 deploy 命名为 deployments
- 移除 pkg/errno
- 使用 proposal 目录
- 优化代码
2021-11-28 13:25:27 +08:00
新亮 fc7e58db04 feature(1.2.8): 优化 graph 2021-11-21 15:59:23 +08:00
新亮 4e3c2afafd feature(1.2.8): 调整 internal 目录结构
- 格式化代码
2021-11-21 13:29:50 +08:00
新亮 63499a432e feature(1.2.8): 调整 internal 目录结构 2021-11-21 13:23:27 +08:00
新亮 498033753e feature(1.2.8): 优化代码
- 删除 third_party_request
2021-11-20 17:19:08 +08:00
新亮 b05ed0b59d feature(1.2.8): 优化代码
- cron 相关
- socket 相关
2021-11-20 16:46:13 +08:00
新亮 8ed27cdce1 feature(1.2.8): 使用 embed 打包静态资源
- go version 升级为 1.16
- 使用 embed 特性,将静态资源打包进二进制文件
- 优化代码
2021-11-20 15:01:50 +08:00
新亮 9aa0067e07 perf(时区): 默认设置为中国时区 2021-11-13 15:21:14 +08:00
新亮andGitHub e2cecae7b1 Merge pull request #57 from malphitee/bugfix/malphitee/fix_httpclientjs_date_err
修复月份判定错误导致的签名信息错误
2021-10-01 20:33:09 +08:00
johnnliu e22593b708 修复月份判定的错误 2021-10-01 16:34:30 +08:00
新亮 05f337088e feature(1.2.8): 新增 websocket 模块
- 修改文档
2021-09-20 19:25:53 +08:00
新亮 17be120c06 feature(1.2.8): 新增 websocket 模块
- import gorilla/websocket
- 新增 实用工具箱->WebSocket 栏目
2021-09-20 19:18:15 +08:00
330 changed files with 6719 additions and 6290 deletions
+3
View File
@@ -14,3 +14,6 @@
# Dependency directories (remove the comment below to include it)
# vendor/
# Project runtime log
logs/*.log
+3 -3
View File
@@ -1,12 +1,12 @@
# FROM 基于 golang:1.15-alpine
FROM golang:1.15-alpine AS builder
# FROM 基于 golang:1.16-alpine
FROM golang:1.16-alpine AS builder
# ENV 设置环境变量
ENV GOPATH=/opt/repo
ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.io,direct
# ADD 源路径 目标路径
# COPY 源路径 目标路径
COPY . $GOPATH/src/github.com/xinliangnote/go-gin-api
# RUN 执行 go build .
+15 -4
View File
@@ -13,8 +13,7 @@
1. 支持 [Swagger](https://github.com/swaggo/gin-swagger) 接口文档生成
1. 支持 [GraphQL](https://github.com/99designs/gqlgen) 查询语言
1. 支持 trace 项目内部链路追踪
1. 支持 [pprof](https://github.com/gin-contrib/pprof) 性能剖析
1. 支持 [jwt](https://github.com/dgrijalva/jwt-go) 接口鉴权
1. 支持 [pprof](https://github.com/gin-contrib/pprof) 性能剖析
1. 支持 errno 统一定义错误码
1. 支持 [zap](https://go.uber.org/zap) 日志收集
1. 支持 [viper](https://github.com/spf13/viper) 配置文件解析
@@ -22,17 +21,29 @@
1. 支持 [go-redis](https://github.com/go-redis/redis/v7) 组件
1. 支持 RESTful API 返回值规范
1. 支持 生成数据表 CURD、控制器方法 等代码生成器
1. 支持 [cron](https://github.com/jakecoffman/cron) 定时任务,在后台可界面配置
1. 支持 [websocket](https://github.com/gorilla/websocket) 实时通讯,在后台有界面演示
1. 支持 web 界面,使用的 [Light Year Admin 模板](https://gitee.com/yinqi/Light-Year-Admin-Using-Iframe)
## 文档索引
## 文档索引(可加入交流群)
- 中文文档:[go-gin-api - 语雀](https://www.yuque.com/xinliangnote/go-gin-api/ngc3x5)
- English Document[en.md](https://github.com/xinliangnote/go-gin-api/blob/master/en.md)
## 轻量版
为了满足开发者对于简单、轻量级 API 框架的需求,开发了 gin-api-mono,旨在提供更便捷的业务开发体验。
相比于 go-gin-api,首先 gin-api-mono 去掉了一些集成的功能和界面,使得整个框架更加简洁、轻量。其次 gin-api-mono 对框架代码进行了升级,以确保其在性能和稳定性方面的优势。这样,开发者就可以更灵活地选择所需的功能,并获得更好的性能和稳定性。
详见链接:https://xiaobot.net/post/e9f7ef4c-81b1-4ffc-9053-bec55c3abb12
## 其他
查看 Jaeger 链路追踪代码,请查看 [v1.0版](https://github.com/xinliangnote/go-gin-api/releases/tag/v1.0),文档点这里 [jaeger.md](https://github.com/xinliangnote/go-gin-api/blob/master/docs/jaeger.md) 。
查看 Jaeger 链路追踪 Demo 代码,请查看 [v1.0 ](https://github.com/xinliangnote/go-gin-api/releases/tag/v1.0) ,链接地址:http://127.0.0.1:9999/jaeger_test
调用的其他服务端 Demo 代码为 [https://github.com/xinliangnote/go-jaeger-demo](https://github.com/xinliangnote/go-jaeger-demo)
## 联系作者
+11
View File
@@ -0,0 +1,11 @@
package assets
import "embed"
var (
//go:embed bootstrap
Bootstrap embed.FS
//go:embed templates
Templates embed.FS
)
File diff suppressed because one or more lines are too long
@@ -0,0 +1,32 @@
document.write('<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-notify/bootstrap-notify.min.js"></script>');
function SuccessNotify(content) {
$.notify({
icon: "mdi mdi-alert",
title: "",
message: content,
url: "",
target: ""
}, {
type: "success",
allow_dismiss: true,
newest_on_top: false,
placement: {
from: "top",
align: "right",
},
offset: {
x: "20",
y: "20"
},
spacing: "10",
z_index: "1031",
delay: "3000",
animate: {
enter: "animated fadeInDown",
exit: "animated fadeOutUp"
},
onClosed: null,
mouse_over: null
});
}
+13 -10
View File
@@ -1,8 +1,8 @@
document.write('<script type="text/javascript" src="../../bootstrap/js/authorization/ksort.js"></script>');
document.write('<script type="text/javascript" src="../../bootstrap/js/authorization/crypto-js.min.js"></script>');
document.write('<script type="text/javascript" src="../../bootstrap/js/authorization/hmac-sha256.js"></script>');
document.write('<script type="text/javascript" src="../../bootstrap/js/authorization/enc-base64.min.js"></script>');
document.write('<script type="text/javascript" src="../../bootstrap/js/jquery.cookie.min.js"></script>');
document.write('<script type="text/javascript" src="/assets/bootstrap/js/authorization/ksort.js"></script>');
document.write('<script type="text/javascript" src="/assets/bootstrap/js/authorization/crypto-js.min.js"></script>');
document.write('<script type="text/javascript" src="/assets/bootstrap/js/authorization/hmac-sha256.js"></script>');
document.write('<script type="text/javascript" src="/assets/bootstrap/js/authorization/enc-base64.min.js"></script>');
document.write('<script type="text/javascript" src="/assets/bootstrap/js/jquery.cookie.min.js"></script>');
document.write('<div style="display:none"><script type="text/javascript">document.write(unescape("%3Cspan id=\'cnzz_stat_icon_1279911342\'%3E%3C/span%3E%3Cscript src=\'https://v1.cnzz.com/z_stat.php%3Fid%3D1279911342%26\' type=\'text/javascript\'%3E%3C/script%3E"));</script></div>');
function GenerateAuthorization(path, method, params) {
@@ -11,7 +11,7 @@ function GenerateAuthorization(path, method, params) {
let date = new Date();
let datetime = date.getFullYear() + "-" // "年"
+ ((date.getMonth() + 1) > 10 ? (date.getMonth() + 1) : "0" + (date.getMonth() + 1)) + "-" // "月"
+ ((date.getMonth() + 1) >= 10 ? (date.getMonth() + 1) : "0" + (date.getMonth() + 1)) + "-" // "月"
+ (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " " // "日"
+ (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":" // "小时"
+ (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) + ":" // "分钟"
@@ -44,10 +44,13 @@ function AjaxError(response) {
let errCode = response.status;
let errMsg = response.responseText;
if (errCode === 401) { // 跳转到登录页
// 关闭当前界面
parent.window.close();
window.open("/login");
if (errCode === 401) {
// 跳转到登录页
if (window.frames.length !== parent.frames.length) {
parent.window.open("/login",'_self');
}else{
window.open("/login",'_self');
}
return;
}
+12 -12
View File
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -51,13 +51,13 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="../../bootstrap/js/authorization/md5.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/authorization/md5.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+9 -9
View File
@@ -3,10 +3,10 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -53,11 +53,11 @@
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery.pagination.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.pagination.js"></script>
<script type="text/javascript">
$(document).ready(function () {
// 加载列表页数据
+10 -10
View File
@@ -5,14 +5,14 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
<title>登录页面</title>
<link rel="shortcut icon" type="image/x-icon" href="bootstrap/favicon.ico">
<link rel="shortcut icon" type="image/x-icon" href="/assets/bootstrap/favicon.ico">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<link rel="stylesheet" type="text/css" href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css">
<link rel="stylesheet" type="text/css" href="../../bootstrap/css/materialdesignicons.min.css">
<link rel="stylesheet" type="text/css" href="../../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../../bootstrap/css/style.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/css/materialdesignicons.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/css/style.min.css">
<style>
.login-form .has-feedback {
@@ -47,7 +47,7 @@
<body class="center-vh">
<div class="card card-shadowed p-5 w-420 mb-0 mr-2 ml-2">
<div class="text-center mb-3">
<img src="../../bootstrap/images/logo-sidebar.png">
<img src="/assets/bootstrap/images/logo-sidebar.png">
</div>
<form class="login-form">
<div class="form-group has-feedback">
@@ -71,10 +71,10 @@
</form>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="../../bootstrap/js/authorization/md5.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/authorization/md5.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+11 -11
View File
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -53,12 +53,12 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
const hash_id = {{ .HashID }}
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -44,12 +44,12 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -46,13 +46,13 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="../../bootstrap/js/authorization/md5.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/authorization/md5.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
@@ -132,8 +132,11 @@
okay: {
text: '关闭',
action: function () {
parent.window.close();
window.open("/login");
if (window.frames.length !== parent.frames.length) {
parent.window.open("/login",'_self');
}else{
window.open("/login",'_self');
}
}
}
}
+11 -11
View File
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -46,12 +46,12 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+12 -12
View File
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -67,13 +67,13 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
@@ -3,9 +3,9 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -206,10 +206,10 @@ console.log({authorization: key + " " + digest, date: datetime});
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/main.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/main.min.js"></script>
<script type="text/javascript">document.write(unescape("%3Cspan id='cnzz_stat_icon_1279911342'%3E%3C/span%3E%3Cscript src='https://v1.cnzz.com/z_stat.php%3Fid%3D1279911342%26' type='text/javascript'%3E%3C/script%3E"));</script>
</body>
</html>
@@ -3,10 +3,10 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -51,11 +51,11 @@
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery.pagination.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.pagination.js"></script>
<script type="text/javascript">
$(document).ready(function () {
// 加载列表页数据
+2 -2
View File
@@ -3,8 +3,8 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -3,9 +3,9 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -56,10 +56,10 @@
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+11 -11
View File
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -138,12 +138,12 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+11 -11
View File
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -137,12 +137,12 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+10 -10
View File
@@ -3,10 +3,10 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -57,12 +57,12 @@
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery.pagination.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.pagination.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+10 -5
View File
@@ -3,8 +3,8 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -18,7 +18,12 @@
<div class="card-title">项目信息 <span class="badge badge-pill badge-warning">{{ .ProjectVersion }}</span> </div>
</header>
<div class="card-body">
<p>操作系统:{{ .GoOS }} <span class="badge badge-brown"> {{ .GoArch }} </span> <span class="badge badge-info"> {{ .GoVersion }} </span></p>
<p>操作系统:{{ .GoOS }}
<span class="badge badge-brown"> {{ .GoArch }} </span>
<span class="badge badge-info"> {{ .GoVersion }} </span>
<span class="badge badge-danger"> mysql{{ .MySQLVersion }} </span>
<span class="badge badge-danger"> redis{{ .RedisVersion }} </span>
</p>
<p>项目地址:{{ .ProjectPath }}</p>
<p>项目域名:{{ .Host }} <span class="badge badge-secondary"> {{ .Env }} </span></p>
</div>
@@ -82,7 +87,7 @@
<div class="card-title">开源信息</div>
</header>
<div class="card-body">
<p>GitHub 地址:<a target="_blank" href="https://github.com/xinliangnote/go-gin-api">xinliangnote/go-gin-api</a></p>
<p>GitHub 地址:<a target="_blank" href="https://github.com/xinliangnote/go-gin-api">[go-gin-api 源码地址]</a> <a target="_blank" href="https://www.yuque.com/xinliangnote/go-gin-api/ngc3x5">[中文文档]</a></p>
<p>GitHub Stars<a href="https://github.com/xinliangnote/go-gin-api/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/xinliangnote/go-gin-api?style=flat-square"></a></p>
<p>GitHub Forks<a href="https://github.com/xinliangnote/go-gin-api/network"><img alt="GitHub forks" src="https://img.shields.io/github/forks/xinliangnote/go-gin-api?style=flat-square"></a></p>
</div>
@@ -96,7 +101,7 @@
</header>
<div class="card-body text-center">
<p style="height: 105px;">
<img style="height: 100px;" src="../../bootstrap/images/qr-code.png"/>
<img style="height: 100px;" src="/assets/bootstrap/images/qr-code.png"/>
</p>
</div>
</div>
@@ -3,9 +3,9 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -48,9 +48,9 @@
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#btnOk").click(function(){
@@ -3,9 +3,9 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -16,7 +16,7 @@
<header class="card-header"><div class="card-title"> 生成控制器方法 </div></header>
<div class="card-body">
<div class="form-group">
<label for="handlerName">handler 名称,例如:<code>user_handler</code></label>
<label for="handlerName">API handler 名称,例如:<code>user</code><small>user 为 internal/api 目录下的文件夹名称</small></label>
<input type="text" class="form-control" id="handlerName" placeholder="请输入 handler 名称">
</div>
@@ -44,9 +44,9 @@
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#btnOk").click(function(){
+23 -20
View File
@@ -5,16 +5,16 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
<title>管理面板</title>
<link rel="shortcut icon" type="image/x-icon" href="bootstrap/favicon.ico">
<link rel="shortcut icon" type="image/x-icon" href="/assets/bootstrap/favicon.ico">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<link rel="stylesheet" type="text/css" href="bootstrap/js/jquery-confirm/jquery-confirm.min.css">
<link rel="stylesheet" type="text/css" href="bootstrap/css/materialdesignicons.min.css">
<link rel="stylesheet" type="text/css" href="bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="bootstrap/js/bootstrap-multitabs/multitabs.min.css">
<link rel="stylesheet" type="text/css" href="bootstrap/css/animate.min.css">
<link rel="stylesheet" type="text/css" href="bootstrap/css/style.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/css/materialdesignicons.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/css/animate.min.css">
<link rel="stylesheet" type="text/css" href="/assets/bootstrap/css/style.min.css">
</head>
<body>
@@ -26,7 +26,7 @@
<!-- logo -->
<div id="logo" class="sidebar-header">
<a href="/">
<img src="bootstrap/images/logo-sidebar.png"/>
<img src="/assets/bootstrap/images/logo-sidebar.png"/>
</a>
</div>
<div class="lyear-layout-sidebar-info lyear-scroll">
@@ -170,7 +170,7 @@
<li class="dropdown dropdown-profile">
<a href="javascript:void(0)" data-toggle="dropdown" class="dropdown-toggle">
<img class="img-avatar img-avatar-48 m-r-10" src="bootstrap/images/users/avatar.png">
<img class="img-avatar img-avatar-48 m-r-10" src="/assets/bootstrap/images/users/avatar.png">
<span id="nickname"></span>
</a>
<ul class="dropdown-menu dropdown-menu-right">
@@ -210,15 +210,15 @@
</div>
</div>
<script type="text/javascript" src="bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="bootstrap/js/perfect-scrollbar.min.js"></script>
<script type="text/javascript" src="bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="bootstrap/js/jquery.cookie.min.js"></script>
<script type="text/javascript" src="bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="bootstrap/js/index.min.js"></script>
<script type="text/javascript" src="bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/perfect-scrollbar.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.cookie.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/index.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
AjaxForm(
@@ -281,8 +281,11 @@
$.cookie('_nav_title_', '');
$.cookie('_login_token_', '');
parent.window.close();
window.open("/login");
if (window.frames.length !== parent.frames.length) {
parent.window.open("/login",'_self');
}else{
window.open("/login",'_self');
}
},
function (response) {
AjaxError(response);
+17 -27
View File
@@ -5,15 +5,15 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
<title>项目初始化</title>
<link rel="shortcut icon" type="image/x-icon" href="../../bootstrap/favicon.ico">
<link rel="shortcut icon" type="image/x-icon" href="/assets/bootstrap/favicon.ico">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-select/bootstrap-select.css" rel="stylesheet">
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-select/bootstrap-select.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -27,7 +27,7 @@
<div class="card-body">
<h5 class="card-title"><span class="badge badge-info">检测 · 环境</span></h5>
<div class="input-group mb-3">
<p class="text-left">所需版本:<code>go1.15+</code> (<small>当前版本 </small><code>{{.GoVersion}}</code>)</p>
<p class="text-left">所需版本:<code>go{{.MinGoVersion}}+</code> (<small>当前版本 </small><code>{{.GoVersion}}</code>)</p>
</div>
<h5 class="card-title"><span class="badge badge-info">配置 · 语言</span></h5>
@@ -98,19 +98,9 @@
</div>
<input type="text" class="form-control" id="mysql_name" value="{{ .Config.MySQL.Write.Name }}"
placeholder="请输入数据库名">
</div>
<div class="input-group mb-3">
<small>
<i class="mdi mdi-checkbox-marked-circle"></i>
初始化 MySQL 数据表:<code>authorized</code>
<code>authorized_api</code>
<code>admin</code>
<code>menu</code>
<code>menu_action</code>
<code>admin_menu</code>
<code>cron_task</code>
</small>
<div class="input-group-append">
<span class="input-group-text"><code>请确保此数据库已存在!</code></span>
</div>
</div>
<button type="button" id="btnOk" class="btn btn-primary">初始化项目</button>
@@ -135,13 +125,13 @@
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-select/bootstrap-select.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-select/i18n/defaults-zh_CN.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-select/bootstrap-select.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-select/i18n/defaults-zh_CN.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('.select-picker').selectpicker();
+24 -9
View File
@@ -5,14 +5,14 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
<title>服务升级</title>
<link rel="shortcut icon" type="image/x-icon" href="../../bootstrap/favicon.ico">
<link rel="shortcut icon" type="image/x-icon" href="/assets/bootstrap/favicon.ico">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -95,15 +95,30 @@
<p>5、退出重新登录,即可以看到自己新增的模块。</p>
<hr/>
<p class="h6">
<span class="badge badge-pill badge-warning">v1.2.7</span>
->
<span class="badge badge-pill badge-warning">v1.2.8</span>
</p>
<p>1、源代码升级:
<mark>拉取最新代码,覆盖旧版本代码即可。</mark>
</p>
<p>2、系统管理员->菜单管理,新增侧边栏:实用工具箱 -> WebSocket,同时添加菜单栏的功能权限。</p>
<p>3、系统管理员->管理员,对管理员进行菜单授权。</p>
<p>4、退出重新登录,即可以看到自己新增的模块。</p>
<hr/>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$(document).on('click', '.upgrade', function () {
+12 -12
View File
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -69,13 +69,13 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+18 -18
View File
@@ -3,13 +3,13 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/js/jquery-treegrid/jquery.treegrid.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-select/bootstrap-select.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-table/bootstrap-table.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-treegrid/jquery.treegrid.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-select/bootstrap-select.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-table/bootstrap-table.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -76,18 +76,18 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-table/bootstrap-table.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-treegrid/jquery.treegrid.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-table/bootstrap-table.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-treegrid/jquery.treegrid.min.js"></script>
<script type="text/javascript"
src="../../bootstrap/js/bootstrap-table/extensions/treegrid/bootstrap-table-treegrid.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-select/bootstrap-select.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-select/i18n/defaults-zh_CN.min.js"></script>
src="/assets/bootstrap/js/bootstrap-table/extensions/treegrid/bootstrap-table-treegrid.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-select/bootstrap-select.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-select/i18n/defaults-zh_CN.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('.select-picker').selectpicker();
+9 -9
View File
@@ -3,10 +3,10 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -61,11 +61,11 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+14 -14
View File
@@ -3,11 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-select/bootstrap-select.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/bootstrap-select/bootstrap-select.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -96,15 +96,15 @@
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/vkbeautify.js"></script>
<script type="text/javascript" src="../../bootstrap/js/main.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-select/bootstrap-select.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-select/i18n/defaults-zh_CN.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/vkbeautify.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/main.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-select/bootstrap-select.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-select/i18n/defaults-zh_CN.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('.select-picker').selectpicker();
+10 -10
View File
@@ -3,10 +3,10 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -75,12 +75,12 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript">
$(document).ready(function () {
+6 -6
View File
@@ -3,9 +3,9 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
@@ -97,9 +97,9 @@
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<div style="display:none">
<script type="text/javascript">document.write(unescape("%3Cspan id='cnzz_stat_icon_1279911342'%3E%3C/span%3E%3Cscript src='https://v1.cnzz.com/z_stat.php%3Fid%3D1279911342%26' type='text/javascript'%3E%3C/script%3E"));</script>
</div>
+184
View File
@@ -0,0 +1,184 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/animate.min.css" rel="stylesheet">
<link href="/assets/bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid p-t-15">
<div class="row">
<div class="col-lg-6">
<div class="card">
<header class="card-header">
<div class="card-title">WebSocket 示例</div>
</header>
<div class="card-body">
<ul class="lyear-timeline lyear-timeline-left timeline-content">
<li class="lyear-timeline-item">
<div class="lyear-timeline-item-dot">
<span class="badge"></span>
</div>
<div class="lyear-timeline-item-content">
<p class="mb-1"><strong class="connect-content"></strong></p>
<p class="mb-0 connect-url"></p>
<p>
<time class="mb-3 connect-time"></time>
</p>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<div class="card-title">WebSocket 示例</div>
</div>
<div class="card-body">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#send_message"
aria-selected="true">发送消息</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active show" id="send_message">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">消息内容</span>
</div>
<input type="text" class="form-control" id="message_content" placeholder="请输入消息内容">
</div>
<button type="button" id="btnSend" class="btn btn-primary">发送</button>
<button type="button" id="btnSending" class="btn btn-primary" disabled
style="display: none">
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
发送中...
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="/assets/bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/httpclient/httpclient.js"></script>
<script type="text/javascript" src="/assets/bootstrap/js/bootstrap-notify/notify.js"></script>
<script type="text/javascript">
$(document).ready(function () {
const ws = new WebSocket("ws://127.0.0.1:9999/socket/system/message");
//连接打开时触发
ws.onopen = function (evt) {
if (evt.isTrusted) {
$(".badge").addClass("badge-success");
$(".connect-content").html("Socket 连接成功");
$(".connect-url").html("连接地址:" + evt.currentTarget.url);
$(".connect-time").html(getCSTTime());
} else {
$(".badge").addClass("badge-danger");
$(".connect-content").html("Socket 连接失败");
$(".connect-url").html("请确认连接地址是否正确");
$(".connect-time").html(getCSTTime());
}
};
//接收到消息时触发
ws.onmessage = function (evt) {
const messageData = JSON.parse(evt.data);
let html = '<li class="lyear-timeline-item">';
html += '<div class="lyear-timeline-item-dot"><span class="badge badge-success"></span></div>';
html += '<div class="lyear-timeline-item-content">';
html += '<p class="mb-1"><strong>' + messageData.username + '</strong></p>';
html += '<p class="mb-0">' + messageData.message + '</p>';
html += '<p><time class="mb-3">' + messageData.time + '</time></p>';
html += '</div></li>';
$(".timeline-content").prepend(html);
};
//连接关闭时触发
ws.onclose = function (evt) {
let html = '<li class="lyear-timeline-item">';
html += '<div class="lyear-timeline-item-dot"><span class="badge badge-muted"></span></div>';
html += '<div class="lyear-timeline-item-content">';
html += '<p class="mb-1"><strong>Socket 连接关闭</strong></p>';
html += '<p class="mb-0">连接已关闭</p>';
html += '<p><time class="mb-3">' + getCSTTime() + '</time></p>';
html += '</div></li>';
$(".timeline-content").prepend(html);
};
function getCSTTime() {
let date = new Date();
let datetime = date.getFullYear() + "-" // "年"
+ ((date.getMonth() + 1) > 10 ? (date.getMonth() + 1) : "0" + (date.getMonth() + 1)) + "-" // "月"
+ (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " " // "日"
+ (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":" // "小时"
+ (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) + ":" // "分钟"
+ (date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds()); // "秒"
return datetime;
}
$('#btnSend').on('click', function () {
const messageContent = $("#message_content").val();
if (messageContent === "") {
$.alert({
title: '温馨提示',
icon: 'mdi mdi-alert',
type: 'orange',
content: '请输入消息内容。',
});
return false;
}
AjaxForm(
"POST",
"/api/tool/send_message",
{message: messageContent},
function () {
$(this).hide();
$("#btnSendLoading").show();
},
function (data) {
$("#btnSendLoading").hide();
$("#btnSend").show();
if (data.status === 'OK') {
$("#message_content").val("");
SuccessNotify("消息发送成功");
}
},
function (response) {
$("#btnSendLoading").hide();
$("#btnSend").show();
AjaxError(response);
}
);
});
})
</script>
</body>
</html>
+2 -2
View File
@@ -23,7 +23,7 @@ import (
"fmt"
"time"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
"github.com/pkg/errors"
"gorm.io/gorm"
@@ -135,7 +135,7 @@ func (qb *{{.QueryBuilderName}}) Offset(offset int) *{{.QueryBuilderName}} {
{{$queryBuilderName := .QueryBuilderName}}
{{range .OptionFields}}
func (qb *{{$queryBuilderName}}) Where{{call $.Helpers.Titelize .FieldName}}(p db_repo.Predicate, value {{.FieldType}}) *{{$queryBuilderName}} {
func (qb *{{$queryBuilderName}}) Where{{call $.Helpers.Titelize .FieldName}}(p mysql.Predicate, value {{.FieldType}}) *{{$queryBuilderName}} {
qb.where = append(qb.where, struct {
prefix string
value interface{}
-102
View File
@@ -1,102 +0,0 @@
## 执行命令
```$xslt
// test_handler 为 ./internal/api/controller/ 中的包名
./scripts/handlergen.sh test_handler
```
## 模板文件参考
```go
package test_handler
import (
"github.com/xinliangnote/go-gin-api/internal/api/service/user_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"go.uber.org/zap"
)
var _ Handler = (*handler)(nil)
type Handler interface {
// i 为了避免被其他包实现
i()
// Create 创建用户
// @Tags Test
// @Router /test/create [post]
Create() core.HandlerFunc
// Update 编辑用户
// @Tags Test
// @Router /test/update [post]
Update() core.HandlerFunc
// Delete 删除用户
// @Tags Test
// @Router /test/delete [post]
Delete() core.HandlerFunc
// Detail 用户详情
// @Tags Test
// @Router /test/detail [post]
Detail() core.HandlerFunc
}
type handler struct {
logger *zap.Logger
cache cache.Repo
userService user_service.UserService
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
userService: user_service.NewUserService(db, cache),
}
}
func (h *handler) i() {}
```
以上会生成 4 个文件
- func_create.go
- func_update.go
- func_delete.go
- func_detail.go
## func_create.go 参考
```go
package test_handler
import (
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
type createRequest struct{}
type createResponse struct{}
// Create 创建用户
// @Summary 创建用户
// @Description 创建用户
// @Tags Test
// @Accept json
// @Produce json
// @Param Request body createRequest true "请求信息"
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /test/create [post]
func (h *handler) Create() core.HandlerFunc {
return func(c core.Context) {
}
}
```
+4 -4
View File
@@ -25,7 +25,7 @@ func init() {
func main() {
fs := token.NewFileSet()
filePath := fmt.Sprintf("./internal/api/controller/%s", handlerName)
filePath := fmt.Sprintf("./internal/api/%s", handlerName)
parsedFile, err := decorator.ParseFile(fs, filePath+"/handler.go", nil, 0)
if err != nil {
log.Fatalf("parsing package: %s: %s\n", filePath, err)
@@ -59,7 +59,7 @@ func main() {
continue
}
filepath := "./internal/api/controller/" + handlerName
filepath := "./internal/api/" + handlerName
filename := fmt.Sprintf("%s/func_%s.go", filepath, strings.ToLower(v.Names[0].String()))
funcFile, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0766)
if err != nil {
@@ -89,14 +89,14 @@ func main() {
funcContent += fmt.Sprintf("// @Description%s \n", nameArr[1])
// Tags
funcContent += fmt.Sprintf("%s \n", v.Decorations().Start.All()[1])
funcContent += fmt.Sprintf("// @Accept json \n")
funcContent += fmt.Sprintf("// @Accept application/x-www-form-urlencoded \n")
funcContent += fmt.Sprintf("// @Produce json \n")
funcContent += fmt.Sprintf("// @Param Request body %sRequest true \"请求信息\" \n", Lcfirst(v.Names[0].String()))
funcContent += fmt.Sprintf("// @Success 200 {object} %sResponse \n", Lcfirst(v.Names[0].String()))
funcContent += fmt.Sprintf("// @Failure 400 {object} code.Failure \n")
// Router
funcContent += fmt.Sprintf("%s \n", v.Decorations().Start.All()[2])
funcContent += fmt.Sprintf("func (h *handler) %s() core.HandlerFunc { \n return func(c core.Context) {\n\n}}", v.Names[0].String())
funcContent += fmt.Sprintf("func (h *handler) %s() core.HandlerFunc { \n return func(ctx core.Context) {\n\n}}", v.Names[0].String())
funcFile.WriteString(funcContent)
funcFile.Close()
+4 -4
View File
@@ -75,7 +75,7 @@ func main() {
for _, table := range tables {
filepath := "./internal/api/repository/db_repo/" + table.Name + "_repo"
filepath := "./internal/repository/mysql/" + table.Name
_ = os.Mkdir(filepath, 0766)
fmt.Println("create dir : ", filepath)
@@ -85,7 +85,7 @@ func main() {
fmt.Printf("markdown file error %v\n", err.Error())
return
}
fmt.Println(" └── file : ", table.Name+"_repo/gen_table.md")
fmt.Println(" └── file : ", table.Name+"/gen_table.md")
modelName := fmt.Sprintf("%s/gen_model.go", filepath)
modelFile, err := os.OpenFile(modelName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0766)
@@ -93,9 +93,9 @@ func main() {
fmt.Printf("create and open model file error %v\n", err.Error())
return
}
fmt.Println(" └── file : ", table.Name+"_repo/gen_model.go")
fmt.Println(" └── file : ", table.Name+"/gen_model.go")
modelContent := fmt.Sprintf("package %s%s\n", table.Name, "_repo")
modelContent := fmt.Sprintf("package %s\n", table.Name)
modelContent += fmt.Sprintf(`import "time"`)
modelContent += fmt.Sprintf("\n\n// %s %s \n", capitalize(table.Name), table.Comment.String)
modelContent += fmt.Sprintf("//go:generate gormgen -structs %s -input . \n", capitalize(table.Name))
+59 -15
View File
@@ -1,9 +1,15 @@
package configs
import (
"bytes"
_ "embed"
"io"
"os"
"path/filepath"
"time"
"github.com/xinliangnote/go-gin-api/pkg/env"
"github.com/xinliangnote/go-gin-api/pkg/file"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
@@ -49,16 +55,6 @@ type Config struct {
To string `toml:"to"`
} `toml:"mail"`
JWT struct {
Secret string `toml:"secret"`
ExpireDuration time.Duration `toml:"expireDuration"`
} `toml:"jwt"`
URLToken struct {
Secret string `toml:"secret"`
ExpireDuration time.Duration `toml:"expireDuration"`
} `toml:"urlToken"`
HashIds struct {
Secret string `toml:"secret"`
Length int `toml:"length"`
@@ -69,12 +65,39 @@ type Config struct {
} `toml:"language"`
}
func init() {
viper.SetConfigName(env.Active().Value() + "_configs")
viper.SetConfigType("toml")
viper.AddConfigPath("./configs")
var (
//go:embed dev_configs.toml
devConfigs []byte
if err := viper.ReadInConfig(); err != nil {
//go:embed fat_configs.toml
fatConfigs []byte
//go:embed uat_configs.toml
uatConfigs []byte
//go:embed pro_configs.toml
proConfigs []byte
)
func init() {
var r io.Reader
switch env.Active().Value() {
case "dev":
r = bytes.NewReader(devConfigs)
case "fat":
r = bytes.NewReader(fatConfigs)
case "uat":
r = bytes.NewReader(uatConfigs)
case "pro":
r = bytes.NewReader(proConfigs)
default:
r = bytes.NewReader(fatConfigs)
}
viper.SetConfigType("toml")
if err := viper.ReadConfig(r); err != nil {
panic(err)
}
@@ -82,6 +105,27 @@ func init() {
panic(err)
}
viper.SetConfigName(env.Active().Value() + "_configs")
viper.AddConfigPath("./configs")
configFile := "./configs/" + env.Active().Value() + "_configs.toml"
_, ok := file.IsExists(configFile)
if !ok {
if err := os.MkdirAll(filepath.Dir(configFile), 0766); err != nil {
panic(err)
}
f, err := os.Create(configFile)
if err != nil {
panic(err)
}
defer f.Close()
if err := viper.WriteConfig(); err != nil {
panic(err)
}
}
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
if err := viper.Unmarshal(config); err != nil {
+15 -4
View File
@@ -1,8 +1,13 @@
package configs
import "time"
const (
// MinGoVersion 最小 Go 版本
MinGoVersion = 1.16
// ProjectVersion 项目版本
ProjectVersion = "v1.2.7"
ProjectVersion = "v1.2.8"
// ProjectName 项目名称
ProjectName = "go-gin-api"
@@ -25,14 +30,14 @@ const (
// HeaderLoginToken 登录验证 TokenHeader 中传递的参数
HeaderLoginToken = "Token"
// HeaderSignToken 签名验证 TokenHeader 中传递的参数
// HeaderSignToken 签名验证 AuthorizationHeader 中传递的参数
HeaderSignToken = "Authorization"
// HeaderSignTokenDate 签名验证 DateHeader 中传递的参数
HeaderSignTokenDate = "Authorization-Date"
// RedisKeyPrefixRequestID Redis Key 前缀 - 防止重复提交
RedisKeyPrefixRequestID = ProjectName + ":request-id:"
// HeaderSignTokenTimeout 签名有效期为 2 分钟
HeaderSignTokenTimeout = time.Minute * 2
// RedisKeyPrefixLoginUser Redis Key 前缀 - 登录用户信息
RedisKeyPrefixLoginUser = ProjectName + ":login-user:"
@@ -45,4 +50,10 @@ const (
// EnUS 英文 - 美国
EnUS = "en-us"
// MaxRequestsPerSecond 每秒最大请求量
MaxRequestsPerSecond = 10000
// LoginSessionTTL 登录有效期为 24 小时
LoginSessionTTL = time.Hour * 24
)
-8
View File
@@ -3,10 +3,6 @@
length = 12
secret = "6ab6122836cfef95f8db"
[jwt]
expireduration = 24
secret = "i1ydX9RtHyuJTrw7frcu"
[language]
local = "zh-cn"
@@ -43,7 +39,3 @@
minidleconns = 5
pass = ""
poolsize = 10
[urltoken]
expireduration = 10
secret = "i1ydX9RtHyuJTrw7frcu"
+788 -251
View File
File diff suppressed because it is too large Load Diff
-20
View File
@@ -1,20 +0,0 @@
## Jaeger Demo 代码
- 代码在 [v1.0](https://github.com/xinliangnote/go-gin-api/releases/tag/v1.0) 版本。
#### Jaeger Demo 文档
访问:
```
http://127.0.0.1:9999/jaeger_test
```
服务端测试代码:
- [https://github.com/xinliangnote/go-jaeger-demo](https://github.com/xinliangnote/go-jaeger-demo)
![](https://github.com/xinliangnote/Go/blob/master/03-go-gin-api%20%5B文档%5D/images/jaeger_demo_2.png)
![](https://github.com/xinliangnote/Go/blob/master/03-go-gin-api%20%5B文档%5D/images/jaeger_demo_3.png)
+776 -245
View File
File diff suppressed because it is too large Load Diff
+488 -188
View File
File diff suppressed because it is too large Load Diff
-5
View File
@@ -13,7 +13,6 @@ Features:
1. GraphQL supported by [GraphQL](https://github.com/99designs/gqlgen)
1. Trace project internal invoking
1. Visualized performance analysis supported by [pprof](https://github.com/gin-contrib/pprof)
1. Industry standard RFC 7519 method for authentication supported by [jwt](https://github.com/dgrijalva/jwt-go)
1. Uniformly defined error codes supported by errno
1. Blazing fast, structured, leveled logging system by [zap](https://go.uber.org/zap)
1. Complete configuration solution supported by [viper](https://github.com/spf13/viper)
@@ -29,10 +28,6 @@ Features:
**Detailed documentation[https://www.yuque.com/xinliangnote/go-gin-api/ngc3x5](https://www.yuque.com/xinliangnote/go-gin-api/ngc3x5)**
## Others
To check Jaeger code [v1.0](https://github.com/xinliangnote/go-gin-api/releases/tag/v1.0)documentation:[jaeger.md](https://github.com/xinliangnote/go-gin-api/blob/master/docs/jaeger.md) 。
## Contributing
Help us with translating `go-gin-api` to your native language.
+26 -36
View File
@@ -1,49 +1,39 @@
module github.com/xinliangnote/go-gin-api
go 1.15
go 1.16
require (
github.com/99designs/gqlgen v0.13.0
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/99designs/gqlgen v0.14.0
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/dave/dst v0.26.2
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fsnotify/fsnotify v1.4.9
github.com/fsnotify/fsnotify v1.5.1
github.com/gin-contrib/pprof v1.3.0
github.com/gin-gonic/gin v1.7.0
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-openapi/spec v0.20.0 // indirect
github.com/go-playground/locales v0.13.0
github.com/go-playground/universal-translator v0.17.0
github.com/go-playground/validator/v10 v10.4.1
github.com/go-redis/redis/v7 v7.4.0
github.com/golang/protobuf v1.5.2
github.com/gin-gonic/gin v1.7.4
github.com/go-playground/locales v0.14.0
github.com/go-playground/universal-translator v0.18.0
github.com/go-playground/validator/v10 v10.9.0
github.com/go-redis/redis/v7 v7.4.1
github.com/gorilla/websocket v1.4.2
github.com/jakecoffman/cron v0.0.0-20190106200828-7e2009c226a5
github.com/jinzhu/gorm v1.9.16
github.com/onsi/ginkgo v1.14.2 // indirect
github.com/onsi/gomega v1.10.4 // indirect
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.10.0
github.com/rs/cors v1.7.0
github.com/shirou/gopsutil v3.21.2+incompatible
github.com/speps/go-hashids v2.0.0+incompatible
github.com/spf13/cast v1.3.1
github.com/spf13/viper v1.8.0
github.com/swaggo/gin-swagger v1.3.0
github.com/swaggo/swag v1.7.0
github.com/tklauser/go-sysconf v0.3.4 // indirect
github.com/vektah/gqlparser/v2 v2.1.0
go.uber.org/multierr v1.6.0
go.uber.org/zap v1.17.0
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
golang.org/x/tools v0.1.4
google.golang.org/grpc v1.38.0
github.com/prometheus/client_golang v1.11.0
github.com/rs/cors v1.8.0
github.com/shirou/gopsutil v3.21.10+incompatible
github.com/speps/go-hashids v1.0.0
github.com/spf13/cast v1.4.1
github.com/spf13/viper v1.9.0
github.com/swaggo/gin-swagger v1.3.3
github.com/swaggo/swag v1.7.4
github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/vektah/gqlparser/v2 v2.2.0
go.uber.org/multierr v1.7.0
go.uber.org/zap v1.19.1
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
golang.org/x/tools v0.1.7
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gorm.io/driver/mysql v1.0.3
gorm.io/gorm v1.20.9
gorm.io/driver/mysql v1.2.0
gorm.io/gorm v1.22.3
)
+199 -301
View File
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
package alert
import (
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/proposal"
"github.com/xinliangnote/go-gin-api/pkg/errors"
"github.com/xinliangnote/go-gin-api/pkg/mail"
"go.uber.org/zap"
)
// NotifyHandler 告警通知
func NotifyHandler(logger *zap.Logger) func(msg *proposal.AlertMessage) {
if logger == nil {
panic("logger required")
}
return func(msg *proposal.AlertMessage) {
cfg := configs.Get().Mail
if cfg.Host == "" || cfg.Port == 0 || cfg.User == "" || cfg.Pass == "" || cfg.To == "" {
logger.Error("Mail config error")
return
}
subject, body, err := newHTMLEmail(
msg.Method,
msg.HOST,
msg.URI,
msg.TraceID,
msg.ErrorMessage,
msg.ErrorStack,
)
if err != nil {
logger.Error("email template error", zap.Error(err))
return
}
options := &mail.Options{
MailHost: cfg.Host,
MailPort: cfg.Port,
MailUser: cfg.User,
MailPass: cfg.Pass,
MailTo: cfg.To,
Subject: subject,
Body: body,
}
if err := mail.Send(options); err != nil {
logger.Error("发送告警通知邮件失败", zap.Error(errors.WithStack(err)))
}
return
}
}
@@ -1,6 +1,54 @@
package templates
package alert
const PanicMail = `
import (
"bytes"
"fmt"
"html/template"
"time"
)
// NewHTMLEmail 告警邮件模板
func newHTMLEmail(method, host, uri, id string, msg interface{}, stack string) (subject string, body string, err error) {
mailData := &struct {
URL string
ID string
Msg string
Stack string
Year int
}{
URL: fmt.Sprintf("%s %s%s", method, host, uri),
ID: id,
Msg: fmt.Sprintf("%+v", msg),
Stack: stack,
Year: time.Now().Year(),
}
// subject 邮件主题
subject = fmt.Sprintf("[系统告警]-%s", uri)
// body 邮件内容
body, err = getEmailHTMLContent(mailTemplate, mailData)
return
}
// getEmailHTMLContent 获取邮件模板
func getEmailHTMLContent(mailTpl string, mailData interface{}) (string, error) {
tpl, err := template.New("email tpl").Parse(mailTpl)
if err != nil {
return "", err
}
buffer := new(bytes.Buffer)
err = tpl.Execute(buffer, mailData)
if err != nil {
return "", err
}
return buffer.String(), nil
}
const mailTemplate = `
<!DOCTYPE html>
<html>
@@ -27,7 +75,7 @@ const PanicMail = `
<!-- Logo -->
<tr>
<td style="padding: 25px 0; text-align: center;">
系统异常
系统告警
</td>
</tr>
@@ -84,7 +132,7 @@ const PanicMail = `
Stack:
</td>
<td style="width: 90%;">
{{.Stack}}}
{{.Stack}}
</td>
</tr>
</table>
@@ -1,20 +1,19 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/admin"
)
type createRequest struct {
Username string `form:"username" binding:"required"` // 用户名
Nickname string `form:"nickname" binding:"required"` // 昵称
Mobile string `form:"mobile" binding:"required"` // 手机号
Password string `form:"password" binding:"required"` // 密码
Password string `form:"password" binding:"required"` // MD5后的密码
}
type createResponse struct {
@@ -25,29 +24,30 @@ type createResponse struct {
// @Summary 新增管理员
// @Description 新增管理员
// @Tags API.admin
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param username formData string true "用户名"
// @Param nickname formData string true "昵称"
// @Param mobile formData string true "手机号"
// @Param password formData string true "密码"
// @Param password formData string true "MD5后的密码"
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin [post]
// @Security LoginToken
func (h *handler) Create() core.HandlerFunc {
return func(c core.Context) {
req := new(createRequest)
res := new(createResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
validation.Error(err)).WithErr(err),
validation.Error(err)).WithError(err),
)
return
}
createData := new(admin_service.CreateAdminData)
createData := new(admin.CreateAdminData)
createData.Nickname = req.Nickname
createData.Username = req.Username
createData.Mobile = req.Mobile
@@ -55,10 +55,10 @@ func (h *handler) Create() core.HandlerFunc {
id, err := h.adminService.Create(c, createData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminCreateError,
code.Text(code.AdminCreateError)).WithErr(err),
code.Text(code.AdminCreateError)).WithError(err),
)
return
}
@@ -1,12 +1,11 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/admin"
)
type createAdminMenuRequest struct {
@@ -22,46 +21,47 @@ type createAdminMenuResponse struct {
// @Summary 提交菜单授权
// @Description 提交菜单授权
// @Tags API.admin
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "Hashid"
// @Param actions formData string true "功能权限ID,多个用,分割"
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/menu [post]
// @Security LoginToken
func (h *handler) CreateAdminMenu() core.HandlerFunc {
return func(c core.Context) {
req := new(createAdminMenuRequest)
res := new(createAdminMenuResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
createData := new(admin_service.CreateMenuData)
createData := new(admin.CreateMenuData)
createData.AdminId = int32(ids[0])
createData.Actions = req.Actions
err = h.adminService.CreateMenu(c, createData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminMenuCreateError,
code.Text(code.AdminMenuCreateError)).WithErr(err),
code.Text(code.AdminMenuCreateError)).WithError(err),
)
return
}
@@ -1,11 +1,10 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type deleteRequest struct {
@@ -26,25 +25,26 @@ type deleteResponse struct {
// @Success 200 {object} deleteResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/{id} [delete]
// @Security LoginToken
func (h *handler) Delete() core.HandlerFunc {
return func(c core.Context) {
req := new(deleteRequest)
res := new(deleteResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -53,10 +53,10 @@ func (h *handler) Delete() core.HandlerFunc {
err = h.adminService.Delete(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminDeleteError,
code.Text(code.AdminDeleteError)).WithErr(err),
code.Text(code.AdminDeleteError)).WithError(err),
)
return
}
+77
View File
@@ -0,0 +1,77 @@
package admin
import (
"encoding/json"
"net/http"
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
"github.com/xinliangnote/go-gin-api/internal/services/admin"
)
type detailResponse struct {
Username string `json:"username"` // 用户名
Nickname string `json:"nickname"` // 昵称
Mobile string `json:"mobile"` // 手机号
Menu []admin.ListMyMenuData `json:"menu"` // 菜单栏
}
// Detail 管理员详情
// @Summary 管理员详情
// @Description 管理员详情
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Success 200 {object} detailResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/info [get]
// @Security LoginToken
func (h *handler) Detail() core.HandlerFunc {
return func(ctx core.Context) {
res := new(detailResponse)
searchOneData := new(admin.SearchOneData)
searchOneData.Id = ctx.SessionUserInfo().UserID
searchOneData.IsUsed = 1
info, err := h.adminService.Detail(ctx, searchOneData)
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminDetailError,
code.Text(code.AdminDetailError)).WithError(err),
)
return
}
menuCacheData, err := h.cache.Get(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(searchOneData.Id)+":menu", redis.WithTrace(ctx.Trace()))
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminDetailError,
code.Text(code.AdminDetailError)).WithError(err),
)
return
}
var menuData []admin.ListMyMenuData
err = json.Unmarshal([]byte(menuCacheData), &menuData)
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminDetailError,
code.Text(code.AdminDetailError)).WithError(err),
)
return
}
res.Username = info.Username
res.Nickname = info.Nickname
res.Mobile = info.Mobile
res.Menu = menuData
ctx.Payload(res)
}
}
@@ -1,15 +1,14 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
"github.com/xinliangnote/go-gin-api/internal/services/admin"
"github.com/xinliangnote/go-gin-api/pkg/timeutil"
"github.com/spf13/cast"
)
@@ -49,25 +48,26 @@ type listResponse struct {
// @Summary 管理员列表
// @Description 管理员列表
// @Tags API.admin
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param page query int false "第几页"
// @Param page_size query string false "每页显示条数"
// @Param page query int true "第几页" default(1)
// @Param page_size query int true "每页显示条数" default(10)
// @Param username query string false "用户名"
// @Param nickname query string false "昵称"
// @Param mobile query string false "手机号"
// @Success 200 {object} listResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin [get]
// @Security LoginToken
func (h *handler) List() core.HandlerFunc {
return func(c core.Context) {
req := new(listRequest)
res := new(listResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
@@ -82,7 +82,7 @@ func (h *handler) List() core.HandlerFunc {
pageSize = 10
}
searchData := new(admin_service.SearchData)
searchData := new(admin.SearchData)
searchData.Page = page
searchData.PageSize = pageSize
searchData.Username = req.Username
@@ -91,20 +91,20 @@ func (h *handler) List() core.HandlerFunc {
resListData, err := h.adminService.PageList(c, searchData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminListError,
code.Text(code.AdminListError)).WithErr(err),
code.Text(code.AdminListError)).WithError(err),
)
return
}
resCountData, err := h.adminService.PageListCount(c, searchData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminListError,
code.Text(code.AdminListError)).WithErr(err),
code.Text(code.AdminListError)).WithError(err),
)
return
}
@@ -116,10 +116,10 @@ func (h *handler) List() core.HandlerFunc {
for k, v := range resListData {
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsEncodeError,
code.Text(code.HashIdsEncodeError)).WithErr(err),
code.Text(code.HashIdsEncodeError)).WithError(err),
)
return
}
@@ -137,9 +137,9 @@ func (h *handler) List() core.HandlerFunc {
Mobile: v.Mobile,
IsUsed: cast.ToInt(v.IsUsed),
IsOnline: isOnline,
CreatedAt: v.CreatedAt.Format(time_parse.CSTLayout),
CreatedAt: v.CreatedAt.Format(timeutil.CSTLayout),
CreatedUser: v.CreatedUser,
UpdatedAt: v.UpdatedAt.Format(time_parse.CSTLayout),
UpdatedAt: v.UpdatedAt.Format(timeutil.CSTLayout),
UpdatedUser: v.UpdatedUser,
}
@@ -1,12 +1,11 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/admin"
)
type listAdminMenuRequest struct {
@@ -14,68 +13,69 @@ type listAdminMenuRequest struct {
}
type listAdminMenuResponse struct {
List []admin_service.ListMenuData `json:"list"`
UserName string `json:"username"`
List []admin.ListMenuData `json:"list"`
UserName string `json:"username"`
}
// ListAdminMenu 菜单授权列表
// @Summary 菜单授权列表
// @Description 菜单授权列表
// @Tags API.admin
// @Accept json
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id path string true "hashId"
// @Success 200 {object} listAdminMenuResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/menu/:id [get]
// @Router /api/admin/menu/{id} [get]
// @Security LoginToken
func (h *handler) ListAdminMenu() core.HandlerFunc {
return func(c core.Context) {
req := new(listAdminMenuRequest)
res := new(listAdminMenuResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
searchOneData := new(admin_service.SearchOneData)
searchOneData := new(admin.SearchOneData)
searchOneData.Id = int32(ids[0])
searchOneData.IsUsed = 1
info, err := h.adminService.Detail(c, searchOneData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminMenuListError,
code.Text(code.AdminMenuListError)).WithErr(err),
code.Text(code.AdminMenuListError)).WithError(err),
)
return
}
res.UserName = info.Username
searchData := new(admin_service.SearchListMenuData)
searchData := new(admin.SearchListMenuData)
searchData.AdminId = int32(ids[0])
listData, err := h.adminService.ListMenu(c, searchData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminMenuListError,
code.Text(code.AdminMenuListError)).WithErr(err),
code.Text(code.AdminMenuListError)).WithError(err),
)
return
}
@@ -1,17 +1,16 @@
package admin_handler
package admin
import (
"encoding/json"
"net/http"
"time"
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/proposal"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
"github.com/xinliangnote/go-gin-api/internal/services/admin"
"github.com/xinliangnote/go-gin-api/pkg/errors"
)
@@ -28,86 +27,78 @@ type loginResponse struct {
// @Summary 管理员登录
// @Description 管理员登录
// @Tags API.admin
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param username formData string true "用户名"
// @Param password formData string true "密码"
// @Param password formData string true "MD5后的密码"
// @Success 200 {object} loginResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/login [post]
// @Router /api/login [post]
// @Security LoginToken
func (h *handler) Login() core.HandlerFunc {
return func(c core.Context) {
req := new(loginRequest)
res := new(loginResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
searchOneData := new(admin_service.SearchOneData)
searchOneData := new(admin.SearchOneData)
searchOneData.Username = req.Username
searchOneData.Password = password.GeneratePassword(req.Password)
searchOneData.IsUsed = 1
info, err := h.adminService.Detail(c, searchOneData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithErr(err),
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
if info == nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithErr(errors.New("未查询出符合条件的用户")),
code.Text(code.AdminLoginError)).WithError(errors.New("未查询出符合条件的用户")),
)
return
}
token := password.GenerateLoginToken(info.Id)
adminCacheData := &struct {
Id int32 `json:"id"` // 主键ID
Username string `json:"username"` // 用户名
Nickname string `json:"nickname"` // 昵称
Mobile string `json:"mobile"` // 手机号
}{
Id: info.Id,
Username: info.Username,
Nickname: info.Nickname,
Mobile: info.Mobile,
// 用户信息
sessionUserInfo := &proposal.SessionUserInfo{
UserID: info.Id,
UserName: info.Username,
}
// 用户信息
adminJsonInfo, _ := json.Marshal(adminCacheData)
// 将用户信息记录到 Redis 中
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token, string(adminJsonInfo), time.Hour*24, cache.WithTrace(c.Trace()))
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token, string(sessionUserInfo.Marshal()), configs.LoginSessionTTL, redis.WithTrace(c.Trace()))
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithErr(err),
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
searchMenuData := new(admin_service.SearchMyMenuData)
searchMenuData := new(admin.SearchMyMenuData)
searchMenuData.AdminId = info.Id
menu, err := h.adminService.MyMenu(c, searchMenuData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithErr(err),
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
@@ -116,24 +107,24 @@ func (h *handler) Login() core.HandlerFunc {
menuJsonInfo, _ := json.Marshal(menu)
// 将菜单栏信息记录到 Redis 中
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":menu", string(menuJsonInfo), time.Hour*24, cache.WithTrace(c.Trace()))
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":menu", string(menuJsonInfo), configs.LoginSessionTTL, redis.WithTrace(c.Trace()))
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithErr(err),
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
searchActionData := new(admin_service.SearchMyActionData)
searchActionData := new(admin.SearchMyActionData)
searchActionData.AdminId = info.Id
action, err := h.adminService.MyAction(c, searchActionData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithErr(err),
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
@@ -142,12 +133,12 @@ func (h *handler) Login() core.HandlerFunc {
actionJsonInfo, _ := json.Marshal(action)
// 将可访问接口信息记录到 Redis 中
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":action", string(actionJsonInfo), time.Hour*24, cache.WithTrace(c.Trace()))
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":action", string(actionJsonInfo), configs.LoginSessionTTL, redis.WithTrace(c.Trace()))
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithErr(err),
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
@@ -1,13 +1,12 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
"github.com/xinliangnote/go-gin-api/pkg/errors"
)
@@ -19,21 +18,22 @@ type logoutResponse struct {
// @Summary 管理员登出
// @Description 管理员登出
// @Tags API.admin
// @Accept json
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Success 200 {object} logoutResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/login [post]
// @Router /api/admin/logout [post]
// @Security LoginToken
func (h *handler) Logout() core.HandlerFunc {
return func(c core.Context) {
res := new(logoutResponse)
res.Username = c.UserName()
res.Username = c.SessionUserInfo().UserName
if !h.cache.Del(configs.RedisKeyPrefixLoginUser+c.GetHeader(configs.HeaderLoginToken), cache.WithTrace(c.Trace())) {
c.AbortWithError(errno.NewError(
if !h.cache.Del(configs.RedisKeyPrefixLoginUser+c.GetHeader(configs.HeaderLoginToken), redis.WithTrace(c.Trace())) {
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLogOutError,
code.Text(code.AdminLogOutError)).WithErr(errors.New("cache del err")),
code.Text(code.AdminLogOutError)).WithError(errors.New("cache del err")),
)
return
}
@@ -1,15 +1,12 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/spf13/cast"
"github.com/xinliangnote/go-gin-api/internal/services/admin"
)
type modifyPasswordRequest struct {
@@ -25,53 +22,52 @@ type modifyPasswordResponse struct {
// @Summary 修改密码
// @Description 修改密码
// @Tags API.admin
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param old_password formData string true "旧密码"
// @Param new_password formData string true "新密码"
// @Success 200 {object} modifyPasswordResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/modify_password [patch]
// @Security LoginToken
func (h *handler) ModifyPassword() core.HandlerFunc {
return func(c core.Context) {
return func(ctx core.Context) {
req := new(modifyPasswordRequest)
res := new(modifyPasswordResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
userId := cast.ToInt32(c.UserID())
searchOneData := new(admin_service.SearchOneData)
searchOneData.Id = userId
searchOneData := new(admin.SearchOneData)
searchOneData.Id = ctx.SessionUserInfo().UserID
searchOneData.Password = password.GeneratePassword(req.OldPassword)
searchOneData.IsUsed = 1
info, err := h.adminService.Detail(c, searchOneData)
info, err := h.adminService.Detail(ctx, searchOneData)
if err != nil || info == nil {
c.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminModifyPasswordError,
code.Text(code.AdminModifyPasswordError)).WithErr(err),
code.Text(code.AdminModifyPasswordError)).WithError(err),
)
return
}
if err := h.adminService.ModifyPassword(c, userId, req.NewPassword); err != nil {
c.AbortWithError(errno.NewError(
if err := h.adminService.ModifyPassword(ctx, ctx.SessionUserInfo().UserID, req.NewPassword); err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminModifyPasswordError,
code.Text(code.AdminModifyPasswordError)).WithErr(err),
code.Text(code.AdminModifyPasswordError)).WithError(err),
)
return
}
res.Username = c.UserName()
c.Payload(res)
res.Username = ctx.SessionUserInfo().UserName
ctx.Payload(res)
}
}
@@ -1,14 +1,11 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/spf13/cast"
"github.com/xinliangnote/go-gin-api/internal/services/admin"
)
type modifyPersonalInfoRequest struct {
@@ -24,42 +21,41 @@ type modifyPersonalInfoResponse struct {
// @Summary 修改个人信息
// @Description 修改个人信息
// @Tags API.admin
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param nickname formData string true "昵称"
// @Param mobile formData string true "手机号"
// @Success 200 {object} modifyPersonalInfoResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/modify_password [patch]
// @Router /api/admin/modify_personal_info [patch]
// @Security LoginToken
func (h *handler) ModifyPersonalInfo() core.HandlerFunc {
return func(c core.Context) {
return func(ctx core.Context) {
req := new(modifyPersonalInfoRequest)
res := new(modifyPersonalInfoResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
userId := cast.ToInt32(c.UserID())
modifyData := new(admin_service.ModifyData)
modifyData := new(admin.ModifyData)
modifyData.Nickname = req.Nickname
modifyData.Mobile = req.Mobile
if err := h.adminService.ModifyPersonalInfo(c, userId, modifyData); err != nil {
c.AbortWithError(errno.NewError(
if err := h.adminService.ModifyPersonalInfo(ctx, ctx.SessionUserInfo().UserID, modifyData); err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminModifyPersonalInfoError,
code.Text(code.AdminModifyPersonalInfoError)).WithErr(err),
code.Text(code.AdminModifyPersonalInfoError)).WithError(err),
)
return
}
res.Username = c.UserName()
c.Payload(res)
res.Username = ctx.SessionUserInfo().UserName
ctx.Payload(res)
}
}
@@ -1,14 +1,13 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
)
type offlineRequest struct {
@@ -23,40 +22,41 @@ type offlineResponse struct {
// @Summary 下线管理员
// @Description 下线管理员
// @Tags API.admin
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "Hashid"
// @Success 200 {object} offlineResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/offline [patch]
// @Security LoginToken
func (h *handler) Offline() core.HandlerFunc {
return func(c core.Context) {
req := new(offlineRequest)
res := new(offlineResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
id := int32(ids[0])
b := h.cache.Del(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(id), cache.WithTrace(c.Trace()))
b := h.cache.Del(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(id), redis.WithTrace(c.Trace()))
if !b {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminOfflineError,
code.Text(code.AdminOfflineError)),
@@ -1,11 +1,10 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type resetPasswordRequest struct {
@@ -26,25 +25,26 @@ type resetPasswordResponse struct {
// @Success 200 {object} resetPasswordResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/reset_password/{id} [patch]
// @Security LoginToken
func (h *handler) ResetPassword() core.HandlerFunc {
return func(c core.Context) {
req := new(resetPasswordRequest)
res := new(resetPasswordResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -53,10 +53,10 @@ func (h *handler) ResetPassword() core.HandlerFunc {
err = h.adminService.ResetPassword(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminResetPasswordError,
code.Text(code.AdminResetPasswordError)).WithErr(err),
code.Text(code.AdminResetPasswordError)).WithError(err),
)
return
}
@@ -1,11 +1,10 @@
package admin_handler
package admin
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type updateUsedRequest struct {
@@ -21,32 +20,33 @@ type updateUsedResponse struct {
// @Summary 更新管理员为启用/禁用
// @Description 更新管理员为启用/禁用
// @Tags API.admin
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "Hashid"
// @Param used formData int true "是否启用 1:是 -1:否"
// @Success 200 {object} updateUsedResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/used [patch]
// @Security LoginToken
func (h *handler) UpdateUsed() core.HandlerFunc {
return func(c core.Context) {
req := new(updateUsedRequest)
res := new(updateUsedResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -55,10 +55,10 @@ func (h *handler) UpdateUsed() core.HandlerFunc {
err = h.adminService.UpdateUsed(c, id, req.Used)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminUpdateError,
code.Text(code.AdminUpdateError)).WithErr(err),
code.Text(code.AdminUpdateError)).WithError(err),
)
return
}
@@ -1,11 +1,11 @@
package admin_handler
package admin
import (
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
"github.com/xinliangnote/go-gin-api/internal/services/admin"
"github.com/xinliangnote/go-gin-api/pkg/hash"
"go.uber.org/zap"
@@ -18,7 +18,7 @@ type Handler interface {
// Login 管理员登录
// @Tags API.admin
// @Router /api/admin/login [post]
// @Router /api/login [post]
Login() core.HandlerFunc
// Logout 管理员登出
@@ -78,23 +78,23 @@ type Handler interface {
// ListAdminMenu 菜单授权列表
// @Tags API.admin
// @Router /api/admin/menu/:id [get]
// @Router /api/admin/menu/{id} [get]
ListAdminMenu() core.HandlerFunc
}
type handler struct {
logger *zap.Logger
cache cache.Repo
cache redis.Repo
hashids hash.Hash
adminService admin_service.Service
adminService admin.Service
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
func New(logger *zap.Logger, db mysql.Repo, cache redis.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
hashids: hash.New(configs.Get().HashIds.Secret, configs.Get().HashIds.Length),
adminService: admin_service.New(db, cache),
adminService: admin.New(db, cache),
}
}
@@ -1,12 +1,11 @@
package authorized_handler
package authorized
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
)
type createRequest struct {
@@ -23,7 +22,7 @@ type createResponse struct {
// @Summary 新增调用方
// @Description 新增调用方
// @Tags API.authorized
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param business_key formData string true "调用方key"
// @Param business_developer formData string true "调用方对接人"
@@ -31,30 +30,31 @@ type createResponse struct {
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized [post]
// @Security LoginToken
func (h *handler) Create() core.HandlerFunc {
return func(c core.Context) {
req := new(createRequest)
res := new(createResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
createData := new(authorized_service.CreateAuthorizedData)
createData := new(authorized.CreateAuthorizedData)
createData.BusinessKey = req.BusinessKey
createData.BusinessDeveloper = req.BusinessDeveloper
createData.Remark = req.Remark
id, err := h.authorizedService.Create(c, createData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedCreateError,
code.Text(code.AuthorizedCreateError)).WithErr(err),
code.Text(code.AuthorizedCreateError)).WithError(err),
)
return
}
@@ -1,12 +1,11 @@
package authorized_handler
package authorized
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
)
type createAPIRequest struct {
@@ -23,7 +22,7 @@ type createAPIResponse struct {
// @Summary 授权调用方接口地址
// @Description 授权调用方接口地址
// @Tags API.authorized
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "HashID"
// @Param method formData string true "请求方法"
@@ -31,25 +30,26 @@ type createAPIResponse struct {
// @Success 200 {object} createAPIResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized_api [post]
// @Security LoginToken
func (h *handler) CreateAPI() core.HandlerFunc {
return func(c core.Context) {
req := new(createAPIRequest)
res := new(createAPIResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -59,25 +59,25 @@ func (h *handler) CreateAPI() core.HandlerFunc {
// 通过 id 查询出 business_key
authorizedInfo, err := h.authorizedService.Detail(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedDetailError,
code.Text(code.AuthorizedDetailError)).WithErr(err),
code.Text(code.AuthorizedDetailError)).WithError(err),
)
return
}
createAPIData := new(authorized_service.CreateAuthorizedAPIData)
createAPIData := new(authorized.CreateAuthorizedAPIData)
createAPIData.BusinessKey = authorizedInfo.BusinessKey
createAPIData.Method = req.Method
createAPIData.API = req.API
createId, err := h.authorizedService.CreateAPI(c, createAPIData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedCreateAPIError,
code.Text(code.AuthorizedCreateAPIError)).WithErr(err),
code.Text(code.AuthorizedCreateAPIError)).WithError(err),
)
return
}
@@ -1,11 +1,10 @@
package authorized_handler
package authorized
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type deleteRequest struct {
@@ -26,25 +25,26 @@ type deleteResponse struct {
// @Success 200 {object} deleteResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized/{id} [delete]
// @Security LoginToken
func (h *handler) Delete() core.HandlerFunc {
return func(c core.Context) {
req := new(deleteRequest)
res := new(deleteResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -53,10 +53,10 @@ func (h *handler) Delete() core.HandlerFunc {
err = h.authorizedService.Delete(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedDeleteError,
code.Text(code.AuthorizedDeleteError)).WithErr(err),
code.Text(code.AuthorizedDeleteError)).WithError(err),
)
return
}
@@ -1,11 +1,10 @@
package authorized_handler
package authorized
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type deleteAPIRequest struct {
@@ -26,25 +25,26 @@ type deleteAPIResponse struct {
// @Success 200 {object} deleteAPIResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized_api/{id} [delete]
// @Security LoginToken
func (h *handler) DeleteAPI() core.HandlerFunc {
return func(c core.Context) {
req := new(deleteAPIRequest)
res := new(deleteAPIResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -53,10 +53,10 @@ func (h *handler) DeleteAPI() core.HandlerFunc {
err = h.authorizedService.DeleteAPI(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedDeleteAPIError,
code.Text(code.AuthorizedDeleteAPIError)).WithErr(err),
code.Text(code.AuthorizedDeleteAPIError)).WithError(err),
)
return
}
@@ -1,13 +1,12 @@
package authorized_handler
package authorized
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
"github.com/xinliangnote/go-gin-api/pkg/timeutil"
"github.com/spf13/cast"
)
@@ -48,10 +47,10 @@ type listResponse struct {
// @Summary 调用方列表
// @Description 调用方列表
// @Tags API.authorized
// @Accept json
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param page query int false "第几页"
// @Param page_size query string false "每页显示条数"
// @Param page query int true "第几页" default(1)
// @Param page_size query int true "每页显示条数" default(10)
// @Param business_key query string false "调用方key"
// @Param business_secret query string false "调用方secret"
// @Param business_developer query string false "调用方对接人"
@@ -59,15 +58,16 @@ type listResponse struct {
// @Success 200 {object} listResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized [get]
// @Security LoginToken
func (h *handler) List() core.HandlerFunc {
return func(c core.Context) {
req := new(listRequest)
res := new(listResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
@@ -82,7 +82,7 @@ func (h *handler) List() core.HandlerFunc {
pageSize = 10
}
searchData := new(authorized_service.SearchData)
searchData := new(authorized.SearchData)
searchData.Page = page
searchData.PageSize = pageSize
searchData.BusinessKey = req.BusinessKey
@@ -91,20 +91,20 @@ func (h *handler) List() core.HandlerFunc {
resListData, err := h.authorizedService.PageList(c, searchData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedListError,
code.Text(code.AuthorizedListError)).WithErr(err),
code.Text(code.AuthorizedListError)).WithError(err),
)
return
}
resCountData, err := h.authorizedService.PageListCount(c, searchData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedListError,
code.Text(code.AuthorizedListError)).WithErr(err),
code.Text(code.AuthorizedListError)).WithError(err),
)
return
}
@@ -116,10 +116,10 @@ func (h *handler) List() core.HandlerFunc {
for k, v := range resListData {
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsEncodeError,
code.Text(code.HashIdsEncodeError)).WithErr(err),
code.Text(code.HashIdsEncodeError)).WithError(err),
)
return
}
@@ -132,9 +132,9 @@ func (h *handler) List() core.HandlerFunc {
BusinessDeveloper: v.BusinessDeveloper,
Remark: v.Remark,
IsUsed: cast.ToInt(v.IsUsed),
CreatedAt: v.CreatedAt.Format(time_parse.CSTLayout),
CreatedAt: v.CreatedAt.Format(timeutil.CSTLayout),
CreatedUser: v.CreatedUser,
UpdatedAt: v.UpdatedAt.Format(time_parse.CSTLayout),
UpdatedAt: v.UpdatedAt.Format(timeutil.CSTLayout),
UpdatedUser: v.UpdatedUser,
}
@@ -1,12 +1,11 @@
package authorized_handler
package authorized
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
"github.com/spf13/cast"
)
@@ -31,31 +30,32 @@ type listAPIResponse struct {
// @Summary 调用方接口地址列表
// @Description 调用方接口地址列表
// @Tags API.authorized
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id query string true "hashID"
// @Success 200 {object} listAPIResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized_api [get]
// @Security LoginToken
func (h *handler) ListAPI() core.HandlerFunc {
return func(c core.Context) {
req := new(listAPIRequest)
res := new(listAPIResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -65,25 +65,25 @@ func (h *handler) ListAPI() core.HandlerFunc {
// 通过 id 查询出 business_key
authorizedInfo, err := h.authorizedService.Detail(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedDetailError,
code.Text(code.AuthorizedDetailError)).WithErr(err),
code.Text(code.AuthorizedDetailError)).WithError(err),
)
return
}
res.BusinessKey = authorizedInfo.BusinessKey
searchAPIData := new(authorized_service.SearchAPIData)
searchAPIData := new(authorized.SearchAPIData)
searchAPIData.BusinessKey = authorizedInfo.BusinessKey
resListData, err := h.authorizedService.ListAPI(c, searchAPIData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedListAPIError,
code.Text(code.AuthorizedListAPIError)).WithErr(err),
code.Text(code.AuthorizedListAPIError)).WithError(err),
)
return
}
@@ -93,10 +93,10 @@ func (h *handler) ListAPI() core.HandlerFunc {
for k, v := range resListData {
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsEncodeError,
code.Text(code.HashIdsEncodeError)).WithErr(err),
code.Text(code.HashIdsEncodeError)).WithError(err),
)
return
}
@@ -1,11 +1,10 @@
package authorized_handler
package authorized
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type updateUsedRequest struct {
@@ -21,32 +20,33 @@ type updateUsedResponse struct {
// @Summary 更新调用方为启用/禁用
// @Description 更新调用方为启用/禁用
// @Tags API.authorized
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "Hashid"
// @Param id formData string true "hashID"
// @Param used formData int true "是否启用 1:是 -1:否"
// @Success 200 {object} updateUsedResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized/used [patch]
// @Security LoginToken
func (h *handler) UpdateUsed() core.HandlerFunc {
return func(c core.Context) {
req := new(updateUsedRequest)
res := new(updateUsedResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -55,10 +55,10 @@ func (h *handler) UpdateUsed() core.HandlerFunc {
err = h.authorizedService.UpdateUsed(c, id, req.Used)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedUpdateError,
code.Text(code.AuthorizedUpdateError)).WithErr(err),
code.Text(code.AuthorizedUpdateError)).WithError(err),
)
return
}
@@ -1,11 +1,11 @@
package authorized_handler
package authorized
import (
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
"github.com/xinliangnote/go-gin-api/pkg/hash"
"go.uber.org/zap"
@@ -54,16 +54,16 @@ type Handler interface {
type handler struct {
logger *zap.Logger
cache cache.Repo
authorizedService authorized_service.Service
cache redis.Repo
authorizedService authorized.Service
hashids hash.Hash
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
func New(logger *zap.Logger, db mysql.Repo, cache redis.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
authorizedService: authorized_service.New(db, cache),
authorizedService: authorized.New(db, cache),
hashids: hash.New(configs.Get().HashIds.Secret, configs.Get().HashIds.Length),
}
}
@@ -1,14 +1,13 @@
package config_handler
package config
import (
"fmt"
"net/http"
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/env"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/pkg/mail"
"github.com/spf13/cast"
@@ -31,7 +30,7 @@ type emailResponse struct {
// @Summary 修改邮件配置
// @Description 修改邮件配置
// @Tags API.config
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param host formData string true "邮箱服务器"
// @Param port formData string true "端口"
@@ -41,15 +40,16 @@ type emailResponse struct {
// @Success 200 {object} emailResponse
// @Failure 400 {object} code.Failure
// @Router /api/config/email [patch]
// @Security LoginToken
func (h *handler) Email() core.HandlerFunc {
return func(c core.Context) {
req := new(emailRequest)
res := new(emailResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
@@ -64,18 +64,14 @@ func (h *handler) Email() core.HandlerFunc {
Body: fmt.Sprintf("%s[%s] 已添加您为系统告警通知人。", configs.ProjectName, env.Active().Value()),
}
if err := mail.Send(options); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.SendEmailError,
code.Text(code.SendEmailError)+err.Error()).WithErr(err),
code.Text(code.SendEmailError)+err.Error()).WithError(err),
)
return
}
viper.SetConfigName(env.Active().Value() + "_configs")
viper.SetConfigType("toml")
viper.AddConfigPath("./configs")
viper.Set("mail.host", req.Host)
viper.Set("mail.port", cast.ToInt(req.Port))
viper.Set("mail.user", req.User)
@@ -84,10 +80,10 @@ func (h *handler) Email() core.HandlerFunc {
err := viper.WriteConfig()
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.WriteConfigError,
code.Text(code.WriteConfigError)).WithErr(err),
code.Text(code.WriteConfigError)).WithError(err),
)
return
}
@@ -1,9 +1,9 @@
package config_handler
package config
import (
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
"go.uber.org/zap"
)
@@ -21,10 +21,10 @@ type Handler interface {
type handler struct {
logger *zap.Logger
cache cache.Repo
cache redis.Repo
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
func New(logger *zap.Logger, db mysql.Repo, cache redis.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
-9
View File
@@ -1,9 +0,0 @@
## controller
控制器层。
主要接收参数、验证参数、调用 `service` 层的业务逻辑处理,最后返回数据。
命名规范:
- 包名以 `_handler` 结尾。
@@ -1,79 +0,0 @@
package admin_handler
import (
"encoding/json"
"net/http"
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/spf13/cast"
)
type detailResponse struct {
Username string `json:"username"` // 用户名
Nickname string `json:"nickname"` // 昵称
Mobile string `json:"mobile"` // 手机号
Menu []admin_service.ListMyMenuData `json:"menu"` // 菜单栏
}
// Detail 管理员详情
// @Summary 管理员详情
// @Description 管理员详情
// @Tags API.admin
// @Accept json
// @Produce json
// @Success 200 {object} detailResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/info [get]
func (h *handler) Detail() core.HandlerFunc {
return func(c core.Context) {
res := new(detailResponse)
searchOneData := new(admin_service.SearchOneData)
searchOneData.Id = cast.ToInt32(c.UserID())
searchOneData.IsUsed = 1
info, err := h.adminService.Detail(c, searchOneData)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AdminDetailError,
code.Text(code.AdminDetailError)).WithErr(err),
)
return
}
menuCacheData, err := h.cache.Get(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(searchOneData.Id)+":menu", cache.WithTrace(c.Trace()))
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AdminDetailError,
code.Text(code.AdminDetailError)).WithErr(err),
)
return
}
var menuData []admin_service.ListMyMenuData
err = json.Unmarshal([]byte(menuCacheData), &menuData)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AdminDetailError,
code.Text(code.AdminDetailError)).WithErr(err),
)
return
}
res.Username = info.Username
res.Nickname = info.Nickname
res.Mobile = info.Mobile
res.Menu = menuData
c.Payload(res)
}
}
@@ -1,13 +1,12 @@
package cron_handler
package cron
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/cron_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/cron"
)
type createRequest struct {
@@ -35,7 +34,7 @@ type createResponse struct {
// @Summary 创建任务
// @Description 创建任务
// @Tags API.cron
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param name formData string true "任务名称"
// @Param spec formData string true "crontab 表达式"
@@ -54,20 +53,21 @@ type createResponse struct {
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron [post]
// @Security LoginToken
func (h *handler) Create() core.HandlerFunc {
return func(ctx core.Context) {
req := new(createRequest)
res := new(createResponse)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
validation.Error(err)).WithErr(err),
validation.Error(err)).WithError(err),
)
return
}
createData := new(cron_service.CreateCronTaskData)
createData := new(cron.CreateCronTaskData)
createData.Name = req.Name
createData.Spec = req.Spec
createData.Command = req.Command
@@ -85,10 +85,10 @@ func (h *handler) Create() core.HandlerFunc {
id, err := h.cronService.Create(ctx, createData)
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.CronCreateError,
code.Text(code.CronCreateError)).WithErr(err),
code.Text(code.CronCreateError)).WithError(err),
)
return
}
@@ -1,13 +1,12 @@
package cron_handler
package cron
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/cron_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/cron"
"github.com/spf13/cast"
)
@@ -42,39 +41,40 @@ type detailResponse struct {
// @Param id path string true "hashId"
// @Success 200 {object} detailResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/:id [get]
// @Router /api/cron/{id} [get]
// @Security LoginToken
func (h *handler) Detail() core.HandlerFunc {
return func(ctx core.Context) {
req := new(detailRequest)
res := new(detailResponse)
if err := ctx.ShouldBindURI(req); err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
validation.Error(err)).WithErr(err),
validation.Error(err)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
searchOneData := new(cron_service.SearchOneData)
searchOneData := new(cron.SearchOneData)
searchOneData.Id = cast.ToInt32(ids[0])
info, err := h.cronService.Detail(ctx, searchOneData)
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.CronDetailError,
code.Text(code.CronDetailError)).WithErr(err),
code.Text(code.CronDetailError)).WithError(err),
)
return
}
@@ -1,12 +1,11 @@
package cron_handler
package cron
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/spf13/cast"
)
@@ -28,36 +27,37 @@ type executeResponse struct {
// @Param id path string true "hashId"
// @Success 200 {object} detailResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/:id [patch]
// @Router /api/cron/exec/{id} [patch]
// @Security LoginToken
func (h *handler) Execute() core.HandlerFunc {
return func(ctx core.Context) {
req := new(executeRequest)
res := new(executeResponse)
if err := ctx.ShouldBindURI(req); err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
validation.Error(err)).WithErr(err),
validation.Error(err)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
err = h.cronService.Execute(ctx, cast.ToInt32(ids[0]))
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.CronExecuteError,
code.Text(code.CronExecuteError)).WithErr(err),
code.Text(code.CronExecuteError)).WithError(err),
)
return
}
@@ -1,15 +1,14 @@
package cron_handler
package cron
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/cron_task_repo"
"github.com/xinliangnote/go-gin-api/internal/api/service/cron_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
"github.com/xinliangnote/go-gin-api/internal/repository/mysql/cron_task"
"github.com/xinliangnote/go-gin-api/internal/services/cron"
"github.com/xinliangnote/go-gin-api/pkg/timeutil"
"github.com/spf13/cast"
)
@@ -58,25 +57,26 @@ type listResponse struct {
// @Summary 任务列表
// @Description 任务列表
// @Tags API.cron
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param page query int false "第几页"
// @Param page_size query string false "每页显示条数"
// @Param page query int true "第几页" default(1)
// @Param page_size query int true "每页显示条数" default(10)
// @Param name query string false "任务名称"
// @Param protocol query int false "执行方式 1:shell 2:http"
// @Param is_used query int false "是否启用 1:是 -1:否"
// @Success 200 {object} listResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron [get]
// @Security LoginToken
func (h *handler) List() core.HandlerFunc {
return func(ctx core.Context) {
req := new(listRequest)
res := new(listResponse)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
validation.Error(err)).WithErr(err),
validation.Error(err)).WithError(err),
)
return
}
@@ -91,7 +91,7 @@ func (h *handler) List() core.HandlerFunc {
pageSize = 10
}
searchData := new(cron_service.SearchData)
searchData := new(cron.SearchData)
searchData.Page = req.Page
searchData.PageSize = req.PageSize
searchData.Name = req.Name
@@ -100,20 +100,20 @@ func (h *handler) List() core.HandlerFunc {
resListData, err := h.cronService.PageList(ctx, searchData)
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.CronListError,
code.Text(code.CronListError)).WithErr(err),
code.Text(code.CronListError)).WithError(err),
)
return
}
resCountData, err := h.cronService.PageListCount(ctx, searchData)
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.CronListError,
code.Text(code.CronListError)).WithErr(err),
code.Text(code.CronListError)).WithError(err),
)
return
}
@@ -126,10 +126,10 @@ func (h *handler) List() core.HandlerFunc {
for k, v := range resListData {
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsEncodeError,
code.Text(code.HashIdsEncodeError)).WithErr(err),
code.Text(code.HashIdsEncodeError)).WithError(err),
)
return
}
@@ -139,21 +139,21 @@ func (h *handler) List() core.HandlerFunc {
HashID: hashId,
Name: v.Name,
Protocol: cast.ToInt(v.Protocol),
ProtocolText: cron_task_repo.ProtocolText[v.Protocol],
ProtocolText: cron_task.ProtocolText[v.Protocol],
Spec: v.Spec,
Command: v.Command,
HttpMethod: cast.ToInt(v.HttpMethod),
HttpMethodText: cron_task_repo.HttpMethodText[v.HttpMethod],
HttpMethodText: cron_task.HttpMethodText[v.HttpMethod],
Timeout: cast.ToInt(v.Timeout),
RetryTimes: cast.ToInt(v.RetryTimes),
RetryInterval: cast.ToInt(v.RetryInterval),
NotifyStatus: cast.ToInt(v.NotifyStatus),
NotifyStatusText: cron_task_repo.NotifyStatusText[v.NotifyStatus],
NotifyStatusText: cron_task.NotifyStatusText[v.NotifyStatus],
IsUsed: cast.ToInt(v.IsUsed),
IsUsedText: cron_task_repo.IsUsedText[v.IsUsed],
CreatedAt: v.CreatedAt.Format(time_parse.CSTLayout),
IsUsedText: cron_task.IsUsedText[v.IsUsed],
CreatedAt: v.CreatedAt.Format(timeutil.CSTLayout),
CreatedUser: v.CreatedUser,
UpdatedAt: v.UpdatedAt.Format(time_parse.CSTLayout),
UpdatedAt: v.UpdatedAt.Format(timeutil.CSTLayout),
UpdatedUser: v.UpdatedUser,
}
@@ -1,13 +1,12 @@
package cron_handler
package cron
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/cron_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/cron"
)
type modifyRequest struct {
@@ -36,9 +35,9 @@ type modifyResponse struct {
// @Summary 编辑任务
// @Description 编辑任务
// @Tags API.cron
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "Hashid"
// @Param id formData string true "hashID"
// @Param name formData string true "任务名称"
// @Param spec formData string true "crontab 表达式"
// @Param command formData string true "执行命令"
@@ -56,32 +55,33 @@ type modifyResponse struct {
// @Success 200 {object} modifyResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/{id} [post]
// @Security LoginToken
func (h *handler) Modify() core.HandlerFunc {
return func(ctx core.Context) {
req := new(modifyRequest)
res := new(modifyResponse)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
validation.Error(err)).WithErr(err),
validation.Error(err)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
id := int32(ids[0])
modifyData := new(cron_service.ModifyCronTaskData)
modifyData := new(cron.ModifyCronTaskData)
modifyData.Name = req.Name
modifyData.Spec = req.Spec
modifyData.Command = req.Command
@@ -98,10 +98,10 @@ func (h *handler) Modify() core.HandlerFunc {
modifyData.IsUsed = req.IsUsed
if err := h.cronService.Modify(ctx, id, modifyData); err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.CronUpdateError,
code.Text(code.CronUpdateError)).WithErr(err),
code.Text(code.CronUpdateError)).WithError(err),
)
return
}
@@ -1,12 +1,11 @@
package cron_handler
package cron
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type updateUsedRequest struct {
@@ -22,32 +21,33 @@ type updateUsedResponse struct {
// @Summary 更新任务为启用/禁用
// @Description 更新任务为启用/禁用
// @Tags API.cron
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "Hashid"
// @Param id formData string true "hashID"
// @Param used formData int true "是否启用 1:是 -1:否"
// @Success 200 {object} updateUsedResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/used [patch]
// @Security LoginToken
func (h *handler) UpdateUsed() core.HandlerFunc {
return func(ctx core.Context) {
req := new(updateUsedRequest)
res := new(updateUsedResponse)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
validation.Error(err)).WithErr(err),
validation.Error(err)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -56,10 +56,10 @@ func (h *handler) UpdateUsed() core.HandlerFunc {
err = h.cronService.UpdateUsed(ctx, id, req.Used)
if err != nil {
ctx.AbortWithError(errno.NewError(
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminUpdateError,
code.Text(code.AdminUpdateError)).WithErr(err),
code.Text(code.AdminUpdateError)).WithError(err),
)
return
}
@@ -1,12 +1,12 @@
package cron_handler
package cron
import (
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/api/service/cron_service"
"github.com/xinliangnote/go-gin-api/internal/cron/cron_server"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
cronRepo "github.com/xinliangnote/go-gin-api/internal/repository/cron"
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
"github.com/xinliangnote/go-gin-api/internal/services/cron"
"github.com/xinliangnote/go-gin-api/pkg/hash"
"go.uber.org/zap"
@@ -39,28 +39,28 @@ type Handler interface {
// Detail 获取单条任务详情
// @Tags API.cron
// @Router /api/cron/:id [get]
// @Router /api/cron/{id} [get]
Detail() core.HandlerFunc
// Execute 手动执行任务
// @Tags API.cron
// @Router /api/cron/:id [patch]
// @Router /api/cron/exec/{id} [patch]
Execute() core.HandlerFunc
}
type handler struct {
logger *zap.Logger
cache cache.Repo
cache redis.Repo
hashids hash.Hash
cronService cron_service.Service
cronService cron.Service
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo, cron cron_server.Server) Handler {
func New(logger *zap.Logger, db mysql.Repo, cache redis.Repo, cronServer cronRepo.Server) Handler {
return &handler{
logger: logger,
cache: cache,
hashids: hash.New(configs.Get().HashIds.Secret, configs.Get().HashIds.Length),
cronService: cron_service.New(db, cache, cron),
cronService: cron.New(db, cache, cronServer),
}
}
+49
View File
@@ -0,0 +1,49 @@
package helper
import (
"crypto/md5"
"encoding/hex"
"net/http"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
type md5Request struct {
Str string `uri:"str" binding:"required"` // 需要加密的字符串
}
type md5Response struct {
Md5Str string `json:"md5_str"` // MD5后的字符串
}
// Md5 加密
// @Summary 加密
// @Description 加密
// @Tags Helper
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param str path string true "需要加密的字符串"
// @Success 200 {object} md5Response
// @Failure 400 {object} code.Failure
// @Router /helper/md5/{str} [get]
func (h *handler) Md5() core.HandlerFunc {
return func(ctx core.Context) {
req := new(md5Request)
res := new(md5Response)
if err := ctx.ShouldBindURI(req); err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithError(err),
)
return
}
m := md5.New()
m.Write([]byte(req.Str))
res.Md5Str = hex.EncodeToString(m.Sum(nil))
ctx.Payload(res)
}
}
+100
View File
@@ -0,0 +1,100 @@
package helper
import (
"fmt"
"net/http"
"net/url"
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errors"
"github.com/xinliangnote/go-gin-api/pkg/signature"
)
type signRequest struct {
Key string `form:"key" binding:"required"` // 调用方 KEY
Path string `form:"path" binding:"required"` // 请求路径 (不附带 querystring),例如:/api/login
Method string `form:"method" binding:"required"` // 请求方式,例如:POST
Params string `form:"params" binding:"required"` // 请求参数,例如:username=tom&password=123456
}
type signResponse struct {
Authorization string `json:"authorization"` // 签名信息-Authorization
AuthorizationDate string `json:"authorization_date"` // 签名信息-Authorization-Date
}
// Sign 签名
// @Summary 签名
// @Description 签名
// @Tags Helper
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param key formData string true "调用方 KEY"
// @Param path formData string true "请求路径 (不附带 querystring),例如:/api/login"
// @Param method formData string true "请求方式,例如:POST"
// @Param params formData string true "请求参数,例如:username=tom&password=123456"
// @Success 200 {object} signResponse
// @Failure 400 {object} code.Failure
// @Router /helper/sign [post]
func (h *handler) Sign() core.HandlerFunc {
return func(ctx core.Context) {
req := new(signRequest)
res := new(signResponse)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithError(err),
)
return
}
authorizedInfo, err := h.authorizedService.DetailByKey(ctx, req.Key)
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizationError,
code.Text(code.AuthorizationError)).WithError(err),
)
return
}
if authorizedInfo.IsUsed == -1 {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizationError,
code.Text(code.AuthorizationError)).WithError(errors.New(req.Key + " 已被禁止调用")),
)
return
}
fmt.Println(req.Params)
params, err := url.ParseQuery(req.Params)
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizationError,
"params 传递格式不正确"),
)
return
}
sign := signature.New(req.Key, authorizedInfo.Secret, configs.HeaderSignTokenTimeout)
authorized, date, err := sign.Generate(req.Path, req.Method, params)
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizationError,
"sign 生成失败"),
)
return
}
res.Authorization = authorized
res.AuthorizationDate = date
ctx.Payload(res)
}
}
+42
View File
@@ -0,0 +1,42 @@
package helper
import (
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
"github.com/xinliangnote/go-gin-api/internal/services/authorized"
"go.uber.org/zap"
)
var _ Handler = (*handler)(nil)
type Handler interface {
i()
// Md5 加密
// @Tags Helper
// @Router /helper/md5/{str} [get]
Md5() core.HandlerFunc
// Sign 签名
// @Tags Helper
// @Router /helper/sign [post]
Sign() core.HandlerFunc
}
type handler struct {
logger *zap.Logger
db mysql.Repo
authorizedService authorized.Service
}
func New(logger *zap.Logger, db mysql.Repo, cache redis.Repo) Handler {
return &handler{
logger: logger,
db: db,
authorizedService: authorized.New(db, cache),
}
}
func (h *handler) i() {}
@@ -1,12 +1,11 @@
package menu_handler
package menu
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/menu_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/menu"
"github.com/spf13/cast"
)
@@ -28,21 +27,22 @@ type createResponse struct {
// @Summary 创建/编辑菜单
// @Description 创建/编辑菜单
// @Tags API.menu
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body createRequest true "请求信息"
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /api/menu [post]
// @Security LoginToken
func (h *handler) Create() core.HandlerFunc {
return func(c core.Context) {
req := new(createRequest)
res := new(createResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
@@ -50,27 +50,27 @@ func (h *handler) Create() core.HandlerFunc {
if req.Id != "" { // 编辑功能
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
id := int32(ids[0])
updateData := new(menu_service.UpdateMenuData)
updateData := new(menu.UpdateMenuData)
updateData.Name = req.Name
updateData.Icon = req.Icon
updateData.Link = req.Link
err = h.menuService.Modify(c, id, updateData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuUpdateError,
code.Text(code.MenuUpdateError)).WithErr(err),
code.Text(code.MenuUpdateError)).WithError(err),
)
return
}
@@ -88,7 +88,7 @@ func (h *handler) Create() core.HandlerFunc {
level = 1
}
createData := new(menu_service.CreateMenuData)
createData := new(menu.CreateMenuData)
createData.Pid = pid
createData.Name = req.Name
createData.Icon = req.Icon
@@ -97,10 +97,10 @@ func (h *handler) Create() core.HandlerFunc {
id, err := h.menuService.Create(c, createData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuCreateError,
code.Text(code.MenuCreateError)).WithErr(err),
code.Text(code.MenuCreateError)).WithError(err),
)
return
}
@@ -1,12 +1,11 @@
package menu_handler
package menu
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/menu_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/menu"
)
type createActionRequest struct {
@@ -23,7 +22,7 @@ type createActionResponse struct {
// @Summary 创建功能权限
// @Description 创建功能权限
// @Tags API.menu
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "HashID"
// @Param method formData string true "请求方法"
@@ -31,54 +30,55 @@ type createActionResponse struct {
// @Success 200 {object} createActionResponse
// @Failure 400 {object} code.Failure
// @Router /api/menu_action [post]
// @Security LoginToken
func (h *handler) CreateAction() core.HandlerFunc {
return func(c core.Context) {
req := new(createActionRequest)
res := new(createActionResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
id := int32(ids[0])
searchOneData := new(menu_service.SearchOneData)
searchOneData := new(menu.SearchOneData)
searchOneData.Id = id
menuInfo, err := h.menuService.Detail(c, searchOneData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuDetailError,
code.Text(code.MenuDetailError)).WithErr(err),
code.Text(code.MenuDetailError)).WithError(err),
)
return
}
createActionData := new(menu_service.CreateMenuActionData)
createActionData := new(menu.CreateMenuActionData)
createActionData.MenuId = menuInfo.Id
createActionData.Method = req.Method
createActionData.API = req.API
createId, err := h.menuService.CreateAction(c, createActionData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuCreateActionError,
code.Text(code.MenuCreateActionError)).WithErr(err),
code.Text(code.MenuCreateActionError)).WithError(err),
)
return
}
@@ -1,11 +1,10 @@
package menu_handler
package menu
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type deleteRequest struct {
@@ -26,25 +25,26 @@ type deleteResponse struct {
// @Success 200 {object} deleteResponse
// @Failure 400 {object} code.Failure
// @Router /api/menu/{id} [delete]
// @Security LoginToken
func (h *handler) Delete() core.HandlerFunc {
return func(c core.Context) {
req := new(deleteRequest)
res := new(deleteResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -53,10 +53,10 @@ func (h *handler) Delete() core.HandlerFunc {
err = h.menuService.Delete(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuDeleteError,
code.Text(code.MenuDeleteError)).WithErr(err),
code.Text(code.MenuDeleteError)).WithError(err),
)
return
}
@@ -1,11 +1,10 @@
package menu_handler
package menu
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type deleteActionRequest struct {
@@ -26,25 +25,26 @@ type deleteActionResponse struct {
// @Success 200 {object} deleteActionResponse
// @Failure 400 {object} code.Failure
// @Router /api/menu_action/{id} [delete]
// @Security LoginToken
func (h *handler) DeleteAction() core.HandlerFunc {
return func(c core.Context) {
req := new(deleteActionRequest)
res := new(deleteActionResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -53,10 +53,10 @@ func (h *handler) DeleteAction() core.HandlerFunc {
err = h.menuService.DeleteAction(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuDeleteActionError,
code.Text(code.MenuDeleteActionError)).WithErr(err),
code.Text(code.MenuDeleteActionError)).WithError(err),
)
return
}
@@ -1,12 +1,11 @@
package menu_handler
package menu
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/menu_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/menu"
)
type detailRequest struct {
@@ -25,46 +24,47 @@ type detailResponse struct {
// @Summary 菜单详情
// @Description 菜单详情
// @Tags API.menu
// @Accept json
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id path string true "hashId"
// @Success 200 {object} detailResponse
// @Failure 400 {object} code.Failure
// @Router /api/menu/{id} [get]
// @Security LoginToken
func (h *handler) Detail() core.HandlerFunc {
return func(c core.Context) {
req := new(detailRequest)
res := new(detailResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
id := int32(ids[0])
searchOneData := new(menu_service.SearchOneData)
searchOneData := new(menu.SearchOneData)
searchOneData.Id = id
info, err := h.menuService.Detail(c, searchOneData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuDetailError,
code.Text(code.MenuDetailError)).WithErr(err),
code.Text(code.MenuDetailError)).WithError(err),
)
return
}
@@ -1,12 +1,11 @@
package menu_handler
package menu
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/menu_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/menu"
"github.com/spf13/cast"
)
@@ -30,20 +29,21 @@ type listResponse struct {
// @Summary 菜单列表
// @Description 菜单列表
// @Tags API.menu
// @Accept json
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Success 200 {object} listResponse
// @Failure 400 {object} code.Failure
// @Router /api/menu [get]
// @Security LoginToken
func (h *handler) List() core.HandlerFunc {
return func(c core.Context) {
res := new(listResponse)
resListData, err := h.menuService.List(c, new(menu_service.SearchData))
resListData, err := h.menuService.List(c, new(menu.SearchData))
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuListError,
code.Text(code.MenuListError)).WithErr(err),
code.Text(code.MenuListError)).WithError(err),
)
return
}
@@ -53,10 +53,10 @@ func (h *handler) List() core.HandlerFunc {
for k, v := range resListData {
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsEncodeError,
code.Text(code.HashIdsEncodeError)).WithErr(err),
code.Text(code.HashIdsEncodeError)).WithError(err),
)
return
}
@@ -1,12 +1,11 @@
package menu_handler
package menu
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/service/menu_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/internal/services/menu"
"github.com/spf13/cast"
)
@@ -31,61 +30,62 @@ type listActionResponse struct {
// @Summary 功能权限列表
// @Description 功能权限列表
// @Tags API.menu
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id query string true "hashID"
// @Success 200 {object} listActionResponse
// @Failure 400 {object} code.Failure
// @Router /api/menu_action [get]
// @Security LoginToken
func (h *handler) ListAction() core.HandlerFunc {
return func(c core.Context) {
req := new(listActionRequest)
res := new(listActionResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
id := int32(ids[0])
searchOneData := new(menu_service.SearchOneData)
searchOneData := new(menu.SearchOneData)
searchOneData.Id = id
menuInfo, err := h.menuService.Detail(c, searchOneData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuDetailError,
code.Text(code.MenuDetailError)).WithErr(err),
code.Text(code.MenuDetailError)).WithError(err),
)
return
}
res.MenuName = menuInfo.Name
searchListData := new(menu_service.SearchListActionData)
searchListData := new(menu.SearchListActionData)
searchListData.MenuId = menuInfo.Id
resListData, err := h.menuService.ListAction(c, searchListData)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.AuthorizedListAPIError,
code.Text(code.AuthorizedListAPIError)).WithErr(err),
code.Text(code.AuthorizedListAPIError)).WithError(err),
)
return
}
@@ -95,10 +95,10 @@ func (h *handler) ListAction() core.HandlerFunc {
for k, v := range resListData {
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsEncodeError,
code.Text(code.HashIdsEncodeError)).WithErr(err),
code.Text(code.HashIdsEncodeError)).WithError(err),
)
return
}
@@ -1,11 +1,10 @@
package menu_handler
package menu
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type updateSortRequest struct {
@@ -21,32 +20,33 @@ type updateSortResponse struct {
// @Summary 更新菜单排序
// @Description 更新菜单排序
// @Tags API.menu
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "Hashid"
// @Param id formData string true "hashId"
// @Param sort formData int true "排序"
// @Success 200 {object} updateSortResponse
// @Failure 400 {object} code.Failure
// @Router /api/menu/sort [patch]
// @Security LoginToken
func (h *handler) UpdateSort() core.HandlerFunc {
return func(c core.Context) {
req := new(updateSortRequest)
res := new(updateSortResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -55,10 +55,10 @@ func (h *handler) UpdateSort() core.HandlerFunc {
err = h.menuService.UpdateSort(c, id, req.Sort)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuUpdateError,
code.Text(code.MenuUpdateError)).WithErr(err),
code.Text(code.MenuUpdateError)).WithError(err),
)
return
}
@@ -1,11 +1,10 @@
package menu_handler
package menu
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/pkg/code"
"github.com/xinliangnote/go-gin-api/internal/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type updateUsedRequest struct {
@@ -21,32 +20,33 @@ type updateUsedResponse struct {
// @Summary 更新菜单为启用/禁用
// @Description 更新菜单为启用/禁用
// @Tags API.menu
// @Accept multipart/form-data
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param id formData string true "Hashid"
// @Param id formData string true "hashId"
// @Param used formData int true "是否启用 1:是 -1:否"
// @Success 200 {object} updateUsedResponse
// @Failure 400 {object} code.Failure
// @Router /api/menu/used [patch]
// @Security LoginToken
func (h *handler) UpdateUsed() core.HandlerFunc {
return func(c core.Context) {
req := new(updateUsedRequest)
res := new(updateUsedResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
code.Text(code.ParamBindError)).WithError(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
code.Text(code.HashIdsDecodeError)).WithError(err),
)
return
}
@@ -55,10 +55,10 @@ func (h *handler) UpdateUsed() core.HandlerFunc {
err = h.menuService.UpdateUsed(c, id, req.Used)
if err != nil {
c.AbortWithError(errno.NewError(
c.AbortWithError(core.Error(
http.StatusBadRequest,
code.MenuUpdateError,
code.Text(code.MenuUpdateError)).WithErr(err),
code.Text(code.MenuUpdateError)).WithError(err),
)
return
}
@@ -1,11 +1,11 @@
package menu_handler
package menu
import (
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/api/service/menu_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"github.com/xinliangnote/go-gin-api/internal/repository/mysql"
"github.com/xinliangnote/go-gin-api/internal/repository/redis"
"github.com/xinliangnote/go-gin-api/internal/services/menu"
"github.com/xinliangnote/go-gin-api/pkg/hash"
"go.uber.org/zap"
@@ -64,17 +64,17 @@ type Handler interface {
type handler struct {
logger *zap.Logger
cache cache.Repo
cache redis.Repo
hashids hash.Hash
menuService menu_service.Service
menuService menu.Service
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
func New(logger *zap.Logger, db mysql.Repo, cache redis.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
hashids: hash.New(configs.Get().HashIds.Secret, configs.Get().HashIds.Length),
menuService: menu_service.New(db, cache),
menuService: menu.New(db, cache),
}
}

Some files were not shown because too many files have changed in this diff Show More