diff --git a/docs/guide-zh-CN/images/sys-db-by.png b/docs/guide-zh-CN/images/sys-db-by.png new file mode 100644 index 0000000..4dd6c3e Binary files /dev/null and b/docs/guide-zh-CN/images/sys-db-by.png differ diff --git a/docs/guide-zh-CN/images/sys-db-by2.png b/docs/guide-zh-CN/images/sys-db-by2.png new file mode 100644 index 0000000..bf25dfa Binary files /dev/null and b/docs/guide-zh-CN/images/sys-db-by2.png differ diff --git a/docs/guide-zh-CN/images/sys-library-dict.png b/docs/guide-zh-CN/images/sys-library-dict.png new file mode 100644 index 0000000..421973f Binary files /dev/null and b/docs/guide-zh-CN/images/sys-library-dict.png differ diff --git a/docs/guide-zh-CN/images/sys-middleware-com-response.png b/docs/guide-zh-CN/images/sys-middleware-com-response.png new file mode 100644 index 0000000..26d46a5 Binary files /dev/null and b/docs/guide-zh-CN/images/sys-middleware-com-response.png differ diff --git a/docs/guide-zh-CN/images/sys-middleware-error-log.png b/docs/guide-zh-CN/images/sys-middleware-error-log.png new file mode 100644 index 0000000..224dfb5 Binary files /dev/null and b/docs/guide-zh-CN/images/sys-middleware-error-log.png differ diff --git a/docs/guide-zh-CN/start-deploy.md b/docs/guide-zh-CN/start-deploy.md new file mode 100644 index 0000000..decee16 --- /dev/null +++ b/docs/guide-zh-CN/start-deploy.md @@ -0,0 +1,108 @@ +## 生产部署 + +目录 + +- 编译配置 +- 编译 +- 修改生产配置文件 +- 启动服务 +- Nginx配置 + +### 编译配置 + +- 配置文件:server/hack/config.yaml,以下是默认配置 +```yaml +gfcli: + build: + name: "hotgo" # 编译后的可执行文件名称 + # arch: "all" #不填默认当前系统架构,可选:386,amd64,arm,all + # system: "all" #不填默认当前系统平台,可选:linux,darwin,windows,all + mod: "none" + cgo: 0 + packSrc: "resource" # 将resource目录打包进可执行文件,静态资源无需单独部署 + packDst: "internal/packed/packed.go" # 打包后生成的Go文件路径,一般使用相对路径指定到本项目目录中 + version: "" + output: "./temp/hotgo" # 可执行文件生成路径 + extra: "" +``` + + +### 编译 + +- 以下方式任选其一即可 + +1、 make一键编译 (确认已安装`make环境`) +```shell +cd server && make build +``` + +2、 按步骤手动编译 +```shell +cd server # 切换到服务端目录下 +rm -rf ./resource/public/admin/ # 删除之前的web资源 +mkdir ./resource/public/admin/ # 重新创建web资源存放目录,除首次编译后续可以跳过执行此步骤 +cd ../web && pnpm run build # 切换到web项目下,编译web项目 +\cp -rf ./dist/* ../server/resource/public/admin/ # 将编译好的web资源复制到server对应的资源存放路径下 +cd ../server # 切换回服务端目录下 +echo "y" | gf build # 编译hotgo服务端 + +# 不出意外你已经编译好了hotgo可执行文件! +``` + +3、分端编译 (多人开发时推荐) +```shell +# 编译服务端 +cd server # 切换到服务端目录下 +rm -rf ./resource/public/admin/ # 删除之前的web资源,如果开发环境没有这个目录可以忽略此步骤 +echo "y" | gf build # 编译hotgo服务端 + +# 编译web端 +cd web +pnpm run build 或 npm run build + +# web端编译完成后,将web/dist/*中的文件上传到`server`端线上运行目录:/resource/public/admin即可 +# 至此,web端和server端都可以独立覆盖更新 +``` + + +### 修改生产配置文件 +- 配置文件:server/manifest/config/config.yaml +> 如关闭debug、mode设为生产环境、修改数据库地址、缓存驱动、队列驱动、日志路径等 + + + +### 启动服务 +> 这里可以接使用gf官方推荐的启动方式,请参考:https://goframe.org/pages/viewpage.action?pageId=1114403 + + +### Nginx配置 +``` + # websocket + location = /socket { + proxy_pass http://127.0.0.1:8000/socket; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + proxy_set_header X-NginX-Proxy true; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_connect_timeout 600s; + proxy_read_timeout 600; + proxy_send_timeout 600s; + } + + # http + location ^~ / { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://127.0.0.1:8000/; + proxy_redirect off; + proxy_buffering off; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection upgrade; + } +``` diff --git a/docs/guide-zh-CN/start-environment.md b/docs/guide-zh-CN/start-environment.md new file mode 100644 index 0000000..7ceabb1 --- /dev/null +++ b/docs/guide-zh-CN/start-environment.md @@ -0,0 +1,31 @@ +## 环境搭建 + +目录 + +- 前端环境 +- 后端环境 +- 使用说明 + +### 前端环境 + +1. 前往https://nodejs.org/zh-cn/下载当前版本node +2. 命令行运行 `node -v` 若控制台输出版本号则node安装成功 +3. node 版本需大于等于 `16.0` +4. 安装pnpm:`npm install -g pnpm` +5. 命令行运行 `pnpm -v` 若控制台输出版本号则前端环境搭建成功 + +### 后端环境 +1. 下载golang安装 版本号需>=1.23 +2. 国际: https://golang.org/dl/ +3. 国内: https://golang.google.cn/dl/ +4. 命令行运行 go 若控制台输出各类提示命令 则安装成功 输入 `go version` 确认版本大于1.23 +5. 开发工具推荐 [Goland](https://www.jetbrains.com/go/) + +### 使用说明 + +> 需要本地具有 git node golang 环境 + +- node版本 >= 20.0.0 +- golang版本 >= 1.23 +- mysql版本 >= 5.7,引擎需要是 innoDB 或 postgresql版本 >=14 +- IDE推荐:Goland diff --git a/docs/guide-zh-CN/start-installation.md b/docs/guide-zh-CN/start-installation.md new file mode 100644 index 0000000..e527318 --- /dev/null +++ b/docs/guide-zh-CN/start-installation.md @@ -0,0 +1,107 @@ +## 系统安装 + +目录 + +- 环境要求 +- 安装 + +### 环境要求 + +- node版本 >= v20.0.0 +- golang版本 >= v1.23 +- goframe版本 >=v2.9.4 +- mysql版本 >=5.7 或 postgresql版本 >=14 + +> 必须先看[环境搭建文档](start-environment.md),如果安装遇到问题务必先查看[常见问题文档](start-issue.md) + +### 安装 + + +一、克隆项目 + +``` +git clone https://github.com/bufanyun/hotgo.git && cd hotgo +``` + +二、配置你的站点信息 + +1、服务端: +- 项目数据库文件 `storage/data/hotgo.sql` 创建数据库并导入 +- 将配置文件 `manifest/config/config.example.yaml` 复制后改为`manifest/config/config.yaml` +- 将`manifest/config/config.yaml`中的`database.default.link`数据库配置改为你自己的: +```yaml +# Database. 配置参考:https://goframe.org/pages/viewpage.action?pageId=1114245 +database: + logger: + path: "logs/database" # 日志文件路径。默认为空,表示关闭,仅输出到终端 + <<: *defaultLogger + stdout: true + default: +# link: "mysql:账号:密码@tcp(127.0.0.1:3306)/数据库名?loc=Local&parseTime=true&charset=utf8mb4" + link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true&charset=utf8mb4" + debug: true + Prefix: "hg_" +``` + +- 将`hack/config.yaml`中的`gfcli.gen.dao[0].link`数据库配置改为你自己的: +```yaml +gfcli: + gen: + dao: + - link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true&charset=utf8mb4" + group: "default" # 分组 使用hotgo代码生成功能时必须填 + # tables: "" # 指定当前数据库中需要执行代码生成的数据表。如果为空,表示数据库的所有表都会生成。 + tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。 + removePrefix: "hg_" + descriptionTag: true + noModelComment: true + jsonCase: "CamelLower" + gJsonSupport: true + clear: false +``` + +2、web前端: +- 配置服务端地址,包含在以下文件中: +* /hotgo/web/.env.development +* /hotgo/web/.env.production +* /hotgo/web/.env + + +三、 启动服务 + +1、服务端: +```shell + cd server + + # 设置国内代理,如果已经设置好了代理可以跳过 + go env -w GOPROXY=https://goproxy.io,direct + + # 更新包 + go mod tidy + + # 查看命令行方法 + go run main.go help + + # 启动所有服务 + go run main.go # 热编译启动: gf run main.go +``` + +2、web前端: +```shell + cd web + # 首先确定你以安装node16.0以上版本并安装了包[npm、pnpm],否则可能会出现一些未知报错 + + # 安装依赖 + pnpm install + + # 启动web项目 + pnpm run dev + + # 如果顺利,至此到浏览器打开:http://你的IP:8001/admin + # 登录账号:admin, 密码:123456 +``` + + + + + diff --git a/docs/guide-zh-CN/start-issue.md b/docs/guide-zh-CN/start-issue.md new file mode 100644 index 0000000..08017c0 --- /dev/null +++ b/docs/guide-zh-CN/start-issue.md @@ -0,0 +1,93 @@ +## 常见问题 + +目录 + +- 一、后台相关 +- 二、数据库相关 +- 三、环境相关 + + +### 一、后台相关 + +#### 1、连接超时,请刷新重试。如仍未解决请检查websocket连接是否正确! + +线上或非本地运行时,请到 系统设置 -> 配置管理 -> 基本设置 -> 找到网站域名和websocket地址,改成你自己实际的地址,保存刷新页面即可 + +#### 2、web页面菜单切换后页面出现白屏 + +请参考:https://github.com/jekip/naive-ui-admin/issues/183 + + +### 二、数据库相关 + +#### 1、安装数据库出现 json 报错不支持 + +请安装 mysql5.7 及以上版本的数据库。如果你使用的是mariadb请确认版本号,mariadb从 10.2 版本开始支持 json 数据类型。 + + + +### 三、环境相关 + +#### 1、not found in resource manager or following system searching paths + +> 报错信息:panic: possible config files "config" or "config.toml/yaml/yml/json/ini/xml/properties" not found in resource manager or following system searching paths: + +系统没有找到配置文件,将配置文件 `manifest/config/config.yaml.bak` 复制后改为`manifest/config/config.yaml` + + +#### 2、net.DialTimeout failed with network + +> 报错信息:connect to 127.0.0.1:8099 error: net.DialTimeout failed with network "tcp", address "127.0.0.1:8099", timeout "10s": dial tcp + +- http服务没有启动或正在启动 +- 通过一键启动所有服务运行时属正常情况,多服务启动时存在先后顺序问题,`tcpClient`比`tcpServer`先启动完成导致的,等`tcpServer`启动完成后会自动重连 + +详细请参考 - [系统安装](start-installation.md) + + +#### 3、cannot find "hack/config.yaml" in following paths: +> 报错信息:get cli configuration file:hack/config.yaml, err:cannot find "hack/config.yaml" in following paths: + +系统运行目录下配置hack/config.yaml文件。如果是生产环境运行,并且不需要开发工具相关功能,可以将`manifest/config/config.yaml`配置文件中的`system.mode`值改为`product`,这样启动时不会加载开发工具相关功能 + +#### 4、非超管角色提示:你没有访问权限! +![1.4.0.png](./images/issue/1.4.0.png) + +此问题因当前角色访问的页面包含未分配权限的接口所致,在多角色场景中较为常见,解决步骤如下: + +1. 定位缺失权限的接口 +- 用超管账号进入系统应用 -> 日志管理 -> 全局日志,搜索状态码为`62 无访问权限`的记录 +- 示例:若请求接口为`/admin/hgexample/treeTable/list`,需处理的权限路径为`/hgexample/treeTable/list`(去除`/admin`前缀) + +![1.4.1.png](./images/issue/1.4.1.png) + +假如查到请求接口是:`/admin/hgexample/treeTable/list`,那需要分配的菜单权限就是:`/hgexample/treeTable/list`,要把`/admin`去掉 + +2. 配置菜单权限 +- 进入权限管理 -> 菜单权限: +- 若目标菜单不存在,先新增菜单 +- 若菜单已存在但未配置接口权限,就把步骤1中的权限路径添加到【分配权限】中(已配置则跳过) + +![1.4.2.png](./images/issue/1.4.2.png) + +3. 分配权限给角色 +- 进入权限管理 -> 角色权限,找到对应角色并点击【菜单权限】 +- 勾选步骤2中配置的菜单权限,保存即可 + +![1.4.3.png](./images/issue/1.4.3.png) + +### 四、前端相关 + +#### 1、Error: connect ECONNREFUSED ::1:8000 + +```text +11:44:52 [vite] http proxy error at /member/info: +Error: connect ECONNREFUSED ::1:8000 + at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1246:16) +``` + +- 服务端没有启动 +- `.\wen\.env.development`中的`VITE_PROXY`配置的服务器地址或端口与实际不一致 + + + diff --git a/docs/guide-zh-CN/start-questions.md b/docs/guide-zh-CN/start-questions.md new file mode 100644 index 0000000..39374f2 --- /dev/null +++ b/docs/guide-zh-CN/start-questions.md @@ -0,0 +1,21 @@ +## 如何提问 + +#### 说明环境情况 + +- 平台: windows/linux +- 软件与版本:golang 1.19, Mysql 5.7 ... +- 系统版本:hotgo 2.6.2 + +#### 你做了什么? + +- 我按文档(附链接)上写了一个控制器xxx,代码如下:xxxx +- 然后我使用xxx访问 +- 这其中我还做了啥 +- ... + +#### 出现什么错误? + +- 当我试图xxx的时候,xxx报了如下错误:(截图) +- 我确认过我的目录权限是正确的,xxx是正确的(必要时带上截图) + +以上是举例提问时所应该描述的情况,当别人看到详细的情况时,也便于快速定位问题所在。 \ No newline at end of file diff --git a/docs/guide-zh-CN/start-update-log.md b/docs/guide-zh-CN/start-update-log.md new file mode 100644 index 0000000..6711f6c --- /dev/null +++ b/docs/guide-zh-CN/start-update-log.md @@ -0,0 +1,333 @@ +## 更新历史 + +升级说明: + +> 创建一个Git版本库,并创建二个分支比如A、B,A分支默认为你的二开分支、B分支为你的版本库分支。 +> 等需要升级的时候,把版本库分支(B)升级为最新的版本,然后切换到A分支,把B分支合并过来,解决掉合并冲突即可。 + +注意: + +> 各个小版本升级例如 2.1.x 升级到 2.2.x 以上不能完美升级最好重新安装 + +> 如果升级(覆盖)代码后打开会出现 sql 报错, 请检查更新的数据库格式或自行调整 + + +### v2.18.9 +updated 2026.5.9 + +- 新增:新增 `AGENTS.md` 项目开发规范,统一前后端开发约定,作为 AI 辅助开发的唯一事实来源 +- 优化:naive-ui版本升级到2.44.1 +- 优化:gf版本升级到v2.10.0 + + +### v2.18.6 +updated 2025.10.25 + +- 新增:国际化(i18n)支持,内置简体中文、繁体中文、英文三种语言包 +- 新增:附件管理支持外链图片转存至系统存储驱动 +- 优化:全局微信公众号实例初始化逻辑,`AccessToken` 获取方式调整为稳定版接口 +- 优化:菜单权限搜索功能,支持按菜单名称或路由地址进行检索 +- 优化:角色权限管理中的菜单权限分配交互体验 +- 优化:naive-ui版本升级到2.43.1 +- 优化:gf版本升级到v2.9.4 +- 修复:删除角色导致关联用户无法登录的问题,新增角色删除前置校验(检查是否存在关联用户) + + +### v2.17.8 +updated 2025.7.13 + +- 优化:表格排序处理器兼容关联表别名 +- 优化:优化动态统计数字在0值时显示问题 +- 优化:优化首页快捷菜单点击事件范围 +- 优化:优化短信、邮件验证码相关验证类数据排序 +- 优化:优化Nginx配置,支持流式请求和兼容部分版本无法匹配到websocket规则问题 +- 优化:naive-ui版本升级到2.42.0 +- 优化:vue3-json-viewer版本升级到2.4.1 +- 修复:修复可选用户选项`Fields`生成错误问题 + + +### v2.16.10 +updated 2025.3.22 + +- 增加:增加组合下拉用户筛选组件 +- 优化:文件上传类型限制改为统一由后台配置控制 +- 优化:websocket重连时间调整为10秒,初始化数据库中的网站地址调整为`127.0.0.1` +- 优化:优化访问日志字段展示方式 +- 优化:系统公告发送编辑模态框调整为抽屉 +- 优化:gf版本升级到v2.9.0 +- 优化:naive-ui版本升级到2.41.0 +- 修复:修复vue路由`Redirect`命名重复问题 +- 修复:优化代码生成在插件中`使用生成字典选项`时model包名重复问题 + + +### v2.15.11 +updated 2024.11.27 + +- 增加:增加配置管理子页面选项参数记忆 +- 修复:修复定时任务中日志配置的读取并发读问题 +- 优化:gf版本升级到v2.8.2 +- 优化:优化数据卡片展示 + + +### v2.15.7 +updated 2024.7.21 + +- 增加:访问日志、服务日志增加关键词搜索 +- 增加:web端增加字典状态管理,重构字典选项使用方式,大幅减少冗余代码 +- 修复:修复生成代码选项式树表已知的一些小bug +- 优化:gf版本升级到v2.7.2 +- 优化:naive-ui版本升级到2.39.0 +- 优化:访问日志不再记录过大的请求头参数,减少日志大小 + + +### v2.15.1 +updated 2024.4.22 + +- 增加:生成代码增加树表生成、字段排序、字段重置、操作人维护,调整关联表生成方式 +- 增加:角色菜单权限增加一键导入支持 +- 增加:访问日志增加忽略请求方式 +- 增加:插件生成增加`consts`目录维护 +- 增加:IP归属地定位增加默认重试,增加新的缓存机制 +- 增加:登录日志增加UA信息、IP归属信息,解藕访问日志 +- 增加:消息队列`rocketmq`驱动更新版本问题,增加延迟队列,支持自动创建主题 +- 增加:部门增加类型支持,通过部门类型实现多租户业务支持 +- 增加:增加多租户业务开发演示 +- 修复:修复部门列表搜索算法在部分情况下无效问题 +- 修复:修复短信、邮件IP发送数量限制 +- 修复:修复分布式锁内存泄漏问题 +- 优化:gf版本升级到v2.7.0 +- 优化:naive-ui版本升级到2.38.1 +- 优化:优化`cmd`服务退出流程 +- 优化:优化生成代码格式化和移除未使用的包 +- 优化:服务端配置文件参数`hotgo`改为`system` +- 优化:web端表格/表单增加自适应宽度计算 +- 优化:日期选择组件不再使用默认值 +- 优化:优化菜单添加/编辑表单,使其操作更加简单方便 + + +### v2.13.1 +updated 2024.3.7 + +- 增加:增加内置数据字典类型:`枚举字典`和`自定义方法字典`,支持代码生成时关联选项使用 +- 增加:增加大文件上传,支持分片上传、断点续传,存储驱动已适配`本地存储` +- 增加:插件模块增加停止服务回调接口,调整静态资源默认存放位置,创建插件选项增加可选扩展功能 +- 增加:功能案例插件增加`30+`常用组件示例,增加`websocket`消息收发测试 +- 增加:文档增`加功能扩展库`、`websocket服务器`、`websocket客户端`使用说明,当前版本文档已完善 +- 修复:修复省市区无法添加地区问题 +- 优化:gf版本升级到v2.6.4 +- 优化:优化缓存组件依赖关系 +- 优化:调整部分前端表格自适应宽度 +- 优化:HTTP错误码接管统一改为由响应中间件处理 + +### v2.12.1 +updated 2023.12.29 + +- 修复:修复访问日志权限过滤 +- 优化:gf版本升级到v2.6.1 +- 优化:naive-ui版本升级到2.36.0,vue版本升级到3.4.0,vite版本升级到4.2.7 +- 优化:优化curd代码生成,编辑表单增加自适应,详情改为`抽屉`,修复菜单权限关系树,简化`State` +- 优化:优化字典编辑和查询 +- 优化:优化角色列表数据加载缓慢问题 + +### v2.11.5 +updated 2023.11.25 + +- 增加`minio`上传驱动支持 +- 增加定时任务调度日志,增加同方法多任务支持 +- 增加gf运行模式控制,生产环境时隐藏开发相关菜单 +- 增加树形表格新增/修改自动维护上下级关系通用处理 +- 增加树形表格使用例子 +- 优化:gf版本升级到v2.5.7 +- 优化`websocket`默认路径配置 +- 优化预处理中间件错误码跟随 +- 优化插件静态目录为可选项 +- 修复升级gf版本后服务日志记录内容为空问题 +- 修复角色权限选择数据重复问题 +- 修复服务日志无日志内容问题 +- 修复用户批量删除可以删除超管问题 +- 修复代码生成时偶尔找不到主键索引问题 +- 修复树形选项组件在`BasicForm`无法使用问题 +- 修复表格批量删除重复传参问题 +- 修复文件缓存`GetOrSet`和`GetOrSetFunc`缓存过期不刷新问题 + +### v2.9.8 +updated 2023.10.21 + +- 优化:gf版本升级到v2.5.5 +- 优化:优化代码生成表单滑动 +- 优化:优化字典列表编辑生效时机 +- 修复:修复日期组件默认值无效问题 +### v2.9.3 +updated 2023.10.08 + +- 优化:gf版本升级到v2.5.4 +- 优化:优化上传文件资源复用策略 +- 修复:修复登录角色的部门状态检查 +- 修复:修复配置参数`exceptLogin`命名 + +### v2.8.9 +updated 2023.09.06 + +- 优化:gf版本升级到v2.5.2 +- 优化:优化代码生成,自定义模板时自动过滤前缀,菜单权限生成预检查 +- 优化:服务日志内容长度超出最大限制截取 +- 修复:修复tcp服务器定时任务执行异常 +- 修复:修复文件选择器错误传参导致的显示异常问题 + +### v2.8.4 +updated 2023.07.20 + +- 增加:增加输入预处理中间件 +- 增加:增加文件选择器 +- 增加:增加在线服务监控,服务许可证管理 +- 增加:TCP服务器增加RPC路由消息注册、路由分发、拦截器注册,更方便的进行应用开发 +- 优化:gf版本升级到v2.5.0 +- 优化:优化CURD代码生成,简化控制器代码逻辑,升级列表数据查询方式 +- 修复:修复角色菜单子权限取消导致父级权限失效问题 +- 修复:修复上传驱动路径错误 +- 修复:修复CURD代码生成时间类型字段默认值获取异常 + +### v2.7.6 +updated 2023.06.19 + +- 优化:gf版本升级到v2.4.3 +- 修复:部门管理查询空指针问题 +- 优化:附件md5生成方式调整(与更新前已上传的文件md5不兼容,如果业务有影响请注意调整) + +### v2.7.3 +updated 2023.05.14 + +- 增加:增加注册、手机号登录、二维码邀请注册功能 +- 优化:优化管理员业务模块验证唯一属性接口,将登录相关功能拆分到管理员基础模块中 +- 移除:移除web端mock插件 + +### v2.6.10 +updated 2023.05.12 + +- 增加:增加jwt+缓存驱动实现的令牌认证,支持自动续约、可控过期失效策略 +- 移除:移除旧jwt功能库 +- 移除:移除`decimal`、`mahonia` package + +### v2.6.7 +updated 2023.05.10 + +- 增加:增加支付网关:集成支付宝、微信支付、QQ支付,可通过后台直接配置参数 +- 增加:增加资金管理模块,包含在线充值、申请提现、资金变动明细功能 +- 增加:增加redis延迟队列 +- 增加:tcp服务增加rpc协议通讯支持 +- 增加:通过微信访问后台自动获取openid,后续微信相关业务使用 +- 优化:gf版本升级到v2.4.1 +- 优化:优化CURD代码生成单表列表 +- 优化:优化菜单权限路由,解决偶尔修改权限不能实时生效的情况 +- 优化:优化后台导出功能搜索参数无效问题 +- 优化:将定时任务拆分成可独立部署的程序,通过tcp长连接方式与后台交互 +- 修复:修复相同文件多次上传页面无响应问题 +- 修复:修复新用户不更新活跃时间问题 +- 修复:修复本地缓存当缓存不存在时的异常错误问题 +- 修复:修复访问日志偶尔出现无法记录问题 + +### v2.5.3 +updated 2023.04.10 + +- 优化:优化IP地理位置定位,增加地理位置缓存,避免相同IP并发操作 +- 优化:优化日志管理中相关列表字段过多在小屏设备列表不显示滚动条情况 +- 增加:增加短信驱动:腾讯云短信,可通过后台一键切换 +- 修复:修复角色权限选择自定义部门时,部门选项无法显示问题 + +### v2.4.9 +updated 2023.04.05 + +- 优化:优化全局日志数据加载和分页加载,大分页增加分批次加载 +- 优化:优化TCP服务认证,超出多端登录上限时直接踢掉所有在线让其重连 +- 增加:增加上传驱动:腾讯云cos、阿里云oss、七牛云对象存储 +- 优化:优化代码生成文档,数据库文档增加多数据库生成配置 +- 修复:修复系统监控在苹果m1芯片空指针以及显示问题 + +### v2.4.4 +updated 2023.03.16 + +- 优化:优化代码生成多库生成时的菜单sql默认指向默认数据库分组 +- 优化:优化TCP服务认证机制 + +### v2.4.2 +updated 2023.03.11 + +- 修复:修复字典管理列表无法添加/编辑问题 +- 优化:优化代码生成文档 +- 优化:优化部门树形选项排序问题 +- 优化:优化基础设置中的LOGO图片上传组件 +- 优化:优化黑名单IP过滤策略 +- 增加:增加基于gtcp实现的C/S服务器,为后续多服务通讯建立基础库 +- 优化:gf版本升级到v2.3.3 + +### v2.3.5 +updated 2023.02.26 + +- 优化: 调整消息队列消费初始化方式,支持在插件模块下注册消费者 +- 修复:后台用户添加模态框无法正常显示问题 +- 优化:创建新插件生成增加web页面的生成 +- 增加:增加生产部署、开发规范、生成代码、表单组件等相关文档 +- 修复:修复后台已知的一些小bug + +### v2.2.10 +updated 2023.02.23 + +- 增加: 增加插件管理、设计新插件等插件模块 +- 增加: 增加插件应用:`功能案例` +- 增加: 增加使用文档 +- 优化: 生成代码适配插件模块 +- 优化:消息队列增加磁盘队列,默认队列从`redis`改为`disk` +- 优化:缓存驱动增加文件适配器,默认驱动从`redis`改为`file`,项目安装不再依赖`redis` +- 优化:优化系统监控加载流程 +- 优化:gf版本升级到v2.3.2 +- 修复:生成代码刷新后偶尔出现加载失败问题 + +### v2.2.1 +updated 2023.01.12 + +- 优化: 缓存清理各个应用的缓存文件夹读写判断 +- 修复: Linux 环境下创建插件报找不到模板文件 +- 修复: Excel 导入找不到最后一列数据 +- 增加: 无权限菜单不显示 +- 优化: 省市区数据为最新的 2023.01.11 的国家统计局省市区数据 +- 优化: 前台关于图片上传的 js 和 css 引入,避免资源依赖找不到 +- 优化: 插件模块查询机制, 增加数据缓存依赖,依赖时间为 360 秒 +- 优化: 文件上传的处理 +- 修复: 网站配置的多图上传引入路径错误 +- 修复: 定时任务协程问题导致执行失败 +- +### v2.1.1 +updated 2022.9.26 + +- 优化: 多图上传的显示样式及功能 +- 修复: 由于上传视频和语音开启了全域名返回导致的上传到服务器错误 +- 增加: 由增加home页面入口,前台页面 + +### v2.0.8 +updated 2022.9.21 + +- 优化: 优化菜单和角色数据权限,支持数据权限和按钮细分权限 +- 优化: 优化附件上传,增加文件上传选项 + +### v2.0.6 +updated 2022.9.18 + +- 增加: 增加阿里云短信配置和发送短信API +- 增加: 增加高德地图配置 +- 优化: 优化数据字典,增加数据类型和标签支持 +- +### v2.0.3 +updated 2022.9.10 + +- 2.0 全新上线 + +### v2.0.2 +updated 2022.6.11 + +- 增加: 增加生成代码功能,目前已支持一键生成CURD和关联表 +- 增加: 增加云存储UCloud配置,后台一键切换驱动 + +### v2.0.0 +updated 2022.5.20 + + - 初始化: 2.0 基础框架 diff --git a/docs/guide-zh-CN/sys-auth.md b/docs/guide-zh-CN/sys-auth.md new file mode 100644 index 0000000..27ac252 --- /dev/null +++ b/docs/guide-zh-CN/sys-auth.md @@ -0,0 +1,155 @@ +## 权限控制 + +目录 + +- 一、菜单权限 +- 二、数据权限 + + +### 一、菜单权限 + +> 菜单权限可以控制web后台菜单功能,每个菜单可以绑定一个或多个API权限,API权限决定了用户是否可以调用服务端接口。 + +#### 为角色添加菜单权限 + +1、HotGo后台 -> 权限管理 -> 菜单权限 -> 找到添加菜单,按照表单提示添加你的菜单信息。 + +2、添加菜单完成后,到 权限管理 -> 角色权限 -> 找到一位已有角色或者添加新角色 -> 在列表右侧操作栏找到菜单权限打开 -> 将第1步中添加的菜单分配给该角色即可。 + +#### 细粒度权限 + +> 一般用于web后台页面上的功能按钮,对不同的角色展示不同的按钮时会用到。 + +1、参考【为角色添加菜单权限】添加一个按钮类型的菜单。并为菜单分配API权限,假设你分配权限是:/test/index + +2、在web页面中创建一个按钮,如下: + +```vue + + + + +``` + +#### 菜单表主要字段解释 + +- 代码片段:[server/internal/model/input/adminin/menu.go](../../server/internal/model/input/adminin/menu.go) + +```go +type MenuRouteMeta struct { + // 解释参考:https://naive-ui-admin-docs.vercel.app/guide/router.html#%E5%A4%9A%E7%BA%A7%E8%B7%AF%E7%94%B1 + Title string `json:"title"` // 菜单名称 一般必填 + // Disabled bool `json:"disabled,omitempty"` // 禁用菜单 + Icon string `json:"icon,omitempty"` // 菜单图标 + KeepAlive bool `json:"keepAlive,omitempty"` // 缓存该路由 + Hidden bool `json:"hidden,omitempty"` // 隐藏菜单 + Sort int `json:"sort,omitempty"` // 排序越小越排前 + AlwaysShow bool `json:"alwaysShow,omitempty"` // 取消自动计算根路由模式 + ActiveMenu string `json:"activeMenu,omitempty"` // 当路由设置了该属性,则会高亮相对应的侧边栏。 + // 这在某些场景非常有用,比如:一个列表页路由为:/list/basic-list + // 点击进入详情页,这时候路由为/list/basic-info/1,但你想在侧边栏高亮列表的路由,就可以进行如下设置 + // 注意是配置高亮路由 `name`,不是path + IsRoot bool `json:"isRoot,omitempty"` // 是否跟路由 顶部混合菜单,必须传 true,否则左侧会显示异常(场景就是,分割菜单之后,当一级菜单没有子菜单) + FrameSrc string `json:"frameSrc,omitempty" ` // 内联外部地址 + Permissions string `json:"permissions,omitempty"` // 菜单包含权限集合,满足其中一个就会显示 + Affix bool `json:"affix,omitempty"` // 是否固定 设置为 true 之后 多页签不可删除 + Type int `json:"type"` // 菜单类型 +} +``` + + +#### API权限验证流程 + +```mermaid + +graph TD + A(用户请求API) --> B(验证中间件
server/internal/logic/middleware/admin_auth.go) + B -->|没有登录,但API需要登录| H(提示登录) + B -->|没有登录,但API不需要登录| G(验证通过,进入业务) + B -->|已登录| C(检查用户角色是否拥有API权限
server/internal/logic/admin/role.go,方法:Verify) -->|有权限| G(验证通过,进入业务) + C -->|API无需验证权限| G(验证通过,进入业务流程) + C -->|无权限| D(提示无权限) +``` + +#### 菜单权限添加或修改后多久生效? + +- API权限实时生效,web后台菜单刷新页面后生效,无需重启服务 + + +### 二、数据权限 + +> 数据权限是某人只能看到某些数据,可以为某人设置一定的数据范围,让其只能看到允许他看到的数据。 + +> 例如:公司存在多个销售部门,不同的部门仅能查看到自己所属部门下的数据;再如:用户有多级代理商,只能查看自己和自己下级的数据。 + +#### 目前已经支持的数据权限如下 + +| 数据范围 | 描述 | +|---------|--------------------------------------------| +| 全部权限 | 不做过滤,可以查看所有数据 | +| 当前部门 | 仅可以看到所属部门下的数据 | +| 当前以及下部门 | 仅可以看到所属以及下级部门的数据 | +| 自定义部门 | 可以看到设置的指定部门,支持多个 | +| 仅自己 | 仅可以看到自己的数据 | +| 自己和直属下级 | 仅可以看到自己和直属下级的数据,直属下级是指当前用户往下1级的用户 | +| 自己和全部下级 | 仅可以看到自己和全部下级的数据,全部下级是指当前用户所有的下级用户,包含其下级的下级 | + +#### 如何区分部门和下级用户? + +- 在实际使用时,部门更多的是在公司或机构中使用,可以通过在 组织管理 -> 后台用户 ->为用户绑定部门 +- 下级用户在代理商或分销系统中比较常见,后台用户由谁添加的,那么被添加的用户就是其下级用户 + +#### 如何判断数据是谁的? + +- 在数据库建表时,只要表中包含字段:`created_by`或`member_id`即可过滤 [仅自己、自己和直属下级、自己和全部下级] 类型的数据权限 + +#### 如何在具体业务中使用数据权限过滤? + +- 只需在查询、更新或删除等ORM链式操作中加入相应`Handler`方法即可 + +- 如果你想对Handler有更多详细了解,请查看:https://goframe.org/pages/viewpage.action?pageId=20087340 + +- 下面提供一个简单使用例子: + +```go +package main + +import ( + "context" + "hotgo/internal/dao" + "hotgo/internal/library/hgorm/handler" +) + +func test(ctx context.Context) { + dao.AdminPost.Ctx(ctx).Where("id", 1).Handler(handler.FilterAuth).Scan(&res) +} +``` + +- 如果表中没有字段:`created_by`或`member_id`,也可以使用自定义字段方法来过滤数据权限,如下: + +```go +package main + +import ( + "context" + "hotgo/internal/dao" + "hotgo/internal/library/hgorm/handler" +) + +func test(ctx context.Context) { + dao.AdminPost.Ctx(ctx).Where("id", 1).Handler(handler.FilterAuthWithField("test_field")).Scan(&res) +} +``` + + +- 过滤方法实现请参考:[server/internal/library/hgorm/handler/filter_auth.go](../../server/internal/library/hgorm/handler/filter_auth.go) + + diff --git a/docs/guide-zh-CN/sys-catalog.md b/docs/guide-zh-CN/sys-catalog.md new file mode 100644 index 0000000..bf9d040 --- /dev/null +++ b/docs/guide-zh-CN/sys-catalog.md @@ -0,0 +1,176 @@ +## 目录结构 + +目录 + +- 服务端 +- web前端 +- uniapp端(待开放) + + +#### 服务端 +``` +/server +├── addons +│ ├── modules +│ ├── xxx插件 +│ | ├── api +│ | ├── controller +│ | ├── crons +│ | ├── global +│ | ├── logic +│ | ├── model +│ | ├── queues +│ | ├── resource +│ | ├── router +│ | ├── service +│ | ├── main.go +│ | └── README.md +├── api +│ ├── admin +│ ├── api +│ ├── home +│ ├── websocket +├── hack +├── internal +│ ├── cmd +│ ├── consts +│ ├── controller +│ ├── crons +│ ├── dao +│ ├── global +│ ├── library +│ ├── logic +│ ├── model +│ | ├── do +│ │ ├── entity +│ │ └── input +│ ├── packed +│ ├── queues +│ ├── router +│ ├── service +│ └── websocket +├── manifest +├── resource +├── storage +├── utility +├── go.mod +├── main.go +├── Makefile +└── README.md +``` + +| 目录 | 描述 | +|--------------------------|-----------------------------------------------------------------| +| 基于gf的工程目录结构做了部分调整 | 参考地址: https://goframe.org/pages/viewpage.action?pageId=30740166 | +| **addons** | 所有的插件模块都放在这里 | +| --- modules | 为插件模块提供隐式初始化 | +| --- xxx插件 | 插件模块名称 | +| --- --- api | 对外接口。提供服务的输入/输出数据结构定义 | +| --- --- --- admin | 后台接口 | +| --- --- --- api | 前台通用接口,包含PC端、移动端接口等 | +| --- --- --- home | 前台PC端、H5端页面 | +| --- --- --- websocket | 可同时为多应用提供websocket接口 | +| --- --- consts | 插件内主要的常量定义 | +| --- --- controller | 接收/解析用户输入参数的入口/接口层,也可以理解为控制器 | +| --- --- crons | 项目中由系统统一接管的定时任务处理 | +| --- --- global | 项目内主要的全局变量和系统的一些初始化操作 | +| --- --- logic | 业务逻辑封装管理,特定的业务逻辑实现和封装往往是项目中最复杂的部分 | +| --- --- model | 数据结构管理模块,管理数据实体对象,以及输入与输出数据结构定义 | +| --- --- --- input | 对内接口。用于controller调用service或service之间调用时的输入/输出结构定义,以及输入过滤和预处理 | +| --- queues | 为项目内所有的消息队列的消费者提供统一的初始化和处理 | +| --- resource | 静态资源文件。这些文件往往可以通过 资源打包/镜像编译 的形式注入到发布文件中 | +| --- --- router | 注册对外接口和分组中间件 | +| --- --- service | 用于业务模块解耦的接口定义层具体的接口实现在logic中进行注入 | +| --- main.go | 插件始化文件和模块插拔接口 | +| **api** | 对外接口。提供服务的输入/输出数据结构定义 | +| --- admin | 后台接口 | +| --- api | 前台通用接口,包含PC端、移动端接口等 | +| --- home | 前台PC端、H5端页面 | +| --- websocket | 可同时为多应用提供websocket接口 | +| **hack** | 存放项目开发工具、脚本等内容例如,CLI工具的配置,各种shell/bat脚本等文件 | +| **internal** | 业务逻辑存放目录通过Golang internal特性对外部隐藏可见性 | +| --- cmd | 命令行管理目录可以管理维护多个命令行 | +| --- consts | 项目内主要的常量定义 | +| --- controller | 接收/解析用户输入参数的入口/接口层,也可以理解为控制器 | +| --- crons | 项目中由系统统一接管的定时任务处理 | +| --- dao | 数据访问对象,这是一层抽象对象,用于和底层数据库交互,仅包含最基础的 CURD 方法 | +| --- global | 项目内主要的全局变量和系统的一些初始化操作 | +| --- library | 项目内常用功能的扩展库 | +| --- logic | 业务逻辑封装管理,特定的业务逻辑实现和封装往往是项目中最复杂的部分 | +| --- model | 数据结构管理模块,管理数据实体对象,以及输入与输出数据结构定义 | +| --- --- do | 用于dao数据操作中业务模型与实例模型转换,由工具维护,用户不能修改 | +| --- --- entity | 与数据集合绑定的程序数据结构定义,通常和数据表一一对应 | +| --- --- input | 对内接口。用于controller调用service或service之间调用时的输入/输出结构定义,以及输入过滤和预处理 | +| --- packed | 将静态资源打包进可执行文件,无需单独部署 | +| --- queues | 为项目内所有的消息队列的消费者提供统一的初始化和处理 | +| --- router | 注册对外接口和分组中间件 | +| --- service | 用于业务模块解耦的接口定义层具体的接口实现在logic中进行注入 | +| **manifest** | 包含程序编译、部署、运行、配置的文件常见内容如下: | +| --- config | 配置文件存放目录 | +| --- docker | Docker镜像相关依赖文件,脚本文件等等 | +| --- deploy | 部署相关的文件默认提供了Kubernetes集群化部署的Yaml模板,通过kustomize管理 | +| **resource** | 静态资源文件。这些文件往往可以通过 资源打包/镜像编译 的形式注入到发布文件中 | +| **storage** | 本地数据存储目录,例如文件缓存、磁盘队列数据、sql数据文件、SSL证书等 | +| **utility** | 一些常用的工具方法 | +| go.mod | 使用Go Module包管理的依赖描述文件 | +| main.go | 程序入口文件 | +| Makefile | 程序构建发布和开发快捷指令 | +| README.md | 项目介绍文件 | + + + + +#### web前端 +``` +/web +├── build # 打包脚本相关 +│ ├── config # 配置文件 +│ ├── generate # 生成器 +│ ├── script # 脚本 +│ └── vite # vite配置 +├── mock # mock文件夹 +├── public # 公共静态资源目录 +├── src # 主目录 +│ ├── api # 接口文件 +│ ├── assets # 资源文件 +│ │ ├── icons # icon sprite 图标文件夹 +│ │ ├── images # 项目存放图片的文件夹 +│ │ └── svg # 项目存放svg图片的文件夹 +│ ├── components # 公共组件 +│ ├── design # 样式文件 +│ ├── directives # 指令 +│ ├── enums # 枚举/常量 +│ ├── hooks # hook +│ │ ├── component # 组件相关hook +│ │ ├── core # 基础hook +│ │ ├── event # 事件相关hook +│ │ ├── setting # 配置相关hook +│ │ └── web # web相关hook +│ ├── layouts # 布局文件 +│ │ ├── default # 默认布局 +│ │ ├── iframe # iframe布局 +│ │ └── page # 页面布局 +│ ├── locales # 多语言 +│ ├── logics # 逻辑 +│ ├── main.ts # 主入口 +│ ├── router # 路由配置 +│ ├── settings # 项目配置 +│ │ ├── componentSetting.ts # 组件配置 +│ │ ├── designSetting.ts # 样式配置 +│ │ ├── encryptionSetting.ts # 加密配置 +│ │ ├── localeSetting.ts # 多语言配置 +│ │ ├── projectSetting.ts # 项目配置 +│ │ └── siteSetting.ts # 站点配置 +│ ├── store # 数据仓库 +│ ├── utils # 工具类 +│ └── views # 页面 +├── types # 类型文件 +├── vite.config.ts # vite配置文件 +└── windi.config.ts # windcss配置文件 +``` + + +#### uniapp端 +``` +// 待开放 +``` \ No newline at end of file diff --git a/docs/guide-zh-CN/sys-code.md b/docs/guide-zh-CN/sys-code.md new file mode 100644 index 0000000..d76d2a3 --- /dev/null +++ b/docs/guide-zh-CN/sys-code.md @@ -0,0 +1,379 @@ +## 代码生成 + +目录 + +- 使用条件 +- 模板配置 +- CLI配置 +- 生成CRUD表格 +- 生成树形表格 +- 多数据库使用 +- 自定义生成模板 +- 内置gf-cli +- 指定gf-cli版本 +- 指定数据库驱动 + + +> 在HotGo中可以通过后台开发工具快速的一键生成CRUD,自动生成Api、控制器、业务逻辑、Web页面、表单组件、菜单权限等。 + + +### 使用条件 + +- hotgo 版本号 >= 2.13.1 +- 使用前必须先看 [数据库](sys-db.md) + + +### 生成模板配置 + +- 配置路径:server/manifest/config/config.yaml +```yaml +# 生成代码 +hggen: + allowedIPs: [ "127.0.0.1", "*" ] # 白名单,*代表所有,只有允许的IP后台才能使用生成代码功能 + selectDbs: [ "default" ] # 可选生成表的数据库配置名称,支持多库 + disableTables: [ "hg_sys_gen_codes","hg_admin_role_casbin" ] # 禁用的表,禁用以后将不会在选择表中看到 + delimiters: [ "@{", "}" ] # 模板引擎变量分隔符号 + # 生成应用模型,所有生成模板允许自定义,可以参考default模板进行改造 + application: + # CRUD和关系树列表模板 + crud: + templates: + # 默认的主包模板 + - group: "default" # 分组名称 + isAddon: false # 是否为插件模板 false|true + masterPackage: "sys" # 主包名称,需和controllerPath、logicPath、inputPath保持关联 + templatePath: "./resource/generate/default/curd" # 模板路径 + apiPath: "./api/admin" # goApi生成路径 + controllerPath: "./internal/controller/admin/sys" # 控制器生成路径 + logicPath: "./internal/logic/sys" # 主要业务生成路径 + inputPath: "./internal/model/input/sysin" # 表单过滤器生成路径 + routerPath: "./internal/router/genrouter" # 生成路由表路径 + sqlPath: "./storage/data/generate" # 生成sql语句路径 + webApiPath: "../web/src/api" # webApi生成路径 + webViewsPath: "../web/src/views" # web页面生成路径 + + # 默认的插件包模板,{$name}会自动替换成实际的插件名称 + - group: "addon" # 分组名称 + isAddon: true # 是否为插件模板 false|true + masterPackage: "sys" # 主包名称,需和controllerPath、logicPath、inputPath保持关联 + templatePath: "./resource/generate/default/curd" # 模板路径 + apiPath: "./addons/{$name}/api/admin" # goApi生成路径 + controllerPath: "./addons/{$name}/controller/admin/sys" # 控制器生成路径 + logicPath: "./addons/{$name}/logic/sys" # 主要业务生成路径 + inputPath: "./addons/{$name}/model/input/sysin" # 表单过滤器生成路径 + routerPath: "./addons/{$name}/router/genrouter" # 生成路由表路径 + sqlPath: "./storage/data/generate/addons" # 生成sql语句路径 + webApiPath: "../web/src/api/addons/{$name}" # webApi生成路径 + webViewsPath: "../web/src/views/addons/{$name}" # web页面生成路径 + + # 消息队列模板 + queue: + templates: + - group: "default" + templatePath: "./resource/generate/default/queue" + + # 定时任务模板 + cron: + templates: + - group: "default" + templatePath: "./resource/generate/default/cron" + + # 生成插件模块,通过后台创建新插件时使用的模板,允许自定义,可以参考default模板进行改造 + addon: + srcPath: "./resource/generate/default/addon" # 生成模板路径 + webApiPath: "../web/src/api/addons/{$name}" # webApi生成路径 + webViewsPath: "../web/src/views/addons/{$name}" # web页面生成路径 +``` + +### 生成CLI配置 + +- hotgo在生成dao、service配置时,默认了和gf官方一致的配置方式和代码生成规则。所以无论你是通过hotgo亦或gf命令生成,最终代码格式完全一致,遵循一致的代码规范。 + +- 配置路径:[server/hack/config.yaml](../../server/hack/config.yaml) + +```yaml +gfcli: + build: + name: "hotgo" # 编译后的可执行文件名称 + # arch: "all" #不填默认当前系统架构,可选:386,amd64,arm,all + # system: "all" #不填默认当前系统平台,可选:linux,darwin,windows,all + mod: "none" + cgo: 0 + packSrc: "resource" # 将resource目录打包进可执行文件,静态资源无需单独部署 + packDst: "internal/packed/packed.go" # 打包后生成的Go文件路径,一般使用相对路径指定到本项目目录中 + version: "" + output: "./temp/hotgo" # 可执行文件生成路径 + extra: "" + + gen: + dao: + - link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true" +# - link: "pgsql:postgres:hg123456@tcp(127.0.0.1:5432)/hotgo" + group: "default" # 分组 使用hotgo代码生成功能时必须填 + # tables: "" # 指定当前数据库中需要执行代码生成的数据表。如果为空,表示数据库的所有表都会生成。 + tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。 + removePrefix: "hg_" + descriptionTag: true + noModelComment: true + jsonCase: "CamelLower" + gJsonSupport: true + clear: true + + service: # 生成业务配置 + srcFolder: "internal/logic" + dstFolder: "internal/service" + dstFileNameCase: "CamelLower" + clear: true +``` + +### 生成CRUD表格 + +- 推荐使用热编译方式启动HotGo,这样生成完成页面自动刷新即可看到新生成内容,无需手动重启 +- 服务端热编译启动:`gf run main.go`, web前端启动:`pnpm run dev` 或 `npm run dev` + +1、创建数据表 + +1.1 创建测试表格表`hg_test_table` +```mysql +CREATE TABLE `hg_test_table` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `category_id` bigint(20) NOT NULL COMMENT '分类ID', + `title` varchar(64) NOT NULL COMMENT '标题', + `description` varchar(255) NOT NULL COMMENT '描述', + `content` text NOT NULL COMMENT '内容', + `image` varchar(255) DEFAULT NULL COMMENT '单图', + `attachfile` varchar(255) DEFAULT NULL COMMENT '附件', + `city_id` bigint(20) DEFAULT '0' COMMENT '所在城市', + `switch` int(11) DEFAULT '1' COMMENT '显示开关', + `sort` int(11) NOT NULL COMMENT '排序', + `status` tinyint(1) DEFAULT '1' COMMENT '状态', + `created_by` bigint(20) DEFAULT '0' COMMENT '创建者', + `updated_by` bigint(20) DEFAULT '0' COMMENT '更新者', + `created_at` datetime DEFAULT NULL COMMENT '创建时间', + `updated_at` datetime DEFAULT NULL COMMENT '修改时间', + `deleted_at` datetime DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='测试表格'; + +``` + +1.2 测试分类表`hg_test_category`: +- 注意:该表为了方便功能演示已经内置无需再次创建,此处提示表结构只是为了方便大家梳理关联表关系 +```mysql +CREATE TABLE `hg_test_category` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类ID', + `name` varchar(255) NOT NULL COMMENT '分类名称', + `description` varchar(255) DEFAULT NULL COMMENT '描述', + `sort` int(11) NOT NULL COMMENT '排序', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + `status` tinyint(1) DEFAULT '1' COMMENT '状态', + `created_at` datetime DEFAULT NULL COMMENT '创建时间', + `updated_at` datetime DEFAULT NULL COMMENT '修改时间', + `deleted_at` datetime DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='测试分类'; + +``` + +1.3 插入测试数据 +```mysql +INSERT INTO `hg_test_table` (`id`, `category_id`, `title`, `description`, `content`, `image`, `attachfile`, `city_id`, `switch`, `sort`, `status`, `created_by`, `updated_by`, `created_at`, `updated_at`, `deleted_at`) VALUES (1, 1, '测试标题', '描述', '

不知道写点啥!



', 'https://gmycos.facms.cn/hotgo/logo.sig.png', 'https://gmycos.facms.cn/hotgo/attachment/2022-12-30/cpf1x44idoycrtajf2.xlsx', 110102, 1, 10, 1, 0, 1, '2022-12-15 19:30:14', '2023-02-23 13:55:32', NULL); + +``` + + +2、创建生成配置 +- 登录HotGo后台 -> 开发工具 -> 代码生成 -> 找到立即生成按钮并打开,选择和填写如下参数: + +![生成添加演示图](images/sys-code-add.png) + + +3、自定义配置 +- 确认配置无误后,点击生成配置会自动跳转到生成配置页面,如下: + +![生成配置页面](images/sys-code-config-init.png) + +- 你可以在该页面点击`预览代码`查看生成的内容,如果无需调整亦可以直接点击`提交生成`,以下是预览代码效果: + +![生成预览](images/sys-code-preview.png) + +- 如果你对默认的生成配置不满意,可以根据页面表单提示,自定义表格属性和字段属性 + +- 这里假设我们要一个关联表,让表`hg_test_table`字段`category_id`去关联 表`hg_test_category`字段`id`,我们可以这样做: + +![生成关联配置](images/sys-code-config-join.png) + + +- 如果你想调整主表每列字段的显示方式,可以点击上方导航栏中的 [主表字段] 进行调整 +- 这里我们不做任何调整直接进入下一步。目的是为了后续演示对最终生成结果不满意的再次调整方案 + +![生成关联配置](images/sys-code-master.png) + +4、以上内容都已配置无误后,点击提交生成即可。 + +- 如果你使用的热编译,那么页面会在生成成功后立即刷新,刷新完成你即可在后台菜单栏中看到`测试表格`菜单。如果不是使用热编译启动,请手动重启服务后刷新。 + +- 注意:热编译环境下,web端往往会快于服务端重启并加载完成,此时访问新生成的菜单页面可能会存在某接口请求超时或404问题,这是服务端正在重启导致的,属于正常现象,一般稍等几秒再试即可。 + +- 接下来让我们看看生成的表格页面,效果如下: + +![生成测试表格页面](images/sys-code-list.png) + + +5、假设我们对生成结果不满意,有新的优化需求如下: +1. 把`单图`、`附件`改换成上传组件 +2. 把`创建者`、`更新者`隐藏 +3. 把`分类ID`隐藏,然后把关联表中的`分类名称`显示出来 + +> 那么我们可以回到 开发工具 -> 代码生成 -> 找到刚刚生成的记录 -> 在右侧操作栏中点击生成配置,再次进入配置页面做如下操作即可: + +1. 点击上方导航栏[主表字段],调整字段选项: + +![修改主表配置](images/sys-code-master-save.png) + + +2. 点击上方导航栏[关联表],调整字段选项: + +![修改关联表配置](images/sys-code-config-join-save.png) + + +3. 返回[基本信息],勾选强制覆盖,然后点击`预览代码`,确认生成代码无误后点击`提交生成` + +![强制覆盖并提交生成](images/sys-code-config-post.png) + + +- 生成完成刷新页面后,再次来到`测试表格`,发现表格已经调整到了我们预期效果 + +1. 列表效果: + +![最终列表效果](images/sys-code-list-ok.png) + +2. 编辑表单效果 + +![最终编辑表单效果](images/sys-code-list-edit-ok.png) + + +- 至此生成增删改查列表示例结束! + +### 生成树形表格 + +待写。 + +### 多数据库使用 + +- 假设我们要增加一个库名为`hotgo2`、分组为`default2`的数据库,并要为其生成代码 + +1. 配置[server/hack/config.yaml](../../server/hack/config.yaml) 如下: +```yaml + gen: + dao: + - link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true" +# - link: "pgsql:postgres:hg123456@tcp(127.0.0.1:5432)/hotgo" + group: "default" # 分组 使用hotgo代码生成功能时必须填 + tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。 + removePrefix: "hg_" + descriptionTag: true + noModelComment: true + jsonCase: "CamelLower" + gJsonSupport: true + clear: false + - link: "mysql:hotgo2:hg123456.@tcp(127.0.0.1:3306)/hotgo2?loc=Local&parseTime=true" + group: "default2" # 分组 使用hotgo代码生成功能时必须填 + tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。 + removePrefix: "" + descriptionTag: true + noModelComment: true + jsonCase: "CamelLower" + gJsonSupport: true + clear: false +``` + +2. 配置`server/manifest/config/config.yaml`, + +`database`配置如下: +```yaml +database: + logger: + level: "all" + stdout: true + default: + link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true" +# - link: "pgsql:postgres:hg123456@tcp(127.0.0.1:5432)/hotgo" + debug: true + Prefix: "hg_" + default2: + link: "mysql:hotgo2:hg123456.@tcp(127.0.0.1:3306)/hotgo2?loc=Local&parseTime=true" + debug: true + Prefix: "" +``` + +`hggen`配置如下: +```yaml +hggen: + allowedIPs: ["127.0.0.1", "*"] # 白名单,*代表所有,只有允许的IP后台才能使用生成代码功能 + selectDbs: [ "default", "default2" ] # 可选生成表的数据库配置名称,支持多库 + disableTables : ["hg_sys_gen_codes","hg_admin_role_casbin"] # 禁用的表,禁用以后将不会在选择表中看到 + delimiters: ["@{", "}"] # 模板引擎变量分隔符号 +``` + +3. 登录HotGo后台 -> 开发工具 -> 代码生成 -> 找到立即生成按钮并打开,就会发现`数据库`选项增加了一个`default2`,后续生成步骤和生成例子完全一样 + +> 注意:上述的配置中所有的`default2`名称必须保持一致 + + +### 自定义生成模板 + +> 系统内置了两组CURD生成模板,请参考[生成模板配置](sys-code.md#生成模板配置)。default:是默认的生成到主模块下;addon:是默认生成到指定的插件下 + +- HotGo允许你新建新的模板分组来满足你的需求,模板可根据现有模板基础拷贝一份出来做改造,默认模板目录:[server/resource/generate/default](../../server/resource/generate/default) + + + +### 内置gf-cli + +> 为了确保生成代码的依赖稳定性,在面对`gf`版本更新可能导致向下不兼容情况时,HotGo将`gf-cli`工具内置到系统中并进行在线执行调整,从而提供更可靠和一致的生成代码功能。 + +- 后续我们也将开放在线运行`gf gen ...`功能。在做插件开发时也会支持到在线生成插件下的service接口,这将会使得插件开发更加方便 + + + +### 指定gf-cli版本 + +> HotGo多数情况下会和最新版本的gf-cli保持同步,如果更新不及时或你不想使用最新版本的gf-cli来生成代码,可以找到自己想要的版本进行替换即可。 + +- 下面大致做一些替换步骤说明: + +1. 打开https://github.com/gogf/gf,找到你想要使用的版本`clone`下来 +2. 将`clone`代码中`gf/cmd/gf/internal/`目录覆盖到`server/internal/library/hggen/internal` +3. 将覆盖过来的目录文件中引入包名`github.com/gogf/gf/cmd/gf/v2/`批量改为`hotgo/internal/library/hggen/` +4. 运行`go mod tidy` +5. 运行`go run main.go`,如果没有报错,那么恭喜你已经完成了。如果有报错一般都是版本差异带来的影响,需要根据情况自行调整 + + + +### 指定数据库驱动 + +> HotGo默认使用mysql驱动,如果你想用其他数据库驱动打开下方文件中注释即可,目前已支持mysql、pgsql + +修改文件路径:server/internal/library/hggen/internal/cmd/cmd_gen_dao.go +```go +package cmd + +import ( + //_ "github.com/gogf/gf/contrib/drivers/clickhouse/v2" + //_ "github.com/gogf/gf/contrib/drivers/mssql/v2" + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" + //_ "github.com/gogf/gf/contrib/drivers/oracle/v2" + _ "github.com/gogf/gf/contrib/drivers/pgsql/v2" + //_ "github.com/gogf/gf/contrib/drivers/sqlite/v2" + + "hotgo/internal/library/hggen/internal/cmd/gendao" +) + +type ( + cGenDao = gendao.CGenDao +) + +``` + +修改完成后运行`go mod tidy` diff --git a/docs/guide-zh-CN/sys-console.md b/docs/guide-zh-CN/sys-console.md new file mode 100644 index 0000000..33e8652 --- /dev/null +++ b/docs/guide-zh-CN/sys-console.md @@ -0,0 +1,75 @@ +## 控制台 + +目录 + +- 启动所有服务 +- HTTP服务 +- 消息队列 +- 定时任务 +- 常用工具 +- Makefile + +### 启动所有服务 +- 仅推荐在开发期间快速调试使用,线上实际部署时建议将各个服务分开部署,这样重新部署某个服务时无需全部重启。 + +```shell + +# 默认 +go run main.go + +# 通过热编译启动 +gf run main.go +``` + +### HTTP服务 +- 启动HTTP服务,包含websocket。 + +```shell +# 默认 +go run main.go http + +# 通过热编译启动 +gf run main.go --args "http" +``` + +### 消息队列 +- 启动消息队列的消费者。 + +```shell +# 默认 +go run main.go queue + +# 通过热编译启动 +gf run main.go --args "queue" +``` + +### 定时任务 +- 启动系统中统一注册的定时任务。 + +```shell +# 默认 +go run main.go cron + +# 通过热编译启动 +gf run main.go --args "cron" +``` + + +### 常用工具 +- 释放casbin权限,用于清理无效的权限设置。 + + +```shell +go run main.go tools -m=casbin -a1=refresh +``` + + +### Makefile +- 通过make提供一些快捷命令 + +```shell +# 一键编译,打包前后端代码到可执行文件 +make build + +# 更多请查看 /server/Makefile文件 +``` \ No newline at end of file diff --git a/docs/guide-zh-CN/sys-cron.md b/docs/guide-zh-CN/sys-cron.md new file mode 100644 index 0000000..efca8a8 --- /dev/null +++ b/docs/guide-zh-CN/sys-cron.md @@ -0,0 +1,70 @@ +## 定时任务 + +目录 + +- 实现接口 +- 一个例子 +- 更多 + +> 在实际的项目开发中,定时任务几乎成为不可或缺的一部分。HotGo为定时任务提供一个方便的后台操作界面,让您能够轻松地进行在线启停、修改和立即执行等操作。这样的设计可以极大地改善您在使用定时任务过程中的体验,让整个过程更加顺畅、高效。 + + +### 实现接口 +- 为了提供高度的扩展性,定时任务在设计上采用了接口化的思路。只需要实现以下接口,您就可以在任何地方注册和使用定时任务功能,从而实现更大的灵活性和可扩展性。 + +```go +// Cron 定时任务接口 +type Cron interface { + // GetName 获取任务名称 + GetName() string + // Execute 执行任务 + Execute(ctx context.Context, parser *Parser) (err error) +} +``` + + +### 一个例子 + +定时任务的文件结构可以根据具体需要进行调整,以下是一个常见的参考结构: + +- 文件路径:server/internal/crons/test.go + +```go +package crons + +import ( + "context" + "hotgo/internal/library/cron" + "time" +) + +func init() { + cron.Register(Test) +} + +// Test 测试任务(无参数) +var Test = &cTest{name: "test"} + +type cTest struct { + name string +} + +func (c *cTest) GetName() string { + return c.name +} + +// Execute 执行任务 +func (c *cTest) Execute(ctx context.Context, parser *cron.Parser) (err error) { + parser.Logger.Infof(ctx, "cron test Execute:%v", time.Now()) // 记录任务调度日志 + return +} +``` + +继续在后台系统设置-定时任务-添加任务,填写的任务名称需要和上面的名称保持一致,再进行简单的策略配置以后,一个后台可控的定时任务就添加好了! + + +### 更多 + +定时任务源码路径:server/internal/library/cron/cron.go + +更多文档请参考:https://goframe.org/pages/viewpage.action?pageId=1114187 \ No newline at end of file diff --git a/docs/guide-zh-CN/sys-db.md b/docs/guide-zh-CN/sys-db.md new file mode 100644 index 0000000..64a70ef --- /dev/null +++ b/docs/guide-zh-CN/sys-db.md @@ -0,0 +1,150 @@ +## 数据库 + +目录 + +- 字段类型 +- 特殊字段默认表单组件 +- 特殊字段默认表单验证器 +- SQL默认查询方式 +- 其他 + +### 字段类型 + +- 创建数据库表当按如下的规则进行字段命名、类型、属性设置和备注后,再生成CRUD代码时会自动生成对应的Api、控制器、业务逻辑、Web页面、[表单组件](web-form.md)等的一些默认属性 +- 当你了解这些默认技巧后,会有效提高你在实际开发中的生产效率 + +| 数据库类型 | 额外属性 | 转换Go类型 | 转换Ts类型 | 表单组件 | +|---------------------------------------------------------------|--------------|--------------|---------|-----------------------| +| int, tinyint,small_int,smallint,medium_int,mediumint,serial | / | int | number | InputNumber(数字输入框) | +| int, tinyint,small_int,smallint,medium_int,mediumint,serial | unsigned | uint | number | InputNumber(数字输入框) | +| big_int,bigint,bigserial | / | int64 | number | InputNumber(数字输入框) | +| big_int,bigint,bigserial | unsigned | uint64 | number | InputNumber(数字输入框) | +| real | / | float32 | number | InputNumber(数字输入框) | +| float,double,decimal,money,numeric,smallmoney | / | float64 | number | InputNumber(数字输入框) | +| bit(1) 、bit(true)、bit(false) | / | bool | boolean | Input(文本输入框,默认) | +| bit | / | int64-bytes | array | InputDynamic(动态KV表单) | +| bit | unsigned | uint64-bytes | array | InputDynamic (动态KV表单) | +| bool | / | bool | boolean | Input(文本输入框,默认) | +| date | / | *gtime.Time | string | Date(日期选择器) | +| datetime,timestamp,timestamptz | / | *gtime.Time | string | Time(时间选择器) | +| json | / | *gjson.Json | string | Input(文本输入框) | +| jsonb | / | *gjson.Json | string | Input(文本输入框) | +| 以下为物理类型中包含字段部分时的转换方式,默认情况 | / | / | / | / | +| text,char,character | / | string | string | Input(文本输入框) | +| float,double,numeric | / | string | string | Input(文本输入框) | +| bool | / | bool | boolean | Input(文本输入框,默认) | +| binary,blob | / | []byte | string | Input(文本输入框,默认) | +| int | / | int | number | InputNumber(数字输入框) | +| int | unsigned | int | number | InputNumber(数字输入框) | +| time | / | *gtime.Time | string | Time(时间选择器) | +| date | / | *gtime.Time | string | Date(日期选择器) | +| 没有满足以上任何条件的 | / | string | string | Input(文本输入框) | + + +### 特殊字段默认表单组件 +- 以下字段在不设置表单组件时会默认使用的表单组件 + +| 数据库字段 | 字段名称 | 表单组件 | +|--------------|----------------------|----------------------| +| status | 状态字段(任意int类型) | Select (单选下拉框) | +| created_at | 创建时间字段 | TimeRange (时间范围选择) | +| province_id | 省份ID字段(任意int类型) | CitySelector (省市区选择) | +| city_id | 城市ID字段(任意int类型) | CitySelector (省市区选择) | +| 任意字串符字段 | 长度>= 200 and <= 500 | InputTextarea (文本域) | +| 任意字串符字段 | 长度> 500 | InputEditor (富文本) | + + +### 特殊字段默认表单验证器 +- 以下字段在不设置表单组件时会默认使用的表单验证器 + +| 数据库字段/Go类型 | 字段名称 | 表单验证规则 | +|-------------------|--------|-----------------------| +| mobile | 手机号 | 不为空时必须是手机号码(国内) | +| qq | QQ | 不为空时必须是QQ号码 | +| email | 邮箱地址 | 不为空时必须是邮箱格式 | +| id_card | 身份证号码 | 不为空时必须是15或18位身份证号码 | +| bank_card | 银行卡号码 | 银行卡号码 | +| password | 密码 | 密码验证,必须包含6-18为字母和数字 | +| price | 价格 | 金额验证,最多允许输入10位整数及2位小数 | +| Go类型为uint、uint64 | 正整数 | 非零正整数验证 | + +### SQL默认查询方式 +- Go类型取决于数据库物理类型,请参考 [字段类型] 部分 + +| Go类型 | 查询方式 | +|-------------------------|--------------------------------------| +| string | LIKE | +| date,datetime | = | +| int,uint,int64,uint64 | = | +| []int,[]int64,[]uint64 | IN (...) | +| float32,float64 | = | +| []byte4 | =(默认) | +| time.Time,*gtime.Time | = | +| *gjson.Json | JSON_CONTAINS(json_doc, val[, path]) | + + + +### 其他 + +#### 默认字典选项 + +- 数据库字段为 `status`且类型为任意数字类型的会使用系统默认的状态字典 + +#### 默认属性 + +- 默认必填,当数据库字段存在非空`IS_NULLABLE`属性时,默认勾选必填验证 +- 默认唯一,当数据库字段索引存在`UNI`时,默认勾选唯一值验证 +- 默认主键,当数据库字段索引存在`PRI`时,默认为主键,不允许编辑 +- 默认排序,当数据库字段存在`sort`时,默认开启排序,添加表单自动获取最大排序增量值并填充表单 +- 默认列名,默认使用字段注释作为表格的列名。当数据库字段未设置注释时,默认使用字段名称作为列名 + +#### 自动更新/插入 + +- 自动更新,当数据库字段为`updated_at`(更新时间),`updated_by`(更新者) +- 自动插入,当数据库字段为`created_at`(创建时间),`created_by`(创建者) +- 软删除,表存在字段`deleted_at`时,使用表的Orm模型查询条件将会自动加入[ `deleted_at` IS NULL ],删除时只更新删除时间而不会真的删除数据 +- 树表:不论更新插入,都会根据表中字段`pid`(上级ID)自动维护`level`(树等级)和`tree`(关系树) + + +#### 操作人字段维护 + +- 生成列表中存在并且勾选展示字段`created_by`(创建者)、`updated_by`(修改者)、`deleted_by`(删除者)时,会自动到表`hg_admin_member`中获取操作人的基本信息摘要,并渲染到列表中,效果如下: + +![](images/sys-db-by.png) + +- 生成列表中存在并且勾选查询字段`created_by`(创建者)、`updated_by`(修改者)、`deleted_by`(删除者)时,会强制将查询表单改为关键词查询,从`hg_admin_member`查询操作人。效果如下: + +![](images/sys-db-by2.png) + +- 查询代码片段,参考路径:[server/internal/logic/admin/member.go](../../server/internal/logic/admin/member.go) + +```go + +// 查询创建者 +if in.CreatedBy != "" { + ids, err := service.AdminMember().GetIdsByKeyword(ctx, in.CreatedBy) + if err != nil { + return nil, 0, err + } + mod = mod.WhereIn(dao.SysGenCurdDemo.Columns().CreatedBy, ids) +} + +// GetIdsByKeyword 根据关键词查找符合条件的用户ID +func (s *sAdminMember) GetIdsByKeyword(ctx context.Context, ks string) (res []int64, err error) { + ks = gstr.Trim(ks) + if len(ks) == 0 { + return + } + array, err := dao.AdminMember.Ctx(ctx).Fields("id"). + Where("`id` = ? or `real_name` = ? or `username` = ? or `mobile` = ?", ks, ks, ks, ks). + Array() + if err != nil { + err = gerror.Wrap(err, "根据关键词获取用户ID失败,请稍后重试!") + } + res = gvar.New(array).Int64s() + return +} +``` + + +> 这里只列举了较为常用的默认规则,其他更多默认规则请参考:[server/internal/library/hggen/views/column_default.go](../../server/internal/library/hggen/views/column_default.go) diff --git a/docs/guide-zh-CN/sys-exploit.md b/docs/guide-zh-CN/sys-exploit.md new file mode 100644 index 0000000..70fb37b --- /dev/null +++ b/docs/guide-zh-CN/sys-exploit.md @@ -0,0 +1,201 @@ +## 开发规范 + +目录 + +- 规范说明 +- 规范建议 +- 命名规范 +- 编码规范 +- 框架规范 +- 插件规范 +- 数据库规范 +- 包功能规范 + +### 规范说明 + +- 开发规范意义是是让大家尽可能写出风格统一的代码,让团队代码有更好的可读性与可维护性。 +- 在实际业务开发中,除了要提高业务开发效率,保证线上业务高性能外,好的编程习惯也是一个开发人员基本素养之一。 + + +### 规范建议 + +- 在我们实际开发中,有很多开发人可能是由某一语言转到另外一个语言领域,在转到另外一门语言后, 我们都会保留着对旧语言的编程习惯,在这里,我建议的是,虽然不同语言之前的某些规范可能是相通的, 但是我们最好能够按照官方的一些demo来熟悉是渐渐适应当前语言的编程规范,而不是直接将原来语言的编程规范也随之迁移过来。 + + +### 命名规范 + + +#### 命名准则 + +* 当变量名称在定义和最后一次使用之间的距离很短时,简短的名称看起来会更好 +* 变量命名应尽量描述其内容,而不是类型 +* 常量命名应尽量描述其值,而不是如何使用这个值 +* 在遇到for,if等循环或分支时,推荐单个字母命名来标识参数和返回值 +* package名称也是命名的一部分,推荐全部使用小写,请尽量将其利用起来 +* 使用一致的命名风格 + +#### 文件命名规范 +* 全部小写 +* 除unit test外避免下划线(_) +* 文件名称不宜过长,但不必为了简短而忽略含义 + +#### 变量命名规范参考 +* 驼峰命名 +* 见名知义,避免拼音替代英文 +* 不建议包含下划线(_) +* 不建议包含数字 + + +#### 函数、常量命名规范 +* 驼峰式命名 +* 可导出的必须首字母大写 +* 不可导出的必须首字母小写 +* 避免全部大写与下划线(_)组合 + + +#### 参考文档 + +* [Practical Go: Real world advice for writing maintainable Go programs](https://dave.cheney.net/practical-go/presentations/gophercon-singapore-2019.html#_simplicity) + + +### 编码规范 + +#### import +* 单行import不建议用圆括号包裹 +* 按照`官方包`,NEW LINE,`当前工程包`,NEW LINE,`第三方依赖包`顺序引入 + +```go +import ( + "context" + "string" + + "greet/user/internal/config" + + "google.golang.org/grpc" +) +``` + +#### 函数返回 +* 对象避免非指针返回 +* 遵循有正常值返回则一定无error,有error则一定无正常值返回的原则 + +#### 错误处理 +* 有error必须处理,如果不能处理就必须抛出。 +* 避免下划线(_)接收error + +#### 函数体编码 +* 建议一个block结束空一行,如if、for等 + +```go + func main (){ + if x==1{ + // do something + } + + fmt.println("xxx") + } +``` +* return前尽可能空一行 + +```go +func getUser(id string)(string,error){ + .... + + return "xx",nil +} +``` + +### 框架规范 + +- 项目启动初始化方法都放在`server/internal/global/init.go`,插件放在:`server/addons/xxx插件/global/init.go` +- Api 对外接口层 都放在`server/api`,根据实际应用和应用具体功能划分子目录,插件放在:`server/addons/xxx插件/api` +- Router 路由注册方式应尽可能按gf2.0版本风格定义,参考:https://goframe.org/pages/viewpage.action?pageId=30736904 +- Controller 控制器层 都放在`server/internal/controller`,根据应用和具体功能拆分子目录,插件放在:`server/addons/xxx插件/controller` +- Input 对内接口层 都放在`server/internal/model/input`,根据应用和具体功能拆分子目录并以`in`结尾,插件放在:`server/addons/xxx插件/model/input` +- Logic 业务逻辑层 统一放在`server/internal/logic` 根据实际业务需求按logic/xxx/*.go拆分,插件放在:`server/addons/xxx插件/logic` +- Orm 模型实体层 统一放在`server/internal/model/entity` +- Dao 数据访问层 统一放在`server/internal/dao` +- 自定义工具函数都放在 `server/utility`,且应根据不同类型的方法做分包,相同类型的方法放在同一个包内 +- 状态枚举统一调用`server/internal/consts`中的常量和属性 + +### 插件规范 + +- 插件命名统一全部小写 +- 资源文件在 `addons/xxx插件/resource`或`server/resource` +- 每个插件之前应该是完全独立的,尽可能避免插件于插件之间的调用依赖 +- 插件和主模块之前的调用应尽可能通过 Service 接口来调用 +- 插件业务初始化顺序下应在主模块之后,应尽可能避免使用init方法隐式初始化 + +### 数据库规范 + +#### 命名规范 + +- 数据表名小写,多关键字使用下划线分割(关键字尽量全称) +- 字段名小写,多关键字使用下划线分割(关键字尽量全称) +- 禁止使用保留字并且尽量少用含有关键词来命名 +- 临时表必须以tmp_开头、以日期结尾,备份表必须以bak_开头、以日期结尾 +- 同数据库表名设置统一前缀,默认是`hg_` +- 插件模块表名建议以`hg_addon_`开头,如:`hg_addon_hgexample_table`,含义:`插件_案例_表格`。在生成代码时可自动识别实体命名为:`Table` + +#### 基础规范 + +- 所有的字段必须添加注释 +- 尽可能地使用InnoDB作为表的存储引擎 +- 所有的表和字段必须添加注释 +- 尽量控制表行数在500万以内 +- 尽可能采用冷热数据分离策略 +- 禁止以图片、文件等二进制数据 + +#### 表设计规范 + +- 尽可能每张表的索引数量控制在5个以内 +- 每一张InnoDB表都必须含有一个主键,自增主键必须是`bigint`类型 +- 尽可能避免使用外键约束 +- 设置数据表架构应考虑后期扩展型 +- 遵循范式与冗余平衡原则 + +#### 字段设计规范 + +- 尽可能将所有的数据列定义为 `NOT NULL` 类型 +- 避免 ENUM 数据类型 +- json 存储的数据用 `json`字段代替 `text` +- 表与表关联的键名保持一致或以关联表名的缩写为前缀 +- 固定长度的字符串字段务必使用 `char` +- 使用 `UNSIGNEG` 存储非负整数 +- 禁止敏感数据以明文形式存储 +- 金额相关的数据必须使用 `DECIMAL` 数据类型 +- 尽量所有表有 `status` 字段来标注数据状态(1:启用,2:禁用,3:已删除),业务状态请使用其他字段;`status`字段类型 为带符号的 `tinyint(1)`。如果还需要其他的数据状态 请先判断该状态的数据是有用的数据还是无意义的数据,有用的数据状态 > 0,无意义的数据状态 < -1 +- 所有的删除(除开清空回收站操作) 请标记 `status` 为 3 +- 创建时间字段为`created_at`,修改时间字段为`updated_at`,删除时间字段为`deleted_at`,类型`datetime` +- 用户关联 id 字段为 `member_id` 或 `created_by` +- 排序字段为 `sort` +- 区分应用字段为 `app_id` +- 区分插件来源需要增加字段为 `addon_name` 和 `is_addon` +- 关系树表中必须包含字段:`id`(主键)、`pid`(上级ID)、`level`(树等级)、`tree`(关系树) +- 多选、多图、多文件字段类型应尽量使用类型`json` + +### 包功能规范 + +##### Input(对内接口 - 过滤验证) + +- 接收Api 对外接口数据和参数过滤 +- 对提交的复杂数据参数进行验证处理返回 + +##### View(视图) + +- 数据处理显示 +- 页面渲染 + +##### Controller(控制器) + +- 数据接收 +- 服务调用 +- 简单CURD入库 +- 简单业务逻辑 + + +##### Logic(业务逻辑 - 服务接口功能) + +- 数据逻辑处理 +- 数据入库 +- 数据查询 \ No newline at end of file diff --git a/docs/guide-zh-CN/sys-i18n.md b/docs/guide-zh-CN/sys-i18n.md new file mode 100644 index 0000000..e3e7e73 --- /dev/null +++ b/docs/guide-zh-CN/sys-i18n.md @@ -0,0 +1,73 @@ +## 国际化 + + +目录 + +- 介绍 +- 配置文件 +- 服务端使用 +- Web端使用 +- 更多文档 + +### 介绍 + +从`v2.18.6`版本开始,HotGo 提供了完善的国际化(i18n)支持,内置简体中文、繁体中文和英文三种语言包,默认语言为简体中文。目前已对后台管理首页进行了多语言适配,开发者可基于该机制扩展实现业务模块的多语言功能。 + +### 配置文件 + +国际化配置位于 `server/manifest/config/config.yaml` 文件中: + +```yaml +# hotgo系统配置 +system: + # ... + # 国际化 + i18n: + switch: true # 国际化功能开关,可选值:false|true,默认:true + defaultLanguage: "zh-CN" # 默认语言,可选值:zh-CN|zh-TW|en,默认:zh-CN +``` + +### 服务端使用 + +多语言配置文件存放目录:`server/manifest/i18n`,您可以在该目录下添加自定义的语言映射文件。 + +**使用示例:** + +```go +// 设置当前上下文的语言为英文 +ctx := gctx.New() +gi18n.WithLanguage(ctx, "en") + +// 基础翻译 +gi18n.T(ctx, "你好,美丽世界") +// 输出:Hello, Beautiful World + +// 格式化翻译(支持参数替换) +gi18n.Tf(ctx, "剩余%v余额", 100) +// 输出:Remaining 100 Balance +``` + + +### Web端使用 + +多语言配置文件存放目录:`web/src/locale`,您可以在该目录下添加自定义的语言映射文件。 + +> 提示:启用国际化功能后,后台管理界面右上角将显示语言切换选项。 + +**使用示例(假设当前语言为英文):** + +```vue + +
{{ t('你好,美丽世界') }}
+ + + +
{{ t('剩余{num}余额', {num:100}) }}
+ +``` + + +### 更多文档 + +- [gi18n](https://goframe.org/docs/core/gi18n) +- [vie-i18n](https://vue-i18n.intlify.dev) \ No newline at end of file diff --git a/docs/guide-zh-CN/sys-library.md b/docs/guide-zh-CN/sys-library.md new file mode 100644 index 0000000..25255d9 --- /dev/null +++ b/docs/guide-zh-CN/sys-library.md @@ -0,0 +1,318 @@ +## 功能扩展库 + +目录 + +- 缓存驱动 +- 请求上下文 +- JWT +- 数据字典 +- 地理定位(待写) +- 通知(待写) + + +### 缓存驱动 + +> 系统默认的缓存驱动为file,目前已支持:memory|redis|file等多种驱动。请自行选择适合你的驱动使用。 + +- 配置文件:server/manifest/config/config.yaml + +```yaml +#缓存 +cache: + adapter: "file" # 缓存驱动方式,支持:memory|redis|file,不填默认memory + fileDir: "./storage/cache" # 文件缓存路径,adapter=file时必填 +``` + +#### 使用方式 +```go +package main + +import ( + "hotgo/internal/library/cache" + "github.com/gogf/gf/v2/os/gctx" +) + +func test() { + ctx := gctx.New() + + // 添加/修改 + cache.Instance().Set(ctx, "qwe", 123, 0) + + // 查询 + cache.Instance().Get(ctx, "qwe") + + // 删除 + cache.Instance().Remove(ctx, "qwe") + + // 更多方法请参考:https://goframe.org/pages/viewpage.action?pageId=27755640 +} + +``` + +### 请求上下文 + +- 主要用于在处理HTTP和websocket请求时通过中间件将用户、应用、插件等信息绑定到上下文中,方便在做业务处理时用到这些信息 + +```go +package admin + +import ( + "fmt" + "context" + "hotgo/internal/library/contexts" + "hotgo/internal/library/addons" +) + + +func test(ctx context.Context) { + // 获取当前请求的所有上下文变量 + var ctxModel = contexts.Get(ctx) + fmt.Printf("当前请求的所有上下文变量:%+v\n", ctxModel) + + // 获取当前请求的应用模块 + var module = contexts.GetModule(ctx) + fmt.Printf("当前请求的应用:%+v\n", module) + + // 获取当前请求的用户信息 + var member = contexts.GetUser(ctx) + fmt.Printf("当前访问用户信息:%+v\n", member) + + // 获取当前请求的插件模块 + fmt.Printf("当前是否为插件请求:%v", contexts.IsAddonRequest(ctx)) + if contexts.IsAddonRequest(ctx) { + fmt.Printf("当前插件名称:%v", contexts.GetAddonName(ctx)) + fmt.Printf("当前插件信息:%v", addons.GetModule(contexts.GetAddonName(ctx))) + } +} + +``` + +### JWT + +- 基于jwt+缓存驱动实现的用户登录令牌功能,支持自动续约,解决了jwt服务端无法退出问题和jwt令牌无法主动失效问题 + +#### 配置示例 +```yaml +# 登录令牌 +token: + secretKey: "hotgo123" # 令牌加密秘钥,考虑安全问题生产环境中请修改默认值 + expires: 604800 # 令牌有效期,单位:秒。默认7天 + autoRefresh: true # 是否开启自动刷新过期时间, false|true 默认为true + refreshInterval: 86400 # 刷新间隔,单位:秒。必须小于expires,否则无法触发。默认1天内只允许刷新一次 + maxRefreshTimes: 30 # 最大允许刷新次数,-1不限制。默认30次 + multiLogin: true # 是否允许多端登录, false|true 默认为true + +``` + +```go +package admin + +import ( + "fmt" + "context" + "hotgo/internal/library/token" + "hotgo/internal/model" +) + + +func test(ctx context.Context) { + // 登录 + user := &model.Identity{ + Id: mb.Id, + Pid: mb.Pid, + DeptId: mb.DeptId, + RoleId: ro.Id, + RoleKey: ro.Key, + Username: mb.Username, + RealName: mb.RealName, + Avatar: mb.Avatar, + Email: mb.Email, + Mobile: mb.Mobile, + App: consts.AppAdmin, + LoginAt: gtime.Now(), + } + + loginToken, expires, err := token.Login(ctx, user) + if err != nil { + return nil, err + } + + // gf请求对象 + r := *ghttp.Request + + // 获取登录用户信息 + user, err := token.ParseLoginUser(r) + if err != nil { + return + } + + // 注销登录 + err = token.Logout(r) +} + +``` + +### 数据字典 + +- hotgo增加了对枚举字典和自定义方法字典的内置支持,从而在系统中经常使用的一些特定数据上做出了增强。 + +#### 字典数据选项 +- 文件路径:server/internal/model/dict.go + +```go +package model + +// Option 字典数据选项 +type Option struct { + Key interface{} `json:"key"` + Label string `json:"label" description:"字典标签"` + Value interface{} `json:"value" description:"字典键值"` + ValueType string `json:"valueType" description:"键值数据类型"` + Type string `json:"type" description:"字典类型"` + ListClass string `json:"listClass" description:"表格回显样式"` +} +``` + +#### 枚举字典 +- 适用于系统开发期间内置的枚举数据,这样即维护了枚举值,又关联了数据字典 + +##### 一个例子 +- 定义枚举值和字典数据选项,并注册字典类型 +- 文件路径:server/internal/consts/credit_log.go + +```go +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +func init() { + dict.RegisterEnums("creditType", "资金变动类型", CreditTypeOptions) + dict.RegisterEnums("creditGroup", "资金变动分组", CreditGroupOptions) +} + +const ( + CreditTypeBalance = "balance" // 余额 + CreditTypeIntegral = "integral" // 积分 +) + +const ( + CreditGroupDecr = "decr" // 扣款 + CreditGroupIncr = "incr" // 加款 + CreditGroupOpDecr = "op_decr" // 操作扣款 + CreditGroupOpIncr = "op_incr" // 操作加款 + CreditGroupBalanceRecharge = "balance_recharge" // 余额充值 + CreditGroupBalanceRefund = "balance_refund" // 余额退款 + CreditGroupApplyCash = "apply_cash" // 申请提现 +) + +// CreditTypeOptions 变动类型 +var CreditTypeOptions = []*model.Option{ + dict.GenSuccessOption(CreditTypeBalance, "余额"), + dict.GenInfoOption(CreditTypeIntegral, "积分"), +} + +// CreditGroupOptions 变动分组 +var CreditGroupOptions = []*model.Option{ + dict.GenWarningOption(CreditGroupDecr, "扣款"), + dict.GenSuccessOption(CreditGroupIncr, "加款"), + dict.GenWarningOption(CreditGroupOpDecr, "操作扣款"), + dict.GenSuccessOption(CreditGroupOpIncr, "操作加款"), + dict.GenWarningOption(CreditGroupBalanceRefund, "余额退款"), + dict.GenSuccessOption(CreditGroupBalanceRecharge, "余额充值"), + dict.GenInfoOption(CreditGroupApplyCash, "申请提现"), +} + +``` + + +#### 自定义方法字典 +- 适用于非固定选项,如数据是从某个表/文件读取或从第三方读取,数据需要进行转换时使用 + +##### 方法字典接口 +- 文件路径:server/internal/consts/credit_log.go + +```go +package dict + +// FuncDict 方法字典,实现本接口即可使用内置方法字典 +type FuncDict func(ctx context.Context) (res []*model.Option, err error) +``` + +##### 一个例子 +- 定义获取字典数据方法,并注册字典类型 +- 文件路径:server/internal/logic/admin/post.go + +```go +package admin + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/consts" + "hotgo/internal/dao" + "hotgo/internal/library/dict" + "hotgo/internal/model" + "hotgo/internal/model/entity" + "hotgo/internal/service" +) + +type sAdminPost struct{} + +func NewAdminPost() *sAdminPost { + return &sAdminPost{} +} + +func init() { + service.RegisterAdminPost(NewAdminPost()) + dict.RegisterFunc("adminPostOption", "岗位选项", service.AdminPost().Option) +} + +// Option 岗位选项 +func (s *sAdminPost) Option(ctx context.Context) (opts []*model.Option, err error) { + var list []*entity.AdminPost + if err = dao.AdminPost.Ctx(ctx).OrderAsc(dao.AdminPost.Columns().Sort).Scan(&list); err != nil { + return nil, err + } + + if len(list) == 0 { + opts = make([]*model.Option, 0) + return + } + + for _, v := range list { + opts = append(opts, dict.GenHashOption(v.Id, v.Name)) + } + return +} +``` + +#### 代码生成支持 +- 内置的枚举字典和自定义方法字典在生成代码时可以直接进行选择,生成代码格式和系统字典管理写法一致 + +![最终编辑表单效果](images/sys-library-dict.png) + + +#### 内置字典和系统字典的区分 + +##### 主要区别 +- 系统字典由表:`hg_sys_dict_type`和`hg_sys_dict_data`共同进行维护,使用时需通过后台到字典管理中进行添加 +- 内置字典是系统开发期间在代码层面事先定义和注册好的数据选项 + + +##### 数据格式区别 +- 系统字典所有ID都是大于0的int64类型 +- 内置字典ID都是小于0的int64类型。枚举字典以20000开头,如:-200001381053496;方法字典以30000开头,如:-30000892528327;开头以外数字是根据数据选项的`key`值进行哈希算法得出 + +### 地理定位 +```go +// 待写 +``` + +### 通知 +```go +// 待写 +``` \ No newline at end of file diff --git a/docs/guide-zh-CN/sys-middleware.md b/docs/guide-zh-CN/sys-middleware.md new file mode 100644 index 0000000..70f334a --- /dev/null +++ b/docs/guide-zh-CN/sys-middleware.md @@ -0,0 +1,250 @@ +## 中间件/拦截器 + +目录 + +- 介绍 +- 全局中间件 +- 鉴权中间件 +- 响应中间件 +- 更多 + +### 介绍 +- 在hotgo中,中间件/拦截器主要作用于web请求的上下文预设、跨域请求处理、鉴权处理、请求拦截和请求结束后统一响应处理等。 + + +### 全局中间件 +```go +package main + +import ( + "hotgo/internal/service" +) + +func main() { + + // 初始化请求上下文,一般需要第一个进行加载,后续中间件存在依赖关系 + service.Middleware().Ctx() + + // 跨域中间件,自动处理跨域问题 + service.Middleware().CORS() + + // IP黑名单中间件,如果请求IP被后台拉黑,所有请求将被拒绝 + service.Middleware().Blacklist() + + // 演示系統操作限制,当开启演示模式时,所有POST请求将被拒绝 + service.Middleware().DemoLimit() + + // 请求输入预处理,api使用gf规范路由并且XxxReq结构体实现了validate.Filter接口即可隐式预处理 + service.Middleware().PreFilter() + + // HTTP响应预处理,在业务处理完成后,对响应结果进行格式化和错误过滤,将处理后的数据发送给请求方 + service.Middleware().ResponseHandler() + +} + +``` +### 鉴权中间件 +```go +package main + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +func main() { + + // 在鉴权中间件下的路由如果没有通过权限验证,后续请求将被拒绝 + // 在hotgo中,鉴权中间件一般是配合一个业务模块下的路由组进行使用 + // 目前admin、api、home、websocket模块都已接入 + // 如果你需要创建一个新的模块也需要用到鉴权中间件,可以参考:server/internal/logic/middleware/admin_auth.go + + + // 一个简单例子 + s := g.Server() + s.Group("/api", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().ApiAuth) + group.Bind( + member.Member, // 管理员 + ) + }) + +} + +``` + +### 响应中间件 +- 文件路径:server/internal/logic/middleware/response.go + + +#### 常用响应类型 + +- hotgo为一些常用的响应类型做了统一格式封装,例如:`application/json`、`text/xml`、`text/html`、`text/event-stream`等,默认使用`application/json`。 +- 下面我们以`text/xml`为例简单演示几种使用方法: + +1. 当你使用规范化路由时,可直接在XxxRes结构体的`g.Meta`中声明响应类型: + +```go +type HelloReq struct { + g.Meta `path:"/hello" tags:"Hello" method:"get" summary:"You first hello api"` + Name string `json:"name" d:"hotgo" dc:"名字"` +} + +type HelloRes struct { + g.Meta `mime:"text/xml" type:"string"` + Tips string `json:"tips"` +} +``` + +2. 在响应前设置响应头: + +```go +var ( + Hello = cHello{} +) + +type cHello struct{} + +func (c *cHello) Hello(ctx context.Context, req *user.HelloReq) (res *user.HelloRes, err error) { + r := ghttp.RequestFromCtx(ctx) + r.Response.Header().Set("Content-Type", "text/xml") + + res = &user.HelloRes{ + Tips: fmt.Sprintf("hello %v, this is the api for %v applications.", req.Name, simple.AppName(ctx)), + } + return +} +``` + +- 浏览器中访问响应内容如下: + +![./images/sys-middleware-com-response.png](./images/sys-middleware-com-response.png) + + +#### 自定义响应 +- 在实际开发中,可能需要使用自定义的响应类型,由于响应中间件是全局的,因此您需要对其进行单独处理。 +- 推荐以下几种处理方案,可做参考: +1. 使用`ghttp.ExitAll()`,需要注意的是此方法会终止后续所有的http处理 + +```go +package main + +import ( + "github.com/gogf/gf/v2/net/ghttp" +) + +func main() { + r := new(ghttp.Request) // 当前请求对象 + + // 清空响应 + r.Response.ClearBuffer() + + // 写入响应 + r.Response.Write("自定义响应内容") + + // 终止后续http处理 + r.ExitAll() +} +``` + +2. 在`server/internal/logic/middleware/response.go`中根据请求的独有特征进行单独的处理,兼容后续http处理。 + +#### 重写响应错误提示 +- 在实际开发中,我们可能想要隐藏一些敏感错误,返回给客户端友好的错误提示,但开发者同时又想需要看到真实的敏感错误。对此hotgo已经进行了过滤处理,下面是一个简单的例子: + +```go +package main + +import ( + "github.com/gogf/gf/v2/errors/gerror" +) + +func test() error { + err = gerror.New("这是一个sql执行错误") + err = gerror.Wrap(err, "用户创建失败,请稍后重试!~") + return err +} +``` + +- 开启debug时的客户端响应: +```json +{ + "code": -1, + "message": "用户创建失败,请稍后重试!~", + "error": [ + "1. 用户创建失败,请稍后重试!~", + " 1). hotgo/internal/logic/admin.(*sAdminMember).List", + " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526", + "2. 这是一个sql执行错误", " 1). hotgo/internal/logic/admin.(*sAdminMember).List", + " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:525", + " 2). hotgo/internal/controller/admin/admin.(*cMember).List", + " E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/controller/admin/admin/member.go:157", "" + ], + "timestamp": 1684145107, + "traceID": "084022730d495f17f19e550140f3e1a8" +} +``` + +- 关闭debug时的客户端响应: +```json +{ + "code": -1, + "message": "用户创建失败,请稍后重试!~", + "timestamp": 1684145107, + "traceID": "084022730d495f17f19e550140f3e1a8" +} +``` + +- 控制台的输出日志: + +```shell +2023-05-15 18:05:07.776 {084022730d495f17f19e550140f3e1a8} 200 "GET http localhost:8000 /admin/member/list?page=1&pageSize=10&roleId=-1 HTTP/1.1" 0.002, 127.0.0.1, "http://192.168.0.207:8001/login", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Co +re/1.94.197.400 QQBrowser/11.7.5287.400", -1, "", "" +Stack: +1. 用户创建失败,请稍后重试!~ + 1). hotgo/internal/logic/admin.(*sAdminMember).List + E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526 +2. 这是一个sql执行错误 + 1). hotgo/internal/logic/admin.(*sAdminMember).List + E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/response.go:24 + 13). hotgo/internal/logic/middleware.(*sMiddleware).DemoLimit + E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:90 + +``` + +- 如果你开启了访问日志,那么日志记录中会详细记录本次请求的相关信息,内容如下: +![./images/sys-middleware-error-log.png](./images/sys-middleware-error-log.png) + + +#### 重写错误码 +- hotgo默认使用了gf内置的错误码进行业务处理,通常情况下成功状态码为`0`,失败状态码为`-1` +- 查看gf内置错误码:https://goframe.org/pages/viewpage.action?pageId=30739587 +- 以下是自定义错误码的简单例子: + +```go +package main + +import ( + "github.com/gogf/gf/v2/errors/gerror" +) + +func test() error { + // 使用自定义状态码30001响应客户端 + err = gerror.NewCode(gcode.New(30001, "用户创建失败,请稍后重试!~", nil)) + return err +} +``` + + +- 客户端响应如下: +```json +{ + "code": 30001, + "message": "用户创建失败,请稍后重试!~", + "timestamp": 1684146313, + "traceID": "b4f90e16264a5f17cd3fc27141aba448" +} +``` + +### 更多 +- 更多关于中间件/拦截器的介绍请参考:https://goframe.org/pages/viewpage.action?pageId=55289881 + diff --git a/docs/guide-zh-CN/sys-payment.md b/docs/guide-zh-CN/sys-payment.md new file mode 100644 index 0000000..e102b23 --- /dev/null +++ b/docs/guide-zh-CN/sys-payment.md @@ -0,0 +1,102 @@ +## 支付网关 + +目录 + +- 介绍 +- 一个简单的支付流程 +- 支付配置 +- 创建支付订单 +- 注册支付回调 +- 订单退款 +- 单笔转账(待更新) +- 其他 + + +### 介绍 +> 在web应用开发中,支付功能可以做为不可或缺的一部分,HotGo提供了相对通用的支付网关,目前已支持支付宝、微信支付、QQ支付,包含创建支付订单、支付回调、订单退款等功能,开发者几乎只需关注订单业务处理即可。 + +#### 一个简单的支付流程 + +```mermaid + +graph TD + A(用户下单) --> B(创建订单
创建成功后,将订单支付信息提交到支付网关处理) + B -->|网关返回失败| H(提示错误) + B -->|网关返回成功| G(拿到支付链接,用户侧跳转支付页面) + G -->|支付完成| C(支付平台通知支付网关
支付网关进行验签和效验支付处理状态) -->|验证通过,回调订单业务| E(订单更新状态,发放业务产品) + G -->|支付取消| D(订单支付超时关闭) + + +``` + + +### 支付配置 +> 请到 系统设置 -> 配置管理 -> 支付配置 -> 找到你需要的支付方式,进行配置即可 + + + +### 创建支付订单 + +```go +package main + +func main() { + // 创建支付网关订单 + create, err := service.Pay().Create(ctx, payin.PayCreateInp{ + Subject: "充值100元", + OrderSn: "唯一业务订单编号", + OrderGroup: "admin_order", // 订单分组,用于订单分类和绑定支付成功的回调方法 + PayType: "wxpay", // 微信支付 + TradeType: "scan", // 二维码扫码 + PayAmount: "100", // 100元 + }) +} +``` + + +### 注册支付回调 +- 在文件`server/internal/logic/pay/notify.go` 加入你的业务订单分组回调方法,当订单支付成功验签通过后会自动进行回调,参考以下: + +```go +package global + +import ( + "hotgo/internal/consts" + "hotgo/internal/library/payment" + "hotgo/internal/service" +) + +// RegisterNotifyCall 注册支付成功回调方法 +func (s *sPay) RegisterNotifyCall() { + payment.RegisterNotifyCallMap(map[string]payment.NotifyCallFunc{ + consts.OrderGroupAdminOrder: service.AdminOrder().PayNotify, // 后台充值订单 + // ... + }) +} +``` + +### 订单退款 + + +```go +package main + +func main() { + refund, err := service.PayRefund().Refund(ctx, payin.PayRefundInp{ + OrderSn: "唯一业务订单编号", + RefundMoney: "退款金额", + Reason: "买家申请退款原因", + Remark: "商家同意退款备注", + }) +} +``` + + +### 单笔转账(待更新) + + + +### 其他 +- 由于各个支付平台中交易方式较多,如果目前已有的交易方式不满足你的支付场景需求,请自行参考gopay文档对文件`server/internal/library/payment/payment.go`中的`PayClient`接口实现进行扩展 +- gopay文档地址:https://github.com/go-pay/gopay + diff --git a/docs/guide-zh-CN/sys-queue.md b/docs/guide-zh-CN/sys-queue.md new file mode 100644 index 0000000..e124805 --- /dev/null +++ b/docs/guide-zh-CN/sys-queue.md @@ -0,0 +1,203 @@ +## 消息队列 + +目录 + +- 配置文件 +- 实现接口 +- 一个例子 +- 控制台 +- 自定义队列驱动 + +> 系统默认的队列驱动为disk(磁盘队列),目前已支持:disk、redis、rocketmq、kafka等多种驱动。请自行选择适合你的驱动使用。 + +### 配置文件 +- 配置文件:server/manifest/config/config.yaml + +```yaml +# 消息队列 +queue: + switch: true # 队列开关,可选:true|false,默认为true + driver: "disk" # 队列驱动,可选:disk|redis|rocketmq|kafka,默认为disk + groupName: "hotgo" # mq群组名称 + # 磁盘队列 + disk: + path: "./storage/diskqueue" # 数据存放路径 + batchSize: 100 # 每100条消息同步一次,batchSize和batchTime满足其一就会同步一次 + batchTime: 1 # 每1秒消息同步一次 + segmentSize: 10485760 # 每个topic分片数据文件最大字节,默认10M + segmentLimit: 3000 # 每个topic最大分片数据文件数量,超出部分将会丢弃 + # redis,默认使用全局redis运行队列 + redis: + timeout: 0 # 队列超时时间以秒为单位,0表示永不超时。如果队列在设定的超时时间内没有被消费,则会被销毁 + rocketmq: + nameSrvAdders: ["127.0.0.1:9876"] # nameSrvAdder+端口,支持多个 + accessKey: "" # 选填。如果开启了acl控制就必填 + secretKey: "" # 选填。如果开启了acl控制就必填 + brokerAddr: "127.0.0.1:10911" # brokerAddr+端口,选填。用于消费者订阅主题前会检查主题是否存在,不存在会自动创建。你也可以在rocketmq控制台手动创建主题 + retry: 0 # 重试次数 + logLevel: "info" # 系统日志级别,可选:all|close|debug|info|warn|error|fatal + kafka: + address: "127.0.0.1:9092" # kafka地址+端口 + version: "2.0.0.0" # kafka专属配置,默认2.0.0.0 + randClient: true # 开启随机生成clientID,可以实现启动多实例同时一起消费相同topic,加速消费能力的特性,默认为true + multiConsumer: true # 是否支持创建多个消费者 +``` + +### 实现接口 +- 为了提供高度的扩展性,消费队列在设计上采用了接口化的思路。只需要实现以下接口,您就可以在任何地方注册和使用消费队列消费功能,从而实现更大的灵活性和可扩展性。 + +```go +// Consumer 消费者接口,实现该接口即可加入到消费队列中 +type Consumer interface { + GetTopic() string // 获取消费主题 + Handle(ctx context.Context, mqMsg MqMsg) (err error) // 处理消息的方法 +} +``` + + +### 一个例子 + +每个被发送到队列的消息应该被定义为一个单独的文件结构。 + +例如,如果您需要异步记录系统日志,内容大致如下: + +- 文件路径:server/internal/queues/sys_log.go + +```go +package queues + +import ( + "context" + "encoding/json" + "hotgo/internal/consts" + "hotgo/internal/library/queue" + "hotgo/internal/model/entity" + "hotgo/internal/service" +) + +func init() { + queue.RegisterConsumer(SysLog) +} + +// SysLog 系统日志 +var SysLog = &qSysLog{} + +type qSysLog struct{} + +// GetTopic 主题 +func (q *qSysLog) GetTopic() string { + return consts.QueueLogTopic +} + +// Handle 处理消息 +func (q *qSysLog) Handle(ctx context.Context, mqMsg queue.MqMsg) (err error) { + var data entity.SysLog + if err = json.Unmarshal(mqMsg.Body, &data); err != nil { + return err + } + return service.SysLog().RealWrite(ctx, data) +} + +``` + +下面是将消息添加到队列的方式,大概内容如下: + +```go +package main + +import ( + "fmt" + "hotgo/internal/consts" + "hotgo/internal/library/queue" + "hotgo/internal/model/entity" +) + +func test() { + data := &entity.SysLog{ + //... + } + if err := queue.Push(consts.QueueLogTopic, data); err != nil { + fmt.Printf("queue.Push err:%+v", err) + } +} + +``` + +延迟队列,目前只有redis、rocketmq驱动支持: + +```go +package main + +import ( + "fmt" + "hotgo/internal/consts" + "hotgo/internal/library/queue" + "hotgo/internal/model/entity" +) + +func test() { + data := &entity.SysLog{ + //... + } + + // redis 延迟10秒 + if err := queue.SendDelayMsg(consts.QueueLogTopic, data, 10); err != nil { + fmt.Printf("queue.Push err:%+v", err) + } + + // rocketmq 延迟5秒 + // 注意rocketmq这里传入的是延迟级别,而不是秒 + // 消息的延时级别level一共有18级,分别为: + // 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h + // 参考:https://github.com/apache/rocketmq-client-go/blob/0e19ee654819bda396a08d950c883f9008b8222b/primitive/message.go#L174 + if err := queue.SendDelayMsg(consts.QueueLogTopic, data, 2); err != nil { + fmt.Printf("queue.Push err:%+v", err) + } +} + +``` + +### 控制台 + +控制台用于处理队列消息,即消费者。 + +相关命令请参考: [控制台](sys-console.md) + + +### 自定义队列驱动 + +只需实现消息队列的生成者和消费者接口,并加入到初始化中进行相应调用即可。 + +- 接口片段:server/internal/library/queue/init.go + +```go +package queue + +import ( + "time" +) + +type MqMsg struct { + RunType int `json:"run_type"` + Topic string `json:"topic"` + MsgId string `json:"msg_id"` + Offset int64 `json:"offset"` + Partition int32 `json:"partition"` + Timestamp time.Time `json:"timestamp"` + Body []byte `json:"body"` +} + +type MqProducer interface { + SendMsg(topic string, body string) (mqMsg MqMsg, err error) + SendByteMsg(topic string, body []byte) (mqMsg MqMsg, err error) + SendDelayMsg(topic string, body string, delay int64) (mqMsg MqMsg, err error) +} + +type MqConsumer interface { + ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg)) (err error) +} + +``` + +将实现过接口(MqProducer、MqConsumer)的实例方法分别加入到NewProducer、NewConsumer中进行相应调用即可。 + diff --git a/docs/guide-zh-CN/sys-tcp-server.md b/docs/guide-zh-CN/sys-tcp-server.md new file mode 100644 index 0000000..6f81a5b --- /dev/null +++ b/docs/guide-zh-CN/sys-tcp-server.md @@ -0,0 +1,271 @@ +## TCP服务器 + +目录 + +- 配置文件 +- 一个基本的消息收发例子 +- 注册路由 +- 拦截器 +- 服务认证 +- 更多 + +> HotGo基于GoFrame的TCP服务器组件,提供了一个简单而灵活的方式快速搭建基于TCP的服务应用。集成了许多常用功能,如长连接、服务认证、路由分发、RPC消息、拦截器和数据绑定等,大大简化和规范了服务器开发流程。 + +### 配置文件 +- 配置文件:server/manifest/config/config.yaml + +```yaml +tcp: + # 服务器 + server: + address: ":8099" + # 客户端 + client: + # 定时任务 + cron: + group: "cron" # 分组名称 + name: "cron1" # 客户端名称 + address: "127.0.0.1:8099" # 服务器地址 + appId: "1002" # 应用名称 + secretKey: "hotgo" # 密钥 + # 系统授权 + auth: + group: "auth" # 分组名称 + name: "auth1" # 客户端名称 + address: "127.0.0.1:8099" # 服务器地址 + appId: "mengshuai" # 应用名称 + secretKey: "123456" # 密钥 + +``` +- 可以看到,除了服务器配置外,还有两个客户端配置`cron` 和`auth` +- `cron`是HotGo内置的定时任务服务,和http服务通过RPC通讯以实现和后台交互,使其可以独立、集群部署。 +- `auth`可以为第三方平台提供授权服务。如果你需要他,可以将它部署在第三方程序中,在重要的位置进行授权验证。 + +### 一个基本的消息收发测试用例 + +- 文件路径:server/internal/library/network/tcp/tcp_example_test.go + +```go +package tcp_test + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/test/gtest" + "hotgo/internal/library/network/tcp" + "testing" + "time" +) + +var T *testing.T // 声明一个全局的 *testing.T 变量 + +type TestMsgReq struct { + Name string `json:"name"` +} + +type TestMsgRes struct { + tcp.ServerRes +} + +type TestRPCMsgReq struct { + Name string `json:"name"` +} + +type TestRPCMsgRes struct { + tcp.ServerRes +} + +func onTestMsg(ctx context.Context, req *TestMsgReq) { + fmt.Printf("服务器收到消息 ==> onTestMsg:%+v\n", req) + conn := tcp.ConnFromCtx(ctx) + gtest.C(T, func(t *gtest.T) { + t.AssertNE(conn, nil) + }) + + res := new(TestMsgRes) + res.Message = fmt.Sprintf("你的名字:%v", req.Name) + conn.Send(ctx, res) +} + +func onResponseTestMsg(ctx context.Context, req *TestMsgRes) { + fmt.Printf("客户端收到响应消息 ==> TestMsgRes:%+v\n", req) + err := req.GetError() + gtest.C(T, func(t *gtest.T) { + t.AssertNil(err) + }) +} + +func onTestRPCMsg(ctx context.Context, req *TestRPCMsgReq) (res *TestRPCMsgRes, err error) { + fmt.Printf("服务器收到消息 ==> onTestRPCMsg:%+v\n", req) + res = new(TestRPCMsgRes) + res.Message = fmt.Sprintf("你的名字:%v", req.Name) + return +} + +func startTCPServer() { + serv := tcp.NewServer(&tcp.ServerConfig{ + Name: "hotgo", + Addr: ":8002", + }) + + // 注册路由 + serv.RegisterRouter( + onTestMsg, + ) + + // 注册RPC路由 + serv.RegisterRPCRouter( + onTestRPCMsg, + ) + + // 服务监听 + err := serv.Listen() + gtest.C(T, func(t *gtest.T) { + t.AssertNil(err) + }) +} + +// 一个基本的消息收发 +func TestSendMsg(t *testing.T) { + T = t + go startTCPServer() + + ctx := gctx.New() + client := tcp.NewClient(&tcp.ClientConfig{ + Addr: "127.0.0.1:8002", + }) + + // 注册路由 + client.RegisterRouter( + onResponseTestMsg, + ) + + go func() { + err := client.Start() + gtest.C(T, func(t *gtest.T) { + t.AssertNil(err) + }) + }() + + // 确保服务都启动完成 + time.Sleep(time.Second * 1) + + // 拿到客户端的连接 + conn := client.Conn() + gtest.C(T, func(t *gtest.T) { + t.AssertNE(conn, nil) + }) + + // 向服务器发送tcp消息,不会阻塞程序执行 + err := conn.Send(ctx, &TestMsgReq{Name: "Tom"}) + gtest.C(T, func(t *gtest.T) { + t.AssertNil(err) + }) + + // 向服务器发送rpc消息,会等待服务器响应结果,直到拿到结果或响应超时才会继续 + var res TestRPCMsgRes + if err = conn.RequestScan(ctx, &TestRPCMsgReq{Name: "Tony"}, &res); err != nil { + gtest.C(T, func(t *gtest.T) { + t.AssertNil(err) + }) + } + + fmt.Printf("客户端收到RPC消息响应 ==> TestRPCMsgRes:%+v\n", res) + time.Sleep(time.Second * 1) +} + +``` + + +### 注册路由 + +- 从上面的例子可以看到,不管是普通TCP消息和RPC消息的请求/响应结构体都采用类似GF框架的规范路由的结构,请求`XxxRes`/响应`XxxRes`的格式,是不是很亲切? + + +### 拦截器 + +- 不管是服务端还是客户端,在初始化时都可以注册多个拦截器来满足更多场景的服务开发,下面是一个使用例子: + +```go +package main + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/library/network/tcp" +) + +func main() { + serv = tcp.NewServer(&tcp.ServerConfig{ + Name: "hotgo", + Addr: ":8002", + }) + + // 注册拦截器 + // 执行顺序是从前到后,即Interceptor -> Interceptor2 -> Interceptor3。如果中间有任意一个抛出错误,则会中断后续处理 + serv.RegisterInterceptor(Interceptor, Interceptor2, Interceptor3) + + // 服务监听 + if err := serv.Listen(); err != nil { + if !serv.IsClose() { + g.Log().Warningf(ctx, "TCPServer Listen err:%v", err) + } + } +} + +func Interceptor(ctx context.Context, msg *tcp.Message) (err error) { + // 可以在拦截器中通过上下文拿到连接 + conn := tcp.ConnFromCtx(ctx) + + // 拿到原始请求消息 + g.Dump(msg) + + // 如果想要中断后续处理只需返回一个错误即可,但注意两种情况 + // tcp消息:如果你还想对该消息进行回复应在拦截器中进行处理,例如:conn.Send(ctx, 回复消息内容) + // rpc消息:返回一个错误后系统会将错误自动回复到rpc响应中,无需单独处理 + return +} + +func Interceptor2(ctx context.Context, msg *tcp.Message) (err error) { + // ... + return +} + +func Interceptor3(ctx context.Context, msg *tcp.Message) (err error) { + // ... + return +} + +``` + + +### 服务认证 + +- 一般情况下,建议客户端连接到服务器时都通过`授权许可证`的方式进行登录认证,当初始化客户端配置认证数据时,连接成功后会自动进行登录认证。 + +```go + // 创建客户端配置 + clientConfig := &tcp.ClientConfig{ + Addr: "127.0.0.1:8002", + AutoReconnect: true, + // 认证数据 + // 认证数据可以在后台-系统监控-在线服务-许可证列表中添加,同一个授权支持多个服务使用,但多个服务不能使用相同的名称进行连接 + Auth: &tcp.AuthMeta{ + Name: "服务名称", + Group: "服务分组", + AppId: "APPID", + SecretKey: "SecretKey", + }, + } + + // 初始化客户端 + client = tcp.NewClient(clientConfig) +``` + + +### 更多 + +TCP服务器源码路径:server/internal/library/network/tcp + +更多文档请参考:https://goframe.org/pages/viewpage.action?pageId=1114625 diff --git a/docs/guide-zh-CN/sys-tenant.md b/docs/guide-zh-CN/sys-tenant.md new file mode 100644 index 0000000..6c97d79 --- /dev/null +++ b/docs/guide-zh-CN/sys-tenant.md @@ -0,0 +1,175 @@ +## SaaS多租户 + + +目录 + +- 介绍 +- 职责划分 +- 如何在HotGo开发多租户业务 +- 多租户数据库设计 +- 多租户功能演示 + +### 介绍 + +SaaS系统多租户多应用设计,已成为互联网企业的重要发展建设方向。核心在于多租户SAAS系统独立前台、共享后台、共享数据库的平台应用架构。 + +> 目前HotGo的部分基础功能并不完全支持多租户设计,但这并不妨碍开发者基于HotGo构建自己的多租户产品 + + +### 职责划分 + +在SaaS系统多租户中,不同身份用户的职责功能划分假设可以是这样: + +> 这只是一个粗略的概念,实际开发时应根据业务来进行调整,每个身份也都不是必须的。 + +| 身份 | 标识 | 职责和功能划分 | +|-----------------|----------|-------------------------------------------------------| +| 公司| company | 管理整个平台,包括商户和用户账户、系统设置以及其他全局性业务流程。 | +| 租户 | tenant | 多租户系统中顶层实体客户、组织或实体。有自己的多个商户、用户、产品、订单等。拥有独立的数据隔离和安全边界。 | +| 商户 | merchant | 受租户的监管和管理,可独立经营的实体。提供产品或服务,管理自己的业务,包括库存管理、订单处理、结算等。 | +| 用户 | user | 真正购买产品或享受服务的人,与商户互动,管理个人信息等个性化功能。 | + + +### 如何在HotGo开发多租户业务 +#### 一、应用功能 + +根据角色来划分用户的后台功能,在创建用户时为其绑定角色,然后为不同角色分配不同的功能菜单 + +请参考: [权限控制](sys-auth.md) + + +#### 二、 数据隔离 + +根据部门来划定用户的数据权限范围,在创建用户时为其绑定部门 + +- 在用户登录成功后,server端可通过上下文来获取用户部门类型来确定用户身份 +- 文件路径:server/internal/library/contexts/context.go + +```go +package contexts + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "hotgo/internal/consts" + "hotgo/internal/model" +) + +// GetDeptType 获取用户部门类型 +func GetDeptType(ctx context.Context) string { + user := GetUser(ctx) + if user == nil { + return "" + } + return user.DeptType +} + +// IsCompanyDept 是否为公司部门 +func IsCompanyDept(ctx context.Context) bool { + return GetDeptType(ctx) == consts.DeptTypeCompany +} + +// IsTenantDept 是否为租户部门 +func IsTenantDept(ctx context.Context) bool { + return GetDeptType(ctx) == consts.DeptTypeTenant +} + +// IsMerchantDept 是否为商户部门 +func IsMerchantDept(ctx context.Context) bool { + return GetDeptType(ctx) == consts.DeptTypeMerchant +} + +// IsUserDept 是否为普通用户部门 +func IsUserDept(ctx context.Context) bool { + return GetDeptType(ctx) == consts.DeptTypeUser +} +``` + +- 在用户登录成功后,web端可通`useUserStore`来获取用户部门类型来确定用户身份 +- 文件路径:web/src/store/modules/user.ts + +```vue + +``` + +### 多租户数据库设计 + +HotGo定位是中小型应用开发,推荐采用一套数据库不同Schema。就是在多租户业务表中加入用户标识字段,来区分不同用户的数据,如:`tenant_id` + +- 参考文章:https://blog.csdn.net/haponchang/article/details/104246317 + + +### 多租户功能演示 + +请登录后台【插件应用】-【功能案例】-【多租户功能演示】查看 + +#### 自动维护租户关系 + +- 只需在表设计时包含以下字段,即可使用handler和hook实现租户权限过滤和租户关系维护 + +| 字段名称 | 数据类型 | 字段注释 | 必选 | +|------|----------|------|-----------------------------------------------------| +| tenant_id | bigint(20) | 租户ID | 否 | +| merchant_id | bigint(20) | 商户ID | 否 | +| user_id | bigint(20) | 用户ID | 否 | + +下面是多租户功能演示例子代码中的使用片段 + +- 封装查询Model + +```go +// Model 多租户功能演示ORM模型 +func (s *sSysTenantOrder) Model(ctx context.Context, option ...*handler.Option) *gdb.Model { + if len(option) == 0 { + // 过滤多租户数据权限 + option = append(option, &handler.Option{ + FilterTenant: true, + //FilterAuth: true, // 如果还需要维护created_by、member_id等部门数据权限范围可放开注释 + }) + } + return handler.Model(dao.AddonHgexampleTenantOrder.Ctx(ctx), option...) +} +``` + +- 增改数据自动维护租户关系 +```go +// Edit 修改/新增多租户功能演示 +func (s *sSysTenantOrder) Edit(ctx context.Context, in *sysin.TenantOrderEditInp) (err error) { + return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) { + + // 修改 + if in.Id > 0 { + if _, err = s.Model(ctx). + Fields(sysin.TenantOrderUpdateFields{}). + WherePri(in.Id).Data(in). + Hook(hook.SaveTenant). // 自动维护租户关系更新 + Update(); err != nil { + } + return + } + + // 新增 + if _, err = dao.AddonHgexampleTenantOrder.Ctx(ctx). + Fields(sysin.TenantOrderInsertFields{}). + Hook(hook.SaveTenant). // 自动维护租户关系更新 + Data(in). + Insert(); err != nil { + } + return + }) +} +``` + +相关代码文件:/server/addons/hgexample/logic/sys/tenant_order.go + diff --git a/docs/guide-zh-CN/sys-test.md b/docs/guide-zh-CN/sys-test.md new file mode 100644 index 0000000..26a1681 --- /dev/null +++ b/docs/guide-zh-CN/sys-test.md @@ -0,0 +1,3 @@ +## 单元测试 + +请参考:https://goframe.org/pages/viewpage.action?pageId=1114153 \ No newline at end of file diff --git a/docs/guide-zh-CN/sys-utility.md b/docs/guide-zh-CN/sys-utility.md new file mode 100644 index 0000000..4a66582 --- /dev/null +++ b/docs/guide-zh-CN/sys-utility.md @@ -0,0 +1,20 @@ +## 工具方法 + +HotGo还提供一些系统中常用的工具库方法,在这里简单说明: + +``` +/server +├── utility +│ ├── charset # 字符串处理 +│ ├── convert # 数据类型转换 +│ ├── encrypt # 数据加密/解密 +│ ├── excel # 电子表格导出/导入 +│ ├── file # 文件/目录处理 +│ ├── format # 数据格式化 +│ ├── simple # 一些简捷函数 +│ ├── tree # 树形结构 +│ ├── url # URL处理 +│ ├── useragent # 请求头代理处理 +└── └── validate # 数据验证 +``` + diff --git a/docs/guide-zh-CN/sys-webhook.md b/docs/guide-zh-CN/sys-webhook.md new file mode 100644 index 0000000..ef5d21e --- /dev/null +++ b/docs/guide-zh-CN/sys-webhook.md @@ -0,0 +1,3 @@ +## WebHook + +请参考:https://goframe.org/pages/viewpage.action?pageId=1114387 diff --git a/docs/guide-zh-CN/sys-websocket-client.md b/docs/guide-zh-CN/sys-websocket-client.md new file mode 100644 index 0000000..517c5e8 --- /dev/null +++ b/docs/guide-zh-CN/sys-websocket-client.md @@ -0,0 +1,213 @@ +## WebSocket客户端 + +目录 + +- 全局消息监听 +- 单页面消息监听 +- 发送消息 + +> 基于WebSocket服务器,hotgo还对客户端的上做了一些封装,使其使用起来更加方便 +- [WebSocket服务器](sys-websocket-server.md) + +### 全局消息监听 +- 所有全局的消息监听都在这里 +- 文件路径:web/src/utils/websocket/registerMessage.ts + +```ts +import { TABS_ROUTES } from '@/store/mutation-types'; +import { SocketEnum } from '@/enums/socketEnum'; +import { useUserStoreWidthOut } from '@/store/modules/user'; +import { notificationStoreWidthOut } from '@/store/modules/notification'; +import { addOnMessage, WebSocketMessage } from '@/utils/websocket/index'; + +// 注册全局消息监听 +export function registerGlobalMessage() { + // 心跳 + addOnMessage(SocketEnum.EventPing, function (_message: WebSocketMessage) { + // console.log('ping..'); + }); + + // 强制退出 + addOnMessage(SocketEnum.EventKick, function (_message: WebSocketMessage) { + const useUserStore = useUserStoreWidthOut(); + useUserStore.logout().then(() => { + // 移除标签页 + localStorage.removeItem(TABS_ROUTES); + location.reload(); + }); + }); + + // 消息通知 + addOnMessage(SocketEnum.EventNotice, function (message: WebSocketMessage) { + const notificationStore = notificationStoreWidthOut(); + notificationStore.triggerNewMessages(message.data); + }); + + // 更多全局消息处理都可以在这里注册 + // ... +} + +``` + +#### 单页面消息监听 +- 当你只需要某个页面使用WebSocket,这将是一个不错的选择,下面是一个简单的演示例子 +- 文件路径:web/src/views/addons/hgexample/portal/websocketTest.vue + +```vue + + + + + +``` + +#### 发送消息 +- 向服务器发送一条消息 + +```ts + import { sendMsg } from '@/utils/websocket'; + + const event = 'admin/addons/hgexample/testMessage'; // 消息路由 + const data: object | null = { // 消息内容 + message: 'message content...', + }; + const isRetry = false; // 发送失败是否重试,不传默认为true + + // 基本使用 + sendMsg(event, data); + + // 无消息内容 + sendMsg(event); + + // 发送失败不重试 + sendMsg(event, data, isRetry); +``` diff --git a/docs/guide-zh-CN/sys-websocket-server.md b/docs/guide-zh-CN/sys-websocket-server.md new file mode 100644 index 0000000..1e6db23 --- /dev/null +++ b/docs/guide-zh-CN/sys-websocket-server.md @@ -0,0 +1,148 @@ +## WebSocket服务器 + +目录 + +- 一个基本的消息收发例子 +- 常用方法 +- HTTP接口 +- 其他 + +> hotgo提供了一个WebSocket服务器,随`HTTP服务`启停。集成了许多常用功能,如JWT身份认证、路由消息处理器、一对一消息/群组消息/广播消息、在线用户管理、心跳保持等,大大简化和规范了WebSocket服务器的开发流程。 +- [Websocket客户端](sys-websocket-client.md) + +### 一个基本的消息收发例子 +- 这是一个基本的消息接收并进行处理的简单例子 + +#### 1.消息处理接口 +- 消息处理在设计上采用了接口化的思路。只需要实现以下接口,即可进行WebSocket消息注册 +- 文件路径:server/internal/websocket/model.go + +```go +package websocket + +// EventHandler 消息处理器 +type EventHandler func(client *Client, req *WRequest) +``` + +#### 2.定义消息处理方法 +- 以下是功能案例中的一个简单演示,实现了消息处理接口,并将收到的消息原样发送给客户端 +- 文件路径:server/addons/hgexample/controller/websocket/handler/index.go + +```go +package handler + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/websocket" +) + +var ( + Index = cIndex{} +) + +type cIndex struct{} + +// TestMessage 测试消息 +func (c *cIndex) TestMessage(client *websocket.Client, req *websocket.WRequest) { + g.Log().Infof(client.Context(), "收到客户端测试消息:%v", gjson.New(req).String()) + // 将收到的消息原样发送给客户端 + websocket.SendSuccess(client, req.Event, req.Data) +} +``` + +#### 3.注册消息 +- 定义消息处理方法后,需要将其注册到WebSocket消息处理器,一般放在对应应用模块的`router/websocket.go`下即可 +- 文件路径:server/addons/hgexample/router/websocket.go + +```go +package router + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "hotgo/addons/hgexample/controller/websocket" + "hotgo/addons/hgexample/controller/websocket/handler" + ws "hotgo/internal/websocket" +) + +// WebSocket ws路由配置 +func WebSocket(ctx context.Context, group *ghttp.RouterGroup) { + // 注册消息路由 + ws.RegisterMsg(ws.EventHandlers{ + "admin/addons/hgexample/testMessage": handler.Index.TestMessage, // 测试消息 + }) + + // 这里"admin/addons/hgexample/testMessage"代表的是一个消息处理ID,可以自定义。建议的格式是和HTTP接口格式保持一致,这样还可以便于对用户请求的消息进行权限验证 + // 客户端连接后,向WebSocket服务器发送event为"admin/addons/hgexample/testMessage"的消息时,会调用TestMessage方法 +} +``` + +- 到此,你已了解了WebSocket消息接收并进行处理的基本流程 + + +### 常用方法 +- websocket服务器还提供了一些常用的方法,下面只对部分进行说明 + +```go +func test() { + websocket.SendToAll() // 发送全部客户端 + websocket.SendToClientID() // 发送单个客户端 + websocket.SendToUser() // 发送单个用户 + websocket.SendToTag() // 发送某个标签、群组 + + client := websocket.Manager().GetClient(id) // 通过连接ID获取客户端连接 + client := websocket.Manager().GetUserClient(userId) // 通过用户ID获取客户端连接,因为用户是可多端登录的,这里返回的是一个切片 + + websocket.SendSuccess(client, "admin/addons/hgexample/testMessage", "消息内容") // 向指定客户端发送一条成功的消息 + websocket.SendError(client, "admin/addons/hgexample/testMessage", gerror.New("错误内容")) // 向指定客户端发送一条失败的消息 + +} +``` + + +### HTTP接口 +- 你还可以通过http接口方式调用WebSocket发送消息 +- 参考文件:server/internal/controller/websocket/send.go + + +### 其他 +- WebSocket被连接时需验证用户认证中间件,所以用户必须登录成功后才能连接成功 +- 参考文件:server/internal/logic/middleware/weboscket_auth.go + +```go +package middleware + +import ( + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/text/gstr" + "hotgo/internal/consts" + "hotgo/internal/library/response" + "hotgo/utility/simple" +) + +// WebSocketAuth websocket鉴权中间件 +func (s *sMiddleware) WebSocketAuth(r *ghttp.Request) { + var ( + ctx = r.Context() + path = gstr.Replace(r.URL.Path, simple.RouterPrefix(ctx, consts.AppWebSocket), "", 1) + ) + + // 不需要验证登录的路由地址 + if s.IsExceptLogin(ctx, consts.AppWebSocket, path) { + r.Middleware.Next() + return + } + + // 将用户信息传递到上下文中 + if err := s.DeliverUserContext(r); err != nil { + response.JsonExit(r, gcode.CodeNotAuthorized.Code(), err.Error()) + return + } + + r.Middleware.Next() +} +``` + +- 如果您不要求用户进行登录即可使用 WebSocket,那么需要对身份验证中间件进行修改。然而,这样做会降低连接的安全性,并且无法应用于需要确定用户身份的情景,因此并不建议采取这种策略 diff --git a/docs/guide-zh-CN/web-deploy.md b/docs/guide-zh-CN/web-deploy.md new file mode 100644 index 0000000..51bc603 --- /dev/null +++ b/docs/guide-zh-CN/web-deploy.md @@ -0,0 +1,261 @@ +## 独立部署 + +目录 + +- 构建 +- 旧版浏览器兼容 +- 预览 +- 分析构建文件体积 +- 压缩 +- 部署 + +> 在实际开发中,web前端也可能需要独立部署,所以在此提供一下部署方案。 + +### 构建 + +项目开发完成之后,执行以下命令进行构建 +```shell +pnpm run build 或 npm run build +``` +构建打包成功之后,会在根目录生成 dist 文件夹,里面就是构建打包好的文件 + + +### 旧版浏览器兼容 + +在 .env.production 内 + +设置 `VITE_LEGACY=true` 即可打包出兼容旧版浏览器的代码 +```shell +VITE_LEGACY = true +``` + + + +### 预览 + +发布之前可以在本地进行预览,有多种方式,这里介绍两种 + +##### 不能直接打开构建后的 html 文件 + +使用项目自定的命令进行预览(推荐) +```shell +# 先打包在进行预览 +pnpm run preview 或 npm run preview +# 直接预览本地 dist 文件目录 +pnpm run preview:dist 或 npm run preview:dist +``` + +- 本地服务器预览(通过 live-server) +```shell +# 1.全局安装live-server +npm -g install live-server +# 2. 进入打包的后目录 +cd ./dist +# 本地预览,默认端口8080 +live-server +# 指定端口 +live-server --port 9000 +``` + +### 分析构建文件体积 +如果你的构建文件很大,可以通过项目内置 [rollup-plugin-analyzer](https://github.com/doesdev/rollup-plugin-analyzer) 插件进行代码体积分析,从而优化你的代码。 +```shell +pnpm run report 或 npm run report +``` +运行之后,在自动打开的页面可以看到具体的体积分布,以分析哪些依赖有问题。 + +- 左上角可以切换 显示 gzip 或者 brotli + +![start-deploy-report.png](./images/start-deploy-report.png) + + +### 压缩 + +#### 开启 gzip 压缩 + +开启 gzip,并配合 nginx 的 `gzip_static` 功能可以大大加快页面访问速度 + +- 只需开启 `VITE_BUILD_COMPRESS='gzip'` 即可在打包的同时生成 .gz 文件 + +```shell +# 根据自己路径来配置更改 +# 例如部署在nginx /next/路径下 则VITE_PUBLIC_PATH=/next/ +VITE_PUBLIC_PATH=/ +``` + +#### 开启 brotli 压缩 + +brotli 是比 gzip 压缩率更高的算法,可以与 gzip 共存不会冲突,需要 nginx 安装指定模块并开启即可。 + +- 只需开启 VITE_BUILD_COMPRESS='brotli' 即可在打包的同时生成 .br 文件 + +```shell +# 根据自己路径来配置更改 +# 例如部署在nginx /next/路径下 则VITE_PUBLIC_PATH=/next/ +VITE_PUBLIC_PATH=/ +``` + + +#### 同时开启 gzip 与 brotli + +只需开启 VITE_BUILD_COMPRESS='brotli,gzip' 即可在打包的同时生成 .gz 和 .br 文件。 + + +#### gzip 与 brotli 在 nginx 内的配置 +``` +http { + # 开启gzip + gzip on; + # 开启gzip_static + # gzip_static 开启后可能会报错,需要安装相应的模块, 具体安装方式可以自行查询 + # 只有这个开启,vue文件打包的.gz文件才会有效果,否则不需要开启gzip进行打包 + gzip_static on; + gzip_proxied any; + gzip_min_length 1k; + gzip_buffers 4 16k; + #如果nginx中使用了多层代理 必须设置这个才可以开启gzip。 + gzip_http_version 1.0; + gzip_comp_level 2; + gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; + gzip_vary off; + gzip_disable "MSIE [1-6]\."; + + # 开启 brotli压缩 + # 需要安装对应的nginx模块,具体安装方式可以自行查询 + # 可以与gzip共存不会冲突 + brotli on; + brotli_comp_level 6; + brotli_buffers 16 8k; + brotli_min_length 20; + brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml; +} + +``` + +### 部署 + +- 注意:项目默认是在生产环境开启 Mock,这样做非常不好,只是为了演示环境有数据,不建议在生产环境使用 Mock,而应该使用真实的后台接口,并将 Mock 关闭。 + +#### 发布 + +简单的部署只需要将最终生成的静态文件,dist 文件夹的静态文件发布到你的 cdn 或者静态服务器即可,需要注意的是其中的 index.html 通常会是你后台服务的入口页面,在确定了 js 和 css 的静态之后可能需要改变页面的引入路径。 + +例如上传到 nginx `/srv/www/project/index.html` + +``` +# nginx配置 +location / { + # 不缓存html,防止程序更新后缓存继续生效 + if ($request_filename ~* .*\.(?:htm|html)$) { + add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; + access_log on; + } + # 这里是vue打包文件dist内的文件的存放路径 + root /srv/www/project/; + index index.html index.htm; +} + + +``` + +部署时可能会发现资源路径不对,只需要修改`.env.production`文件即可。 + +```shell +# 根据自己路径来配置更改 +# 注意需要以 / 开头和结尾 +VITE_PUBLIC_PATH=/ +VITE_PUBLIC_PATH=/xxx/ + +``` + +#### 前端路由与服务端的结合 + +项目前端路由使用的是 vue-router,所以你可以选择两种方式:history 和 hash。 + +- hash 默认会在 url 后面拼接# +- history 则不会,不过 history 需要服务器配合 + +可在 src/router/index.ts 内进行 mode 修改 + +```vue +import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'; + +createRouter({ + history: createWebHashHistory(), + // or + history: createWebHistory(), +}); + +``` + +#### history 路由模式下服务端配置 + +开启 history 模式需要服务器配置,更多的服务器配置详情可以看 [history-mode](https://router.vuejs.org/guide/essentials/history-mode.html#html5-mode) + +这里以 nginx 配置为例 + + +##### 部署到根目录 +``` +server { + listen 80; + location / { + # 用于配合 History 使用 + try_files $uri $uri/ /index.html; + } +} +``` + +#### 部署到非根目录 + +1. 首先需要在打包的时候更改配置 + +```shell +# 在.env.production内,配置子目录路径 +VITE_PUBLIC_PATH = /sub/ +``` + +``` +server { + listen 80; + server_name localhost; + location /sub/ { + # 这里是vue打包文件dist内的文件的存放路径 + alias /srv/www/project/; + index index.html index.htm; + try_files $uri $uri/ /sub/index.html; + } +} +``` + +#### 使用 nginx 处理跨域 + +使用 nginx 处理项目部署后的跨域问题 + +1. 配置前端项目接口地址 + +``` +# 在.env.production内,配置接口地址 +VITE_GLOB_API_URL=/api +``` + +2. 在 nginx 配置请求转发到后台 + +``` +server { + listen 8080; + server_name localhost; + # 接口代理,用于解决跨域问题 + location /api { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # 后台接口地址 + proxy_pass http://110.110.1.1:8080/api; + proxy_redirect default; + add_header Access-Control-Allow-Origin *; + add_header Access-Control-Allow-Headers X-Requested-With; + add_header Access-Control-Allow-Methods GET,POST,OPTIONS; + } +} +``` \ No newline at end of file diff --git a/docs/guide-zh-CN/web-form.md b/docs/guide-zh-CN/web-form.md new file mode 100644 index 0000000..17a8a19 --- /dev/null +++ b/docs/guide-zh-CN/web-form.md @@ -0,0 +1,879 @@ +## 表单组件 + +目录 + +- 文本输入 Input +- 数字输入 Input Number +- 文本域 InputTextarea +- 富文本 InputEditor +- 动态键值对 InputDynamic +- 日期选择 Date(Y-M-D) +- 日期范围选择 DateRange +- 时间选择 Time(Y-M-D H:i:s) +- 时间范围选择 TimeRange +- 单选按钮 Radio +- 复选框 Checkbox +- 单选下拉框 Select +- 多选下拉框 SelectMultiple +- 树型选择 Tree Select +- 单图上传 UploadImage +- 多图上传 UploadImage +- 单文件上传 UploadFile +- 多文件上传 UploadFile +- 文件选择器 FileChooser +- 大文件上传 MultipartUpload +- 开关 Switch +- 评分 Rate +- 省市区选择器 CitySelector +- 图标选择器 IconSelector + +### 文本输入 Input + +```vue + + + +``` + +### 数字输入 Input Number + +```vue + + + +``` + +### 文本域 InputTextarea + +```vue + + + +``` + +### 富文本 InputEditor + +```vue + + + +``` + +### 动态键值对 InputDynamic + +```vue + + + +``` + +### 日期选择 Date(Y-M-D) + +```vue + + + +``` + +### 日期范围选择 DateRange + +```vue + + + +``` + +### 时间选择 Time(Y-M-D H:i:s) + +```vue + + + +``` + +### 时间范围选择 TimeRange + +```vue + + + +``` + +### 单选按钮 Radio + +```vue + + + +``` + +### 复选框 Checkbox +```vue + + + +``` + + +### 单选下拉框 Select +```vue + + + +``` + +### 多选下拉框 SelectMultiple +```vue + + + +``` + +### 树型选择 Tree Select +```vue + + + + + +``` + + +### 单图上传 UploadImage +```vue + + + +``` + +### 多图上传 UploadImage +```vue + + + +``` + +### 单文件上传 UploadFile +```vue + + + +``` + +### 多文件上传 UploadFile +```vue + + + +``` + +### 文件选择器 FileChooser +- 基础用法 +```vue + + + +``` + +- 指定fileType,支持多种选择器类型,默认情况是全部都可以选择 +```ts +type FileType = 'image' | 'doc' | 'audio' | 'video' | 'zip' | 'other' | 'default'; +``` + +- 图片选择器 +```vue + +``` + +- 多选支持,指定`maxNumber`多选数量 +```vue + +``` + +### 大文件上传 MultipartUpload +- 基础用法 +```vue + + + +``` + +### 开关 Switch +```vue + + + +``` + +### 评分 Rate +```vue + + + +``` + +### 省市区选择器 CitySelector +```vue + + + +``` + +### 图标选择器 IconSelector +```vue + + + +``` + + +更多组件请参考:https://www.naiveui.com/zh-CN/os-theme/components/button + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..8d2ad74 --- /dev/null +++ b/index.html @@ -0,0 +1,187 @@ + + + + + + + + + HotGo-V2 + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/.gitattributes b/server/.gitattributes new file mode 100644 index 0000000..1fbf887 --- /dev/null +++ b/server/.gitattributes @@ -0,0 +1 @@ +* linguist-language=GO \ No newline at end of file diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..a314378 --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,39 @@ +.buildpath +.hgignore.swp +.project +.orig +.swp +.idea/ +.settings/ +.vscode/ +vendor/ +composer.lock +pkg/ +cbuild +**/.DS_Store +/test/ +main +output/ +manifest/config/config.yaml +manifest/output/ +resource/log/ +resource/public/admin/ +resource/public/attachment/ +storage/cache/ +storage/diskqueue/ +storage/cert/ssl/server.crt +storage/cert/ssl/server.key +storage/cert/pay/alipay/ +storage/cert/pay/wxpay/ +temp/ +logs/ +main.exe +main.exe~ +*.exe +*.log +*.zip +.idea +!hotgo/ +*.lock +/bin/package.sh +internal/packed/packed.go diff --git a/server/.golangci.yml b/server/.golangci.yml new file mode 100644 index 0000000..94f158a --- /dev/null +++ b/server/.golangci.yml @@ -0,0 +1,287 @@ +## This file contains all available configuration options +## with their default values. + +# See https://github.com/golangci/golangci-lint#config-file +# See https://golangci-lint.run/usage/configuration/ + +# Options for analysis running. +run: + # Exit code when at least one issue was found. + # Default: 1 + issues-exit-code: 2 + + # Include test files or not. + # Default: true + tests: false + go: "1.20" + + # Which dirs to skip: issues from them won't be reported. + # Can use regexp here: `generated.*`, regexp is applied on full path. + # Default value is empty list, + # but default dirs are skipped independently of this option's value (see skip-dirs-use-default). + # "/" will be replaced by current OS file path separator to properly work on Windows. + # skip-dirs: + # - internal/library/hggen/internal + + # Which files to skip: they will be analyzed, but issues from them won't be reported. + # Default value is empty list, + # but there is no need to include all autogenerated files, + # we confidently recognize autogenerated files. + # If it's not please let us know. + # "/" will be replaced by current OS file path separator to properly work on Windows. + # skip-files: [] + + +# Main linters configurations. +# See https://golangci-lint.run/usage/linters +linters: + # Disable all default enabled linters. + disable-all: true + # Custom enable linters we want to use. + enable: + - errcheck # Errcheck is a program for checking for unchecked errors in go programs. + - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted. + - funlen # Tool for detection of long functions + - goconst # Finds repeated strings that could be replaced by a constant + - gocritic # Provides diagnostics that check for bugs, performance and style issues. +# - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification + - gosimple # Linter for Go source code that specializes in simplifying code + - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string + - misspell # Finds commonly misspelled English words in comments + - nolintlint # Reports ill-formed or insufficient nolint directives + - revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. + - staticcheck # It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. + - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code + - usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library. + - whitespace # Tool for detection of leading and trailing whitespace + + +issues: + exclude-rules: + # helpers in tests often (rightfully) pass a *testing.T as their first argument + - path: _test\.go + text: "context.Context should be the first parameter of a function" + linters: + - revive + # Yes, they are, but it's okay in a test + - path: _test\.go + text: "exported func.*returns unexported type.*which can be annoying to use" + linters: + - revive + # https://github.com/go-critic/go-critic/issues/926 + - linters: + - gocritic + text: "unnecessaryDefer:" + exclude-dirs: + - internal/library/hggen/internal + exclude-files: [] + + +# https://golangci-lint.run/usage/linters +linters-settings: + # https://golangci-lint.run/usage/linters/#misspell + misspell: + locale: US + ignore-words: + - cancelled + + # https://golangci-lint.run/usage/linters/#revive + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md + revive: + ignore-generated-header: true + severity: error + rules: + - name: atomic + - name: line-length-limit + severity: error + arguments: [ 1024 ] + - name: unhandled-error + severity: warning + disabled: true + arguments: [] + - name: var-naming + severity: warning + disabled: true + arguments: + # AllowList + - [ "ID","URL","IP","HTTP","JSON","API","UID","Id","Api","Uid","Http","Json","Ip","Url" ] + # DenyList + - [ "VM" ] + - name: string-format + severity: warning + disabled: false + arguments: + - - 'core.WriteError[1].Message' + - '/^([^A-Z]|$)/' + - must not start with a capital letter + - - 'fmt.Errorf[0]' + - '/(^|[^\.!?])$/' + - must not end in punctuation + - - panic + - '/^[^\n]*$/' + - must not contain line breaks + - name: function-result-limit + severity: warning + disabled: false + arguments: [ 4 ] + + # https://golangci-lint.run/usage/linters/#funlen + funlen: + # Checks the number of lines in a function. + # If lower than 0, disable the check. + # Default: 60 + lines: 330 + # Checks the number of statements in a function. + # If lower than 0, disable the check. + # Default: 40 + statements: -1 + + # https://golangci-lint.run/usage/linters/#goconst + goconst: + # Minimal length of string constant. + # Default: 3 + min-len: 4 + # Minimum occurrences of constant string count to trigger issue. + # Default: 3 + # For subsequent optimization, the value is reduced. + min-occurrences: 30 + # Ignore test files. + # Default: false + ignore-tests: true + # Look for existing constants matching the values. + # Default: true + match-constant: false + # Search also for duplicated numbers. + # Default: false + numbers: true + # Minimum value, only works with goconst.numbers + # Default: 3 + min: 5 + # Maximum value, only works with goconst.numbers + # Default: 3 + max: 20 + # Ignore when constant is not used as function argument. + # Default: true + ignore-calls: false + + # https://golangci-lint.run/usage/linters/#gocritic + gocritic: + disabled-checks: + - ifElseChain + - assignOp + - appendAssign + - singleCaseSwitch + - regexpMust + - typeSwitchVar + - elseif + + # https://golangci-lint.run/usage/linters/#gosimple + gosimple: + # Select the Go version to target. + # Default: 1.13 + # Deprecated: use the global `run.go` instead. + # go: "1.15" + # Sxxxx checks in https://staticcheck.io/docs/configuration/options/#checks + # Default: ["*"] + checks: [ + "all", "-S1000", "-S1001", "-S1002", "-S1008", "-S1009", "-S1016", "-S1023", "-S1025", "-S1029", "-S1034", "-S1040" + ] + + # https://golangci-lint.run/usage/linters/#govet + govet: + # Report about shadowed variables. + # Default: false + # check-shadowing: true + # Settings per analyzer. + settings: + # Analyzer name, run `go tool vet help` to see all analyzers. + printf: + # Comma-separated list of print function names to check (in addition to default, see `go tool vet help printf`). + # Default: [] + funcs: + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + # shadow: + # Whether to be strict about shadowing; can be noisy. + # Default: false + # strict: false + unusedresult: + # Comma-separated list of functions whose results must be used + # (in addition to defaults context.WithCancel,context.WithDeadline,context.WithTimeout,context.WithValue, + # errors.New,fmt.Errorf,fmt.Sprint,fmt.Sprintf,sort.Reverse) + # Default [] + funcs: + - pkg.MyFunc + - context.WithCancel + # Comma-separated list of names of methods of type func() string whose results must be used + # (in addition to default Error,String) + # Default [] + stringmethods: + - MyMethod + # Enable all analyzers. + # Default: false + enable-all: true + # Disable analyzers by name. + # Run `go tool vet help` to see all analyzers. + # Default: [] + disable: + - asmdecl + - assign + - atomic + - atomicalign + - bools + - buildtag + - cgocall + - composites + - copylocks + - deepequalerrors + - errorsas + - fieldalignment + - findcall + - framepointer + - httpresponse + - ifaceassert + - loopclosure + - lostcancel + - nilfunc + - nilness + - reflectvaluecompare + - shift + - shadow + - sigchanyzer + - sortslice + - stdmethods + - stringintconv + - structtag + - testinggoroutine + - tests + - unmarshal + - unreachable + - unsafeptr + - unusedwrite + + # https://golangci-lint.run/usage/linters/#staticcheck + staticcheck: + # Select the Go version to target. + # Default: "1.13" + # Deprecated: use the global `run.go` instead. + # go: "1.15" + # SAxxxx checks in https://staticcheck.io/docs/configuration/options/#checks + # Default: ["*"] + checks: [ "all","-SA1019","-SA4015","-SA1029","-SA1016","-SA9003","-SA4006","-SA6003" ] + + # https://golangci-lint.run/usage/linters/#gofmt + gofmt: + # Simplify code: gofmt with `-s` option. + # Default: true + simplify: true + # Apply the rewrite rules to the source before reformatting. + # https://pkg.go.dev/cmd/gofmt + # Default: [] + rewrite-rules: [ ] + # - pattern: 'interface{}' + # replacement: 'any' + # - pattern: 'a[b:len(a)]' + # replacement: 'a[b:]' \ No newline at end of file diff --git a/server/Makefile b/server/Makefile new file mode 100644 index 0000000..9731f00 --- /dev/null +++ b/server/Makefile @@ -0,0 +1,113 @@ +ROOT_DIR = $(shell pwd) +NAMESPACE = "default" +DEPLOY_NAME = "template-single" +DOCKER_NAME = "template-single" +ADMIN_RESOURCE_PATH = "/resource/public/admin/" + +# 一键编译。编译web前端,并将编译后的包移动到服务端对应静态资源路径下,最后编译服务端 +.PHONY: build +build: + @rm -rf ./$(ADMIN_RESOURCE_PATH) + @mkdir ./$(ADMIN_RESOURCE_PATH) + @cd ../web && pnpm run build && \cp -rf ./dist/* ../server$(ADMIN_RESOURCE_PATH) + @cd ../server + @echo "y" | gf build + +# 通过热编译启动所有服务 +.PHONY: all +all: + gf run main.go --args "all" + +.PHONY: http +http: + gf run main.go --args "http" + +.PHONY: queue +queue: + gf run main.go --args "queue" + +.PHONY: cron +cron: + gf run main.go --args "cron" + +.PHONY: auth +auth: + gf run main.go --args "auth" + +# 启动web服务 +.PHONY: web +web: + @cd ../web && pnpm run dev + +# 刷新casbin权限 +.PHONY: refresh +refresh: + @go run main.go tools -m=casbin -a1=refresh + +# 清理casbin权限 +.PHONY: clear +clear: + @go run main.go tools -m=casbin -a1=clear + +# 运行代码质量分析工具 +# https://github.com/ywanbing/golangci +.PHONY: lint +lint: + golangci-lint run + +.PHONY: killmain +killmain: + @kill -9 $(ps -ef|grep main|grep -v grep|awk '{print $2}') + +# Install/Update to the latest CLI tool. +.PHONY: cli +cli: + @set -e; \ + wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(shell go env GOOS)_$(shell go env GOARCH) && \ + chmod +x gf && \ + ./gf install -y && \ + rm ./gf + +# Check and install CLI tool. +.PHONY: cli.install +cli.install: + @set -e; \ + gf -v > /dev/null 2>&1 || if [[ "$?" -ne "0" ]]; then \ + echo "GoFame CLI is not installed, start proceeding auto installation..."; \ + make cli; \ + fi; + +# Generate Go files for DAO/DO/Entity. +.PHONY: dao +dao: cli.install + @gf gen dao + +# Generate Go files for Service. +.PHONY: service +service: cli.install + @gf gen service + +# Build image, deploy image and yaml to current kubectl environment and make port forward to local machine. +.PHONY: start +start: + @set -e; \ + make image; \ + make deploy; \ + make port; + +# Build docker image and commit to the repository. +# example: make image tag=v0.0.1 +.PHONY: image +image: + @echo "y" | gf docker main.go -p -tn hotgo:$(tag) + +# Deploy image and yaml to current kubectl environment. +.PHONY: deploy +deploy: + $(eval _TAG = $(if ${TAG}, ${TAG}, develop)) + @set -e; \ + mkdir -p $(ROOT_DIR)/temp/kustomize;\ + cd $(ROOT_DIR)/manifest/deploy/kustomize/overlays/${_TAG};\ + kustomize build > $(ROOT_DIR)/temp/kustomize.yaml;\ + kubectl apply -f $(ROOT_DIR)/temp/kustomize.yaml; \ + kubectl patch -n $(NAMESPACE) deployment/$(DEPLOY_NAME) -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"$(shell date +%s)\"}}}}}"; diff --git a/server/README.MD b/server/README.MD new file mode 100644 index 0000000..67735c3 --- /dev/null +++ b/server/README.MD @@ -0,0 +1 @@ +## HotGo 管理后台服务端 \ No newline at end of file diff --git a/server/addons/addons.go b/server/addons/addons.go new file mode 100644 index 0000000..aa1b522 --- /dev/null +++ b/server/addons/addons.go @@ -0,0 +1,6 @@ +// Package addons +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package addons diff --git a/server/addons/hgexample/README.MD b/server/addons/hgexample/README.MD new file mode 100644 index 0000000..8fa3944 --- /dev/null +++ b/server/addons/hgexample/README.MD @@ -0,0 +1,39 @@ +## 功能案例 + +### 简介 + +系统的一些功能案例 + + +### 使用说明 + +系统自带的功能使用示例及其说明,包含一些简单的交互 + + +### 安装 + +1、安装 HotGo (2.11.4及以上) + +项目介绍:https://github.com/bufanyun/hotgo + +2、将当前插件项目拷贝进 HotGo 根目录的 server/addons 目录下 + +3、在 HotGo 根目录的 server/addons/modules 目录下创建go文件:hgexample.go,内容如下: +```go +package modules + +import _ "hotgo/addons/hgexample" +``` + +4、HotGo 后台进入 开发工具->插件管理->找到 功能案例 (hgexample) 进行安装 + +5、重启服务即可生效 + + +### 常用命令行 + +```shell +# 接口维护-gen service +gf gen service -s=addons/hgexample/logic -d=addons/hgexample/service + +``` diff --git a/server/addons/hgexample/api/admin/comp/import.go b/server/addons/hgexample/api/admin/comp/import.go new file mode 100644 index 0000000..75bd097 --- /dev/null +++ b/server/addons/hgexample/api/admin/comp/import.go @@ -0,0 +1,26 @@ +// Package comp +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package comp + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" +) + +// ImportExcelReq 导入Excel +type ImportExcelReq struct { + g.Meta `path:"/comp/importExcel" method:"post" tags:"功能案例" summary:"导入Excel"` + File *ghttp.UploadFile `json:"file" type:"file" dc:"分片文件"` +} + +type ImportExcelSheet struct { + Sheet string `json:"sheet"` + Rows [][]string `json:"rows"` +} + +type ImportExcelRes struct { + Sheets []*ImportExcelSheet `json:"sheets"` +} diff --git a/server/addons/hgexample/api/admin/config/config.go b/server/addons/hgexample/api/admin/config/config.go new file mode 100644 index 0000000..83b431f --- /dev/null +++ b/server/addons/hgexample/api/admin/config/config.go @@ -0,0 +1,30 @@ +// Package config +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package config + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/hgexample/model/input/sysin" +) + +// GetReq 获取指定分组的配置 +type GetReq struct { + g.Meta `path:"/config/get" method:"get" tags:"配置" summary:"获取指定分组的配置"` + sysin.GetConfigInp +} + +type GetRes struct { + *sysin.GetConfigModel +} + +// UpdateReq 获取指定分组的配置 +type UpdateReq struct { + g.Meta `path:"/config/update" method:"post" tags:"配置" summary:"获取指定分组的配置"` + sysin.UpdateConfigInp +} + +type UpdateRes struct { +} diff --git a/server/addons/hgexample/api/admin/index/index.go b/server/addons/hgexample/api/admin/index/index.go new file mode 100644 index 0000000..764eaa8 --- /dev/null +++ b/server/addons/hgexample/api/admin/index/index.go @@ -0,0 +1,21 @@ +// Package index +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package index + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/hgexample/model/input/sysin" +) + +// TestReq 测试 +type TestReq struct { + g.Meta `path:"/index/test" method:"get" tags:"功能案例" summary:"测试"` + sysin.IndexTestInp +} + +type TestRes struct { + *sysin.IndexTestModel +} diff --git a/server/addons/hgexample/api/admin/table/table.go b/server/addons/hgexample/api/admin/table/table.go new file mode 100644 index 0000000..368c4dc --- /dev/null +++ b/server/addons/hgexample/api/admin/table/table.go @@ -0,0 +1,83 @@ +// Package table +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package table + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/internal/model/input/form" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/table/list" method:"get" tags:"表格例子" summary:"获取表格列表"` + sysin.TableListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.TableListModel `json:"list" dc:"数据列表"` +} + +// ExportReq 导出列表 +type ExportReq struct { + g.Meta `path:"/table/export" method:"get" tags:"表格例子" summary:"导出表格列表"` + sysin.TableListInp +} + +type ExportRes struct{} + +// ViewReq 获取信息 +type ViewReq struct { + g.Meta `path:"/table/view" method:"get" tags:"表格例子" summary:"获取指定信息"` + sysin.TableViewInp +} + +type ViewRes struct { + *sysin.TableViewModel +} + +// EditReq 修改/新增 +type EditReq struct { + g.Meta `path:"/table/edit" method:"post" tags:"表格例子" summary:"修改/新增表格"` + sysin.TableEditInp +} + +type EditRes struct{} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/table/delete" method:"post" tags:"表格例子" summary:"删除表格"` + sysin.TableDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 最大排序 +type MaxSortReq struct { + g.Meta `path:"/table/maxSort" method:"get" tags:"表格例子" summary:"表格最大排序"` + sysin.TableMaxSortInp +} + +type MaxSortRes struct { + *sysin.TableMaxSortModel +} + +// StatusReq 更新状态 +type StatusReq struct { + g.Meta `path:"/table/status" method:"post" tags:"表格例子" summary:"更新表格状态"` + sysin.TableStatusInp +} + +type StatusRes struct{} + +// SwitchReq 更新开关状态 +type SwitchReq struct { + g.Meta `path:"/table/switch" method:"post" tags:"表格例子" summary:"更新表格状态"` + sysin.TableSwitchInp +} + +type SwitchRes struct{} diff --git a/server/addons/hgexample/api/admin/tenantorder/tenantorder.go b/server/addons/hgexample/api/admin/tenantorder/tenantorder.go new file mode 100644 index 0000000..edb8c2e --- /dev/null +++ b/server/addons/hgexample/api/admin/tenantorder/tenantorder.go @@ -0,0 +1,59 @@ +// Package tenantorder +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.13.1 +package tenantorder + +import ( + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/internal/model/input/form" + + "github.com/gogf/gf/v2/frame/g" +) + +// ListReq 查询多租户功能演示列表 +type ListReq struct { + g.Meta `path:"/tenantOrder/list" method:"get" tags:"多租户功能演示" summary:"获取多租户功能演示列表"` + sysin.TenantOrderListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.TenantOrderListModel `json:"list" dc:"数据列表"` +} + +// ExportReq 导出多租户功能演示列表 +type ExportReq struct { + g.Meta `path:"/tenantOrder/export" method:"get" tags:"多租户功能演示" summary:"导出多租户功能演示列表"` + sysin.TenantOrderListInp +} + +type ExportRes struct{} + +// ViewReq 获取多租户功能演示指定信息 +type ViewReq struct { + g.Meta `path:"/tenantOrder/view" method:"get" tags:"多租户功能演示" summary:"获取多租户功能演示指定信息"` + sysin.TenantOrderViewInp +} + +type ViewRes struct { + *sysin.TenantOrderViewModel +} + +// EditReq 修改/新增多租户功能演示 +type EditReq struct { + g.Meta `path:"/tenantOrder/edit" method:"post" tags:"多租户功能演示" summary:"修改/新增多租户功能演示"` + sysin.TenantOrderEditInp +} + +type EditRes struct{} + +// DeleteReq 删除多租户功能演示 +type DeleteReq struct { + g.Meta `path:"/tenantOrder/delete" method:"post" tags:"多租户功能演示" summary:"删除多租户功能演示"` + sysin.TenantOrderDeleteInp +} + +type DeleteRes struct{} \ No newline at end of file diff --git a/server/addons/hgexample/api/admin/treetable/treetable.go b/server/addons/hgexample/api/admin/treetable/treetable.go new file mode 100644 index 0000000..d5ebb96 --- /dev/null +++ b/server/addons/hgexample/api/admin/treetable/treetable.go @@ -0,0 +1,92 @@ +// Package treetable +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package treetable + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/internal/model/input/form" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/treeTable/list" method:"get" tags:"树形表格例子" summary:"获取表格列表"` + sysin.TreeTableListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.TreeTableListModel `json:"list" dc:"数据列表"` +} + +// ExportReq 导出列表 +type ExportReq struct { + g.Meta `path:"/treeTable/export" method:"get" tags:"树形表格例子" summary:"导出表格列表"` + sysin.TableListInp +} + +type ExportRes struct{} + +// ViewReq 获取信息 +type ViewReq struct { + g.Meta `path:"/treeTable/view" method:"get" tags:"树形表格例子" summary:"获取指定信息"` + sysin.TableViewInp +} + +type ViewRes struct { + *sysin.TableViewModel +} + +// EditReq 修改/新增 +type EditReq struct { + g.Meta `path:"/treeTable/edit" method:"post" tags:"树形表格例子" summary:"修改/新增表格"` + sysin.TableEditInp +} + +type EditRes struct{} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/treeTable/delete" method:"post" tags:"树形表格例子" summary:"删除表格"` + sysin.TableDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 最大排序 +type MaxSortReq struct { + g.Meta `path:"/treeTable/maxSort" method:"get" tags:"树形表格例子" summary:"表格最大排序"` + sysin.TableMaxSortInp +} + +type MaxSortRes struct { + *sysin.TableMaxSortModel +} + +// StatusReq 更新状态 +type StatusReq struct { + g.Meta `path:"/treeTable/status" method:"post" tags:"树形表格例子" summary:"更新表格状态"` + sysin.TableStatusInp +} + +type StatusRes struct{} + +// SwitchReq 更新开关状态 +type SwitchReq struct { + g.Meta `path:"/treeTable/switch" method:"post" tags:"树形表格例子" summary:"更新表格状态"` + sysin.TableSwitchInp +} + +type SwitchRes struct{} + +// SelectReq 树形选项 +type SelectReq struct { + g.Meta `path:"/treeTable/select" method:"get" tags:"树形表格例子" summary:"树形选项"` +} + +type SelectRes struct { + List []*sysin.TableTree `json:"list" dc:"数据列表"` +} diff --git a/server/addons/hgexample/api/api/index/index.go b/server/addons/hgexample/api/api/index/index.go new file mode 100644 index 0000000..764eaa8 --- /dev/null +++ b/server/addons/hgexample/api/api/index/index.go @@ -0,0 +1,21 @@ +// Package index +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package index + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/hgexample/model/input/sysin" +) + +// TestReq 测试 +type TestReq struct { + g.Meta `path:"/index/test" method:"get" tags:"功能案例" summary:"测试"` + sysin.IndexTestInp +} + +type TestRes struct { + *sysin.IndexTestModel +} diff --git a/server/addons/hgexample/api/home/index/index.go b/server/addons/hgexample/api/home/index/index.go new file mode 100644 index 0000000..7a44e68 --- /dev/null +++ b/server/addons/hgexample/api/home/index/index.go @@ -0,0 +1,21 @@ +// Package index +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package index + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/hgexample/model/input/sysin" +) + +// TestReq 测试 +type TestReq struct { + g.Meta `path:"/index/test" method:"get" tags:"功能案例" summary:"测试首页"` + sysin.IndexTestInp +} + +type TestRes struct { + g.Meta `mime:"text/html" type:"string" example:""` +} diff --git a/server/addons/hgexample/api/websocket/index/index.go b/server/addons/hgexample/api/websocket/index/index.go new file mode 100644 index 0000000..764eaa8 --- /dev/null +++ b/server/addons/hgexample/api/websocket/index/index.go @@ -0,0 +1,21 @@ +// Package index +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package index + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/hgexample/model/input/sysin" +) + +// TestReq 测试 +type TestReq struct { + g.Meta `path:"/index/test" method:"get" tags:"功能案例" summary:"测试"` + sysin.IndexTestInp +} + +type TestRes struct { + *sysin.IndexTestModel +} diff --git a/server/addons/hgexample/controller/admin/sys/comp.go b/server/addons/hgexample/controller/admin/sys/comp.go new file mode 100644 index 0000000..ba57d0b --- /dev/null +++ b/server/addons/hgexample/controller/admin/sys/comp.go @@ -0,0 +1,46 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "github.com/xuri/excelize/v2" + "hotgo/addons/hgexample/api/admin/comp" +) + +var ( + Comp = cComp{} +) + +type cComp struct{} + +// ImportExcel 导入Excel +func (c *cComp) ImportExcel(ctx context.Context, req *comp.ImportExcelReq) (res *comp.ImportExcelRes, err error) { + file, err := req.File.Open() + if err != nil { + return + } + defer file.Close() + + excel, err := excelize.OpenReader(file) + if err != nil { + return + } + defer excel.Close() + + res = new(comp.ImportExcelRes) + sheetList := excel.GetSheetList() + for _, sheet := range sheetList { + item := new(comp.ImportExcelSheet) + item.Sheet = sheet + item.Rows, err = excel.GetRows(sheet) + if err != nil { + return nil, err + } + res.Sheets = append(res.Sheets, item) + } + return +} diff --git a/server/addons/hgexample/controller/admin/sys/config.go b/server/addons/hgexample/controller/admin/sys/config.go new file mode 100644 index 0000000..ef40a69 --- /dev/null +++ b/server/addons/hgexample/controller/admin/sys/config.go @@ -0,0 +1,33 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/addons/hgexample/api/admin/config" + "hotgo/addons/hgexample/service" +) + +var ( + Config = cConfig{} +) + +type cConfig struct{} + +// GetConfig 获取指定分组的配置 +func (c *cConfig) GetConfig(ctx context.Context, req *config.GetReq) (res *config.GetRes, err error) { + data, err := service.SysConfig().GetConfigByGroup(ctx, &req.GetConfigInp) + + res = new(config.GetRes) + res.GetConfigModel = data + return +} + +// UpdateConfig 更新指定分组的配置 +func (c *cConfig) UpdateConfig(ctx context.Context, req *config.UpdateReq) (res *config.UpdateRes, err error) { + err = service.SysConfig().UpdateConfigByGroup(ctx, &req.UpdateConfigInp) + return +} diff --git a/server/addons/hgexample/controller/admin/sys/index.go b/server/addons/hgexample/controller/admin/sys/index.go new file mode 100644 index 0000000..b378b1d --- /dev/null +++ b/server/addons/hgexample/controller/admin/sys/index.go @@ -0,0 +1,30 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/addons/hgexample/api/admin/index" + "hotgo/addons/hgexample/service" +) + +var ( + Index = cIndex{} +) + +type cIndex struct{} + +// Test 测试 +func (c *cIndex) Test(ctx context.Context, req *index.TestReq) (res *index.TestRes, err error) { + data, err := service.SysIndex().Test(ctx, &req.IndexTestInp) + if err != nil { + return + } + + res = new(index.TestRes) + res.IndexTestModel = data + return +} diff --git a/server/addons/hgexample/controller/admin/sys/table.go b/server/addons/hgexample/controller/admin/sys/table.go new file mode 100644 index 0000000..03188cf --- /dev/null +++ b/server/addons/hgexample/controller/admin/sys/table.go @@ -0,0 +1,85 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/addons/hgexample/api/admin/table" + "hotgo/addons/hgexample/service" +) + +var ( + Table = cTable{} +) + +type cTable struct{} + +// List 查看列表 +func (c *cTable) List(ctx context.Context, req *table.ListReq) (res *table.ListRes, err error) { + list, totalCount, err := service.SysTable().List(ctx, &req.TableListInp) + if err != nil { + return + } + + res = new(table.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出列表 +func (c *cTable) Export(ctx context.Context, req *table.ExportReq) (res *table.ExportRes, err error) { + err = service.SysTable().Export(ctx, &req.TableListInp) + return +} + +// Edit 更新 +func (c *cTable) Edit(ctx context.Context, req *table.EditReq) (res *table.EditRes, err error) { + err = service.SysTable().Edit(ctx, &req.TableEditInp) + return +} + +// MaxSort 最大排序 +func (c *cTable) MaxSort(ctx context.Context, req *table.MaxSortReq) (res *table.MaxSortRes, err error) { + data, err := service.SysTable().MaxSort(ctx, &req.TableMaxSortInp) + if err != nil { + return + } + + res = new(table.MaxSortRes) + res.TableMaxSortModel = data + return +} + +// View 获取指定信息 +func (c *cTable) View(ctx context.Context, req *table.ViewReq) (res *table.ViewRes, err error) { + data, err := service.SysTable().View(ctx, &req.TableViewInp) + if err != nil { + return + } + + res = new(table.ViewRes) + res.TableViewModel = data + return +} + +// Delete 删除 +func (c *cTable) Delete(ctx context.Context, req *table.DeleteReq) (res *table.DeleteRes, err error) { + err = service.SysTable().Delete(ctx, &req.TableDeleteInp) + return +} + +// Status 更新状态 +func (c *cTable) Status(ctx context.Context, req *table.StatusReq) (res *table.StatusRes, err error) { + err = service.SysTable().Status(ctx, &req.TableStatusInp) + return +} + +// Switch 更新开关状态 +func (c *cTable) Switch(ctx context.Context, req *table.SwitchReq) (res *table.SwitchRes, err error) { + err = service.SysTable().Switch(ctx, &req.TableSwitchInp) + return +} diff --git a/server/addons/hgexample/controller/admin/sys/tenant_order.go b/server/addons/hgexample/controller/admin/sys/tenant_order.go new file mode 100644 index 0000000..33f98b0 --- /dev/null +++ b/server/addons/hgexample/controller/admin/sys/tenant_order.go @@ -0,0 +1,67 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.13.1 +package sys + +import ( + "context" + "hotgo/addons/hgexample/api/admin/tenantorder" + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/addons/hgexample/service" +) + +var ( + TenantOrder = cTenantOrder{} +) + +type cTenantOrder struct{} + +// List 查看多租户功能演示列表 +func (c *cTenantOrder) List(ctx context.Context, req *tenantorder.ListReq) (res *tenantorder.ListRes, err error) { + list, totalCount, err := service.SysTenantOrder().List(ctx, &req.TenantOrderListInp) + if err != nil { + return + } + + if list == nil { + list = []*sysin.TenantOrderListModel{} + } + + res = new(tenantorder.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出多租户功能演示列表 +func (c *cTenantOrder) Export(ctx context.Context, req *tenantorder.ExportReq) (res *tenantorder.ExportRes, err error) { + err = service.SysTenantOrder().Export(ctx, &req.TenantOrderListInp) + return +} + +// Edit 更新多租户功能演示 +func (c *cTenantOrder) Edit(ctx context.Context, req *tenantorder.EditReq) (res *tenantorder.EditRes, err error) { + err = service.SysTenantOrder().Edit(ctx, &req.TenantOrderEditInp) + return +} + +// View 获取指定多租户功能演示信息 +func (c *cTenantOrder) View(ctx context.Context, req *tenantorder.ViewReq) (res *tenantorder.ViewRes, err error) { + data, err := service.SysTenantOrder().View(ctx, &req.TenantOrderViewInp) + if err != nil { + return + } + + res = new(tenantorder.ViewRes) + res.TenantOrderViewModel = data + return +} + +// Delete 删除多租户功能演示 +func (c *cTenantOrder) Delete(ctx context.Context, req *tenantorder.DeleteReq) (res *tenantorder.DeleteRes, err error) { + err = service.SysTenantOrder().Delete(ctx, &req.TenantOrderDeleteInp) + return +} diff --git a/server/addons/hgexample/controller/admin/sys/tree_table.go b/server/addons/hgexample/controller/admin/sys/tree_table.go new file mode 100644 index 0000000..0d2dd86 --- /dev/null +++ b/server/addons/hgexample/controller/admin/sys/tree_table.go @@ -0,0 +1,92 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/addons/hgexample/api/admin/treetable" + "hotgo/addons/hgexample/service" +) + +var ( + TreeTable = cTreeTable{} +) + +type cTreeTable struct{} + +// List 查看列表 +func (c *cTreeTable) List(ctx context.Context, req *treetable.ListReq) (res *treetable.ListRes, err error) { + list, totalCount, err := service.SysTreeTable().List(ctx, &req.TreeTableListInp) + if err != nil { + return + } + + res = new(treetable.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出列表 +func (c *cTreeTable) Export(ctx context.Context, req *treetable.ExportReq) (res *treetable.ExportRes, err error) { + err = service.SysTable().Export(ctx, &req.TableListInp) + return +} + +// Edit 更新 +func (c *cTreeTable) Edit(ctx context.Context, req *treetable.EditReq) (res *treetable.EditRes, err error) { + err = service.SysTreeTable().Edit(ctx, &req.TableEditInp) + return +} + +// MaxSort 最大排序 +func (c *cTreeTable) MaxSort(ctx context.Context, req *treetable.MaxSortReq) (res *treetable.MaxSortRes, err error) { + data, err := service.SysTable().MaxSort(ctx, &req.TableMaxSortInp) + if err != nil { + return + } + + res = new(treetable.MaxSortRes) + res.TableMaxSortModel = data + return +} + +// View 获取指定信息 +func (c *cTreeTable) View(ctx context.Context, req *treetable.ViewReq) (res *treetable.ViewRes, err error) { + data, err := service.SysTable().View(ctx, &req.TableViewInp) + if err != nil { + return + } + + res = new(treetable.ViewRes) + res.TableViewModel = data + return +} + +// Delete 删除 +func (c *cTreeTable) Delete(ctx context.Context, req *treetable.DeleteReq) (res *treetable.DeleteRes, err error) { + err = service.SysTreeTable().Delete(ctx, &req.TableDeleteInp) + return +} + +// Status 更新状态 +func (c *cTreeTable) Status(ctx context.Context, req *treetable.StatusReq) (res *treetable.StatusRes, err error) { + err = service.SysTable().Status(ctx, &req.TableStatusInp) + return +} + +// Switch 更新开关状态 +func (c *cTreeTable) Switch(ctx context.Context, req *treetable.SwitchReq) (res *treetable.SwitchRes, err error) { + err = service.SysTable().Switch(ctx, &req.TableSwitchInp) + return +} + +// Select 树形选项 +func (c *cTreeTable) Select(ctx context.Context, _ *treetable.SelectReq) (res *treetable.SelectRes, err error) { + res = new(treetable.SelectRes) + res.List, err = service.SysTreeTable().Select(ctx) + return +} diff --git a/server/addons/hgexample/controller/api/index.go b/server/addons/hgexample/controller/api/index.go new file mode 100644 index 0000000..c604f1d --- /dev/null +++ b/server/addons/hgexample/controller/api/index.go @@ -0,0 +1,30 @@ +// Package api +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package api + +import ( + "context" + "hotgo/addons/hgexample/api/api/index" + "hotgo/addons/hgexample/service" +) + +var ( + Index = cIndex{} +) + +type cIndex struct{} + +// Test 测试 +func (c *cIndex) Test(ctx context.Context, req *index.TestReq) (res *index.TestRes, err error) { + data, err := service.SysIndex().Test(ctx, &req.IndexTestInp) + if err != nil { + return + } + + res = new(index.TestRes) + res.IndexTestModel = data + return +} diff --git a/server/addons/hgexample/controller/home/index.go b/server/addons/hgexample/controller/home/index.go new file mode 100644 index 0000000..668fc74 --- /dev/null +++ b/server/addons/hgexample/controller/home/index.go @@ -0,0 +1,34 @@ +// Package home +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package home + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/hgexample/api/home/index" + "hotgo/addons/hgexample/service" + "hotgo/internal/model" + isc "hotgo/internal/service" +) + +// Index 基础 +var Index = cIndex{} + +type cIndex struct{} + +func (a *cIndex) Index(ctx context.Context, req *index.TestReq) (res *index.TestRes, err error) { + data, err := service.SysIndex().Test(ctx, &req.IndexTestInp) + if err != nil { + return + } + + isc.View().RenderTpl(ctx, "home/index.html", model.View{Data: g.Map{ + "name": data.Name, + "module": data.Module, + "time": data.Time, + }}) + return +} diff --git a/server/addons/hgexample/controller/websocket/handler/index.go b/server/addons/hgexample/controller/websocket/handler/index.go new file mode 100644 index 0000000..0cc74ab --- /dev/null +++ b/server/addons/hgexample/controller/websocket/handler/index.go @@ -0,0 +1,25 @@ +// Package handler +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package handler + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/websocket" +) + +var ( + Index = cIndex{} +) + +type cIndex struct{} + +// TestMessage 测试消息 +func (c *cIndex) TestMessage(client *websocket.Client, req *websocket.WRequest) { + g.Log().Infof(client.Context(), "收到客户端测试消息:%v", gjson.New(req).String()) + // 将收到的消息原样发送给客户端 + websocket.SendSuccess(client, req.Event, req.Data) +} diff --git a/server/addons/hgexample/controller/websocket/index.go b/server/addons/hgexample/controller/websocket/index.go new file mode 100644 index 0000000..37b9bbf --- /dev/null +++ b/server/addons/hgexample/controller/websocket/index.go @@ -0,0 +1,30 @@ +// Package websocket +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package websocket + +import ( + "context" + "hotgo/addons/hgexample/api/websocket/index" + "hotgo/addons/hgexample/service" +) + +var ( + Index = cIndex{} +) + +type cIndex struct{} + +// Test 测试 +func (c *cIndex) Test(ctx context.Context, req *index.TestReq) (res *index.TestRes, err error) { + data, err := service.SysIndex().Test(ctx, &req.IndexTestInp) + if err != nil { + return + } + + res = new(index.TestRes) + res.IndexTestModel = data + return +} diff --git a/server/addons/hgexample/crons/crons.go b/server/addons/hgexample/crons/crons.go new file mode 100644 index 0000000..e20bf6c --- /dev/null +++ b/server/addons/hgexample/crons/crons.go @@ -0,0 +1,9 @@ +// Package crons +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package crons + +// 定时任务. +// 插件中的定时任务可以统一在这里注册和处理 diff --git a/server/addons/hgexample/global/global.go b/server/addons/hgexample/global/global.go new file mode 100644 index 0000000..f549f88 --- /dev/null +++ b/server/addons/hgexample/global/global.go @@ -0,0 +1,12 @@ +// Package global +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package global + +import "hotgo/internal/library/addons" + +var ( + skeleton *addons.Skeleton // 插件架子 +) diff --git a/server/addons/hgexample/global/init.go b/server/addons/hgexample/global/init.go new file mode 100644 index 0000000..9db6de9 --- /dev/null +++ b/server/addons/hgexample/global/init.go @@ -0,0 +1,22 @@ +// Package global +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package global + +import ( + "context" + "hotgo/internal/library/addons" +) + +func Init(ctx context.Context, sk *addons.Skeleton) { + skeleton = sk +} + +func GetSkeleton() *addons.Skeleton { + if skeleton == nil { + panic("addon skeleton not initialized.") + } + return skeleton +} diff --git a/server/addons/hgexample/logic/.gitkeep b/server/addons/hgexample/logic/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/addons/hgexample/logic/logic.go b/server/addons/hgexample/logic/logic.go new file mode 100644 index 0000000..bd978f2 --- /dev/null +++ b/server/addons/hgexample/logic/logic.go @@ -0,0 +1,9 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package logic + +import ( + _ "hotgo/addons/hgexample/logic/sys" +) diff --git a/server/addons/hgexample/logic/sys/config.go b/server/addons/hgexample/logic/sys/config.go new file mode 100644 index 0000000..73620b2 --- /dev/null +++ b/server/addons/hgexample/logic/sys/config.go @@ -0,0 +1,59 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "hotgo/addons/hgexample/global" + "hotgo/addons/hgexample/model" + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/addons/hgexample/service" + isc "hotgo/internal/service" +) + +type sSysConfig struct{} + +func NewSysConfig() *sSysConfig { + return &sSysConfig{} +} + +func init() { + service.RegisterSysConfig(NewSysConfig()) +} + +// GetBasic 获取基础配置 +func (s *sSysConfig) GetBasic(ctx context.Context) (conf *model.BasicConfig, err error) { + var in sysin.GetConfigInp + in.GetAddonsConfigInp.AddonName = global.GetSkeleton().Name + in.GetAddonsConfigInp.Group = "basic" + models, err := isc.SysAddonsConfig().GetConfigByGroup(ctx, &in.GetAddonsConfigInp) + if err != nil { + return + } + + err = gconv.Struct(models.List, &conf) + return +} + +// GetConfigByGroup 获取指定分组配置 +func (s *sSysConfig) GetConfigByGroup(ctx context.Context, in *sysin.GetConfigInp) (res *sysin.GetConfigModel, err error) { + in.GetAddonsConfigInp.AddonName = global.GetSkeleton().Name + models, err := isc.SysAddonsConfig().GetConfigByGroup(ctx, &in.GetAddonsConfigInp) + if err != nil { + return + } + + res = new(sysin.GetConfigModel) + res.List = models.List + return +} + +// UpdateConfigByGroup 更新指定分组的配置 +func (s *sSysConfig) UpdateConfigByGroup(ctx context.Context, in *sysin.UpdateConfigInp) error { + in.UpdateAddonsConfigInp.AddonName = global.GetSkeleton().Name + return isc.SysAddonsConfig().UpdateConfigByGroup(ctx, &in.UpdateAddonsConfigInp) +} diff --git a/server/addons/hgexample/logic/sys/index.go b/server/addons/hgexample/logic/sys/index.go new file mode 100644 index 0000000..d3e8ccd --- /dev/null +++ b/server/addons/hgexample/logic/sys/index.go @@ -0,0 +1,35 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/os/gtime" + "hotgo/addons/hgexample/global" + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/addons/hgexample/service" + "hotgo/internal/library/contexts" +) + +type sSysIndex struct{} + +func NewSysIndex() *sSysIndex { + return &sSysIndex{} +} + +func init() { + service.RegisterSysIndex(NewSysIndex()) +} + +// Test 测试 +func (s *sSysIndex) Test(ctx context.Context, in *sysin.IndexTestInp) (res *sysin.IndexTestModel, err error) { + res = new(sysin.IndexTestModel) + res.Name = in.Name + res.Module = fmt.Sprintf("当前插件模块是:%s,当前应用模块是:%s", global.GetSkeleton().Name, contexts.Get(ctx).Module) + res.Time = gtime.Now() + return +} diff --git a/server/addons/hgexample/logic/sys/table.go b/server/addons/hgexample/logic/sys/table.go new file mode 100644 index 0000000..9c828bb --- /dev/null +++ b/server/addons/hgexample/logic/sys/table.go @@ -0,0 +1,233 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/util/gconv" + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/addons/hgexample/service" + "hotgo/internal/dao" + "hotgo/internal/library/contexts" + "hotgo/internal/library/hgorm" + "hotgo/internal/library/hgorm/handler" + "hotgo/internal/model/input/form" + "hotgo/utility/convert" + "hotgo/utility/excel" + "hotgo/utility/validate" +) + +type sSysTable struct{} + +func NewSysTable() *sSysTable { + return &sSysTable{} +} + +func init() { + service.RegisterSysTable(NewSysTable()) +} + +// Model Orm模型 +func (s *sSysTable) Model(ctx context.Context, option ...*handler.Option) *gdb.Model { + return handler.Model(dao.AddonHgexampleTable.Ctx(ctx), option...) +} + +// List 获取列表 +func (s *sSysTable) List(ctx context.Context, in *sysin.TableListInp) (list []*sysin.TableListModel, totalCount int, err error) { + mod := s.Model(ctx) + cols := dao.AddonHgexampleTable.Columns() + + if in.Title != "" { + mod = mod.WhereLike(cols.Title, "%"+in.Title+"%") + } + + if in.Content != "" { + mod = mod.WhereLike(cols.Content, "%"+in.Content+"%") + } + + if in.Status > 0 { + mod = mod.Where(cols.Status, in.Status) + } + + if in.Switch > 0 { + mod = mod.Where(cols.Switch, in.Switch) + } + + if len(in.Price) > 0 { + if in.Price[0] > 0 && in.Price[1] > 0 { + mod = mod.WhereBetween(cols.Price, in.Price[0], in.Price[1]) + } else if in.Price[0] > 0 && in.Price[1] == 0 { + mod = mod.WhereGTE(cols.Price, in.Price[0]) + } else if in.Price[0] == 0 && in.Price[1] > 0 { + mod = mod.WhereLTE(cols.Price, in.Price[1]) + } + } + + if in.ActivityAt != nil { + mod = mod.Where(cols.ActivityAt, in.ActivityAt) + } + + if len(in.CreatedAt) == 2 { + mod = mod.WhereBetween(cols.CreatedAt, in.CreatedAt[0], in.CreatedAt[1]) + } + + if !in.Flag.IsNil() { + mod = mod.Where(fmt.Sprintf(`JSON_CONTAINS(%s,'%v')`, cols.Flag, in.Flag)) + } + + if !in.Hobby.IsNil() { + mod = mod.Where(fmt.Sprintf(`JSON_CONTAINS(%s,'%v')`, cols.Hobby, in.Hobby)) + } + + totalCount, err = mod.Clone().Count() + if err != nil { + err = gerror.Wrap(err, "获取表格数据行失败,请稍后重试!") + return + } + + if totalCount == 0 { + return + } + + // .OrderAsc(cols.Sort).OrderDesc(cols.Id) + if err = mod.Fields(sysin.TableListModel{}).Page(in.Page, in.PerPage).Handler(handler.Sorter(in)).Scan(&list); err != nil { + err = gerror.Wrap(err, "获取表格列表失败,请稍后重试!") + return + } + return +} + +// Export 导出 +func (s *sSysTable) Export(ctx context.Context, in *sysin.TableListInp) (err error) { + list, totalCount, err := s.List(ctx, in) + if err != nil { + return + } + + // 字段的排序是依据tags的字段顺序,如果你不想使用默认的排序方式,可以直接定义 tags = []string{"字段名称", "字段名称2", ...} + tags, err := convert.GetEntityDescTags(sysin.TableExportModel{}) + if err != nil { + return + } + + var ( + fileName = "表格例子导出-" + gctx.CtxId(ctx) + sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, form.CalPageCount(totalCount, in.PerPage), in.Page, len(list)) + exports []sysin.TableExportModel + ) + + if err = gconv.Scan(list, &exports); err != nil { + return + } + + if err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName); err != nil { + return + } + return +} + +// Edit 修改/新增 +func (s *sSysTable) Edit(ctx context.Context, in *sysin.TableEditInp) (err error) { + cols := dao.AddonHgexampleTable.Columns() + if err = hgorm.IsUnique(ctx, &dao.AddonHgexampleTable, g.Map{cols.Qq: in.Qq}, "QQ号码已存在,请换一个", in.Id); err != nil { + return + } + + // 修改 + if in.Id > 0 { + in.UpdatedBy = contexts.GetUserId(ctx) + if _, err = s.Model(ctx).WherePri(in.Id).Data(in).Update(); err != nil { + err = gerror.Wrap(err, "修改表格失败,请稍后重试!") + return + } + return + } + + // 新增 + in.CreatedBy = contexts.GetUserId(ctx) + if _, err = s.Model(ctx, &handler.Option{FilterAuth: false}).Data(in).OmitEmptyData().Insert(); err != nil { + err = gerror.Wrap(err, "新增表格失败,请稍后重试!") + return + } + return +} + +// Delete 删除 +func (s *sSysTable) Delete(ctx context.Context, in *sysin.TableDeleteInp) (err error) { + if _, err = s.Model(ctx).WherePri(in.Id).Delete(); err != nil { + err = gerror.Wrap(err, "删除表格失败,请稍后重试!") + return + } + return +} + +// Status 更新状态 +func (s *sSysTable) Status(ctx context.Context, in *sysin.TableStatusInp) (err error) { + update := g.Map{ + dao.AddonHgexampleTable.Columns().Status: in.Status, + dao.AddonHgexampleTable.Columns().UpdatedBy: contexts.GetUserId(ctx), + } + + if _, err = s.Model(ctx).WherePri(in.Id).Data(update).Update(); err != nil { + err = gerror.Wrap(err, "更新表格状态失败,请稍后重试!") + return + } + return +} + +// Switch 更新开关状态 +func (s *sSysTable) Switch(ctx context.Context, in *sysin.TableSwitchInp) (err error) { + var fields = []string{ + dao.AddonHgexampleTable.Columns().Switch, + // ... + } + + if !validate.InSlice(fields, in.Key) { + err = gerror.New("开关键名不在白名单") + return + } + + update := g.Map{ + in.Key: in.Value, + dao.AddonHgexampleTable.Columns().UpdatedBy: contexts.GetUserId(ctx), + } + + if _, err = s.Model(ctx).Where(dao.AddonHgexampleTable.Columns().Id, in.Id).Data(update).Update(); err != nil { + err = gerror.Wrap(err, "更新表格开关失败,请稍后重试!") + return + } + return +} + +// MaxSort 最大排序 +func (s *sSysTable) MaxSort(ctx context.Context, in *sysin.TableMaxSortInp) (res *sysin.TableMaxSortModel, err error) { + dx := dao.AddonHgexampleTable + if err = dx.Ctx(ctx).Fields(dx.Columns().Sort).OrderDesc(dx.Columns().Sort).Scan(&res); err != nil { + err = gerror.Wrap(err, "获取表格最大排序,请稍后重试!") + return + } + + if res == nil { + res = new(sysin.TableMaxSortModel) + } + + res.Sort = form.DefaultMaxSort(res.Sort) + return +} + +// View 获取指定信息 +func (s *sSysTable) View(ctx context.Context, in *sysin.TableViewInp) (res *sysin.TableViewModel, err error) { + if err = s.Model(ctx).WherePri(in.Id).Scan(&res); err != nil { + err = gerror.Wrap(err, "获取生成演示信息,请稍后重试!") + return + } + return +} diff --git a/server/addons/hgexample/logic/sys/tenant_order.go b/server/addons/hgexample/logic/sys/tenant_order.go new file mode 100644 index 0000000..ac8094d --- /dev/null +++ b/server/addons/hgexample/logic/sys/tenant_order.go @@ -0,0 +1,174 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.13.1 +package sys + +import ( + "context" + "fmt" + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/addons/hgexample/service" + "hotgo/internal/dao" + "hotgo/internal/library/hgorm/handler" + "hotgo/internal/library/hgorm/hook" + "hotgo/internal/model/input/form" + "hotgo/utility/convert" + "hotgo/utility/excel" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/util/gconv" +) + +type sSysTenantOrder struct{} + +func NewSysTenantOrder() *sSysTenantOrder { + return &sSysTenantOrder{} +} + +func init() { + service.RegisterSysTenantOrder(NewSysTenantOrder()) +} + +// Model 多租户功能演示ORM模型 +func (s *sSysTenantOrder) Model(ctx context.Context, option ...*handler.Option) *gdb.Model { + if len(option) == 0 { + // 过滤多租户数据权限 + option = append(option, &handler.Option{ + FilterTenant: true, + //FilterAuth: true, // 如果还需要维护created_by、member_id等部门数据权限范围可放开注释 + }) + } + return handler.Model(dao.AddonHgexampleTenantOrder.Ctx(ctx), option...) +} + +// List 获取多租户功能演示列表 +func (s *sSysTenantOrder) List(ctx context.Context, in *sysin.TenantOrderListInp) (list []*sysin.TenantOrderListModel, totalCount int, err error) { + mod := s.Model(ctx) + + // 字段过滤 + mod = mod.Fields(sysin.TenantOrderListModel{}) + + // 查询主键 + if in.Id > 0 { + mod = mod.Where(dao.AddonHgexampleTenantOrder.Columns().Id, in.Id) + } + + // 查询租户ID + if in.TenantId > 0 { + mod = mod.Where(dao.AddonHgexampleTenantOrder.Columns().TenantId, in.TenantId) + } + + // 查询商户ID + if in.MerchantId > 0 { + mod = mod.Where(dao.AddonHgexampleTenantOrder.Columns().MerchantId, in.MerchantId) + } + + // 查询用户ID + if in.UserId > 0 { + mod = mod.Where(dao.AddonHgexampleTenantOrder.Columns().UserId, in.UserId) + } + + // 查询关联订单号 + if in.OrderSn != "" { + mod = mod.Where(dao.AddonHgexampleTenantOrder.Columns().OrderSn, in.OrderSn) + } + + // 查询支付状态 + if in.Status > 0 { + mod = mod.Where(dao.AddonHgexampleTenantOrder.Columns().Status, in.Status) + } + + // 查询创建时间 + if len(in.CreatedAt) == 2 { + mod = mod.WhereBetween(dao.AddonHgexampleTenantOrder.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1]) + } + + // 分页 + mod = mod.Page(in.Page, in.PerPage) + + // 排序 + mod = mod.OrderDesc(dao.AddonHgexampleTenantOrder.Columns().Id) + + // 查询数据 + if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { + err = gerror.Wrap(err, "获取多租户功能演示列表失败,请稍后重试!") + return + } + return +} + +// Export 导出多租户功能演示 +func (s *sSysTenantOrder) Export(ctx context.Context, in *sysin.TenantOrderListInp) (err error) { + list, totalCount, err := s.List(ctx, in) + if err != nil { + return + } + + // 字段的排序是依据tags的字段顺序,如果你不想使用默认的排序方式,可以直接定义 tags = []string{"字段名称", "字段名称2", ...} + tags, err := convert.GetEntityDescTags(sysin.TenantOrderExportModel{}) + if err != nil { + return + } + + var ( + fileName = "导出多租户功能演示-" + gctx.CtxId(ctx) + sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, form.CalPageCount(totalCount, in.PerPage), in.Page, len(list)) + exports []sysin.TenantOrderExportModel + ) + + if err = gconv.Scan(list, &exports); err != nil { + return + } + + err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName) + return +} + +// Edit 修改/新增多租户功能演示 +func (s *sSysTenantOrder) Edit(ctx context.Context, in *sysin.TenantOrderEditInp) (err error) { + return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) { + // 修改 + if in.Id > 0 { + if _, err = s.Model(ctx). + Fields(sysin.TenantOrderUpdateFields{}). + WherePri(in.Id).Data(in). + Hook(hook.SaveTenant). // 自动维护租户关系更新 + Update(); err != nil { + } + return + } + + // 新增 + if _, err = dao.AddonHgexampleTenantOrder.Ctx(ctx). + Fields(sysin.TenantOrderInsertFields{}). + Hook(hook.SaveTenant). // 自动维护租户关系更新 + Data(in). + Insert(); err != nil { + } + return + }) +} + +// Delete 删除多租户功能演示 +func (s *sSysTenantOrder) Delete(ctx context.Context, in *sysin.TenantOrderDeleteInp) (err error) { + if _, err = s.Model(ctx).WherePri(in.Id).Delete(); err != nil { + err = gerror.Wrap(err, "删除多租户功能演示失败,请稍后重试!") + return + } + return +} + +// View 获取多租户功能演示指定信息 +func (s *sSysTenantOrder) View(ctx context.Context, in *sysin.TenantOrderViewInp) (res *sysin.TenantOrderViewModel, err error) { + if err = s.Model(ctx).WherePri(in.Id).Scan(&res); err != nil { + err = gerror.Wrap(err, "获取多租户功能演示信息,请稍后重试!") + return + } + return +} diff --git a/server/addons/hgexample/logic/sys/tree_table.go b/server/addons/hgexample/logic/sys/tree_table.go new file mode 100644 index 0000000..2f09057 --- /dev/null +++ b/server/addons/hgexample/logic/sys/tree_table.go @@ -0,0 +1,186 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/addons/hgexample/service" + "hotgo/internal/consts" + "hotgo/internal/dao" + "hotgo/internal/library/contexts" + "hotgo/internal/library/hgorm" + "hotgo/internal/library/hgorm/handler" + "hotgo/internal/model/entity" +) + +type sSysTreeTable struct{} + +func NewSysTreeTable() *sSysTreeTable { + return &sSysTreeTable{} +} + +func init() { + service.RegisterSysTreeTable(NewSysTreeTable()) +} + +// Model Orm模型 +func (s *sSysTreeTable) Model(ctx context.Context, option ...*handler.Option) *gdb.Model { + return handler.Model(dao.AddonHgexampleTable.Ctx(ctx), option...) +} + +// List 获取列表 +func (s *sSysTreeTable) List(ctx context.Context, in *sysin.TreeTableListInp) (list []*sysin.TreeTableListModel, totalCount int, err error) { + mod := s.Model(ctx) + cols := dao.AddonHgexampleTable.Columns() + + if in.Title != "" { + mod = mod.WhereLike(cols.Title, "%"+in.Title+"%") + } + + if in.Content != "" { + mod = mod.WhereLike(cols.Content, "%"+in.Content+"%") + } + + if in.Status > 0 { + mod = mod.Where(cols.Status, in.Status) + } + + if in.Switch > 0 { + mod = mod.Where(cols.Switch, in.Switch) + } + + if in.Pid > 0 { + mod = mod.Where(cols.Pid, in.Pid) + } + + if len(in.Price) > 0 { + if in.Price[0] > 0 && in.Price[1] > 0 { + mod = mod.WhereBetween(cols.Price, in.Price[0], in.Price[1]) + } else if in.Price[0] > 0 && in.Price[1] == 0 { + mod = mod.WhereGTE(cols.Price, in.Price[0]) + } else if in.Price[0] == 0 && in.Price[1] > 0 { + mod = mod.WhereLTE(cols.Price, in.Price[1]) + } + } + + if in.ActivityAt != nil { + mod = mod.Where(cols.ActivityAt, in.ActivityAt) + } + + if len(in.CreatedAt) == 2 { + mod = mod.WhereBetween(cols.CreatedAt, in.CreatedAt[0], in.CreatedAt[1]) + } + + if !in.Flag.IsNil() { + mod = mod.Where(fmt.Sprintf(`JSON_CONTAINS(%s,'%v')`, cols.Flag, in.Flag)) + } + + if !in.Hobby.IsNil() { + mod = mod.Where(fmt.Sprintf(`JSON_CONTAINS(%s,'%v')`, cols.Hobby, in.Hobby)) + } + + totalCount, err = mod.Clone().Count() + if err != nil { + err = gerror.Wrap(err, "获取表格数据行失败,请稍后重试!") + return + } + + if totalCount == 0 { + return + } + + if err = mod.Fields(sysin.TableListModel{}).Page(in.Page, in.PerPage).Handler(handler.Sorter(in)).Scan(&list); err != nil { + err = gerror.Wrap(err, "获取表格列表失败,请稍后重试!") + return + } + return +} + +// Edit 修改/新增 +func (s *sSysTreeTable) Edit(ctx context.Context, in *sysin.TableEditInp) (err error) { + cols := dao.AddonHgexampleTable.Columns() + if err = hgorm.IsUnique(ctx, &dao.AddonHgexampleTable, g.Map{cols.Qq: in.Qq}, "QQ号码已存在,请换一个", in.Id); err != nil { + return + } + + return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) { + in.Pid, in.Level, in.Tree, err = hgorm.AutoUpdateTree(ctx, &dao.AddonHgexampleTable, in.Id, in.Pid) + if err != nil { + return err + } + + if in.Id > 0 { + in.UpdatedBy = contexts.GetUserId(ctx) + if _, err = s.Model(ctx).WherePri(in.Id).Data(in).Update(); err != nil { + err = gerror.Wrap(err, "修改表格失败,请稍后重试!") + return err + } + } else { + in.CreatedBy = contexts.GetUserId(ctx) + if _, err = s.Model(ctx, &handler.Option{FilterAuth: false}).Data(in).OmitEmptyData().Insert(); err != nil { + err = gerror.Wrap(err, "新增表格失败,请稍后重试!") + return err + } + } + return + }) +} + +// Delete 删除 +func (s *sSysTreeTable) Delete(ctx context.Context, in *sysin.TableDeleteInp) (err error) { + count, err := dao.AdminMenu.Ctx(ctx).Where("pid", in.Id).Count() + if err != nil { + err = gerror.Wrap(err, consts.ErrorORM) + return err + } + if count > 0 { + return gerror.New("请先删除该表格下的所有下级!") + } + + if _, err = s.Model(ctx).WherePri(in.Id).Delete(); err != nil { + err = gerror.Wrap(err, "删除表格失败,请稍后重试!") + return + } + return +} + +// Select 关系树选项列表 +func (s *sSysTreeTable) Select(ctx context.Context) (list []*sysin.TableTree, err error) { + var models []*entity.AddonHgexampleTable + if err = dao.AddonHgexampleTable.Ctx(ctx).Order("pid asc,id asc,sort asc").Scan(&models); err != nil { + err = gerror.Wrap(err, "获取关系树选项列表失败!") + return + } + + list = s.treeList(0, models) + return +} + +// treeList 树状列表 +func (s *sSysTreeTable) treeList(pid int64, nodes []*entity.AddonHgexampleTable) (list []*sysin.TableTree) { + list = make([]*sysin.TableTree, 0) + for _, v := range nodes { + if v.Pid == pid { + item := new(sysin.TableTree) + item.AddonHgexampleTable = *v + item.Label = v.Title + item.Value = v.Id + item.Key = v.Id + + child := s.treeList(v.Id, nodes) + if len(child) > 0 { + item.Children = child + } + list = append(list, item) + } + } + return +} diff --git a/server/addons/hgexample/main.go b/server/addons/hgexample/main.go new file mode 100644 index 0000000..2cccd3a --- /dev/null +++ b/server/addons/hgexample/main.go @@ -0,0 +1,97 @@ +// Package hgexample +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package hgexample + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gctx" + _ "hotgo/addons/hgexample/crons" + "hotgo/addons/hgexample/global" + _ "hotgo/addons/hgexample/logic" + _ "hotgo/addons/hgexample/queues" + "hotgo/addons/hgexample/router" + "hotgo/internal/library/addons" + "hotgo/internal/service" + "sync" +) + +type module struct { + skeleton *addons.Skeleton + ctx context.Context + sync.Mutex +} + +func init() { + newModule() +} + +func newModule() { + m := &module{ + skeleton: &addons.Skeleton{ + Label: "功能案例", + Name: "hgexample", + Group: 1, + Logo: "", + Brief: "系统的一些功能案例", + Description: "系统自带的功能使用示例及其说明,包含一些简单的交互", + Author: "孟帅", + Version: "v1.0.0", // 当该版本号高于已安装的版本号时,会提示可以更新 + }, + ctx: gctx.New(), + } + + addons.RegisterModule(m) +} + +// Start 启动模块 +func (m *module) Start(option *addons.Option) (err error) { + // 初始化模块 + global.Init(m.ctx, m.skeleton) + + // 注册插件路由 + option.Server.Group("/", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Addon) + router.Admin(m.ctx, group) + router.Api(m.ctx, group) + router.Home(m.ctx, group) + router.WebSocket(m.ctx, group) + }) + return +} + +// Stop 停止模块 +func (m *module) Stop() (err error) { + return +} + +// Ctx 上下文 +func (m *module) Ctx() context.Context { + return m.ctx +} + +// GetSkeleton 获取模块 +func (m *module) GetSkeleton() *addons.Skeleton { + return m.skeleton +} + +// Install 安装模块 +func (m *module) Install(ctx context.Context) (err error) { + // ... + return +} + +// Upgrade 更新模块 +func (m *module) Upgrade(ctx context.Context) (err error) { + // ... + return +} + +// UnInstall 卸载模块 +func (m *module) UnInstall(ctx context.Context) (err error) { + // ... + return +} diff --git a/server/addons/hgexample/model/config.go b/server/addons/hgexample/model/config.go new file mode 100644 index 0000000..7496b4b --- /dev/null +++ b/server/addons/hgexample/model/config.go @@ -0,0 +1,11 @@ +// Package model +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package model + +// BasicConfig 基础配置 +type BasicConfig struct { + Test string `json:"basicTest"` +} diff --git a/server/addons/hgexample/model/input/sysin/config.go b/server/addons/hgexample/model/input/sysin/config.go new file mode 100644 index 0000000..05c4fc1 --- /dev/null +++ b/server/addons/hgexample/model/input/sysin/config.go @@ -0,0 +1,24 @@ +// Package sysin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sysin + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/sysin" +) + +// UpdateConfigInp 更新指定配置 +type UpdateConfigInp struct { + sysin.UpdateAddonsConfigInp +} + +type GetConfigInp struct { + sysin.GetAddonsConfigInp +} + +type GetConfigModel struct { + List g.Map `json:"list"` +} diff --git a/server/addons/hgexample/model/input/sysin/index.go b/server/addons/hgexample/model/input/sysin/index.go new file mode 100644 index 0000000..8fb45c7 --- /dev/null +++ b/server/addons/hgexample/model/input/sysin/index.go @@ -0,0 +1,26 @@ +// Package sysin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sysin + +import ( + "context" + "github.com/gogf/gf/v2/os/gtime" +) + +// IndexTestInp 测试 +type IndexTestInp struct { + Name string `json:"name" d:"HotGo" dc:"名称"` +} + +func (in *IndexTestInp) Filter(ctx context.Context) (err error) { + return +} + +type IndexTestModel struct { + Name string `json:"name" dc:"名称"` + Module string `json:"module" dc:"当前插件模块"` + Time *gtime.Time `json:"time" dc:"当前时间"` +} diff --git a/server/addons/hgexample/model/input/sysin/table.go b/server/addons/hgexample/model/input/sysin/table.go new file mode 100644 index 0000000..e8d9f58 --- /dev/null +++ b/server/addons/hgexample/model/input/sysin/table.go @@ -0,0 +1,180 @@ +// Package sysin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sysin + +import ( + "context" + "errors" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "hotgo/internal/consts" + "hotgo/internal/model/entity" + "hotgo/internal/model/input/form" + "hotgo/utility/validate" +) + +// TableEditInp 修改/新增 +type TableEditInp struct { + entity.AddonHgexampleTable +} + +type TableEditModel struct{} + +func (in *TableEditInp) Filter(ctx context.Context) (err error) { + if in.Map.IsNil() { + in.Map = gjson.New(consts.NilJsonToString) + } + if in.Flag.IsNil() { + in.Flag = gjson.New(consts.NilJsonToString) + } + if in.Images.IsNil() { + in.Images = gjson.New(consts.NilJsonToString) + } + if in.Attachfiles.IsNil() { + in.Attachfiles = gjson.New(consts.NilJsonToString) + } + if in.Hobby.IsNil() { + in.Hobby = gjson.New(consts.NilJsonToString) + } + + if in.Title == "" { + return errors.New("标题不能为空") + } + + if in.Email != "" && !validate.IsEmail(in.Email) { + return errors.New("邮箱格式不正确") + } + + if err := g.Validator().Rules("float|between:0,5").Messages("请输入一个浮点数|推荐星只能是0~5星").Data(in.Star).Run(ctx); err != nil { + return err.Current() + } + return +} + +// TableDeleteInp 删除类型 +type TableDeleteInp struct { + Id interface{} `json:"id" v:"required#表格ID不能为空" dc:"表格ID"` +} + +type TableDeleteModel struct{} + +// TableViewInp 获取信息 +type TableViewInp struct { + Id int64 `json:"id" v:"required#表格ID不能为空" dc:"表格ID"` +} + +type TableViewModel struct { + entity.AddonHgexampleTable +} + +// TableListInp 获取列表 +type TableListInp struct { + form.PageReq + form.Sorters + Id int64 `json:"id" description:""` + Flag *gjson.Json `json:"flag" description:"标签"` + Title string `json:"title" description:"标题"` + Content string `json:"content" description:"内容"` + Price []float64 `json:"price" description:"价格"` + ActivityAt *gtime.Time `json:"activityAt" description:"活动时间"` + Switch int `json:"switch" description:"开关"` + Hobby *gjson.Json `json:"hobby" description:"爱好"` + Status int `json:"status" description:"状态"` + CreatedAt []*gtime.Time `json:"createdAt" description:"创建时间"` +} + +type TableListModel struct { + entity.AddonHgexampleTable + TableCategoryName string `json:"TableCategoryName" description:"分类名称"` + TableCategoryDescription string `json:"TableCategoryDescription" description:"分类描述"` + TableCategoryRemark string `json:"TableCategoryRemark" description:"分类备注"` + SysProvincesTitle string `json:"sysProvincesTitle" description:""` +} + +func (in *TableListInp) Filter(ctx context.Context) (err error) { + if !in.Flag.IsNil() { + in.Flag = gjson.New(in.Flag.Var().Ints()) + } + if !in.Hobby.IsNil() { + in.Hobby = gjson.New(in.Hobby.Var().Ints()) + } + return +} + +type TableExportModel struct { + Id int64 `json:"id" description:""` + CategoryId int64 `json:"categoryId" description:"分类ID"` + Flag *gjson.Json `json:"flag" description:"标签"` + Title string `json:"title" description:"标题"` + Star float64 `json:"star" description:"推荐星"` + Price float64 `json:"price" description:"价格"` + Views int64 `json:"views" description:"浏览次数"` + ActivityAt *gtime.Time `json:"activityAt" description:"活动时间"` + StartAt *gtime.Time `json:"startAt" description:"开启时间"` + EndAt *gtime.Time `json:"endAt" description:"结束时间"` + Switch int `json:"switch" description:"开关"` + Sort int `json:"sort" description:"排序"` + Avatar string `json:"avatar" description:"头像"` + Sex int `json:"sex" description:"性别"` + Qq string `json:"qq" description:"qq"` + Email string `json:"email" description:"邮箱"` + Mobile string `json:"mobile" description:"手机号码"` + Hobby *gjson.Json `json:"hobby" description:"爱好"` + Channel int `json:"channel" description:"渠道"` + Pid int64 `json:"pid" description:"上级ID"` + Level int `json:"level" description:"树等级"` + Tree string `json:"tree" description:"关系树"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态"` + CreatedBy int64 `json:"createdBy" description:"创建者"` + UpdatedBy int64 `json:"updatedBy" description:"更新者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} + +// TableMaxSortInp 最大排序 +type TableMaxSortInp struct{} + +type TableMaxSortModel struct { + Sort int `json:"sort" description:"排序"` +} + +// TableStatusInp 更新状态 +type TableStatusInp struct { + Id int64 `json:"id" v:"required#表格ID不能为空" dc:"表格ID"` + Status int `json:"status" dc:"状态"` +} + +func (in *TableStatusInp) Filter(ctx context.Context) (err error) { + if in.Id <= 0 { + err = gerror.New("ID不能为空") + return + } + + if in.Status <= 0 { + err = gerror.New("状态不能为空") + return + } + + if !validate.InSlice(consts.StatusSlice, in.Status) { + err = gerror.New("状态不正确") + return + } + return +} + +type TableStatusModel struct{} + +// TableSwitchInp 更新开关状态 +type TableSwitchInp struct { + form.SwitchReq + Id int64 `json:"id" v:"required#表格ID不能为空" dc:"表格ID"` +} + +type TableSwitchModel struct{} diff --git a/server/addons/hgexample/model/input/sysin/tenant_order.go b/server/addons/hgexample/model/input/sysin/tenant_order.go new file mode 100644 index 0000000..61b44a6 --- /dev/null +++ b/server/addons/hgexample/model/input/sysin/tenant_order.go @@ -0,0 +1,123 @@ +// Package sysin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.13.1 +package sysin + +import ( + "context" + "hotgo/internal/model/entity" + "hotgo/internal/model/input/form" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// TenantOrderUpdateFields 修改多租户功能演示字段过滤 +type TenantOrderUpdateFields struct { + TenantId int64 `json:"tenantId" dc:"租户ID"` + MerchantId int64 `json:"merchantId" dc:"商户ID"` + UserId int64 `json:"userId" dc:"用户ID"` + ProductName string `json:"productName" dc:"购买产品"` + OrderSn string `json:"orderSn" dc:"关联订单号"` + Money float64 `json:"money" dc:"充值金额"` + Remark string `json:"remark" dc:"备注"` + Status int `json:"status" dc:"支付状态"` +} + +// TenantOrderInsertFields 新增多租户功能演示字段过滤 +type TenantOrderInsertFields struct { + TenantId int64 `json:"tenantId" dc:"租户ID"` + MerchantId int64 `json:"merchantId" dc:"商户ID"` + UserId int64 `json:"userId" dc:"用户ID"` + ProductName string `json:"productName" dc:"购买产品"` + OrderSn string `json:"orderSn" dc:"关联订单号"` + Money float64 `json:"money" dc:"充值金额"` + Remark string `json:"remark" dc:"备注"` + Status int `json:"status" dc:"支付状态"` +} + +// TenantOrderEditInp 修改/新增多租户功能演示 +type TenantOrderEditInp struct { + entity.AddonHgexampleTenantOrder +} + +func (in *TenantOrderEditInp) Filter(ctx context.Context) (err error) { + // 验证充值金额 + if err := g.Validator().Rules("required").Data(in.Money).Messages("充值金额不能为空").Run(ctx); err != nil { + return err.Current() + } + + return +} + +type TenantOrderEditModel struct{} + +// TenantOrderDeleteInp 删除多租户功能演示 +type TenantOrderDeleteInp struct { + Id interface{} `json:"id" v:"required#主键不能为空" dc:"主键"` +} + +func (in *TenantOrderDeleteInp) Filter(ctx context.Context) (err error) { + return +} + +type TenantOrderDeleteModel struct{} + +// TenantOrderViewInp 获取指定多租户功能演示信息 +type TenantOrderViewInp struct { + Id int64 `json:"id" v:"required#主键不能为空" dc:"主键"` +} + +func (in *TenantOrderViewInp) Filter(ctx context.Context) (err error) { + return +} + +type TenantOrderViewModel struct { + entity.AddonHgexampleTenantOrder +} + +// TenantOrderListInp 获取多租户功能演示列表 +type TenantOrderListInp struct { + form.PageReq + Id int64 `json:"id" dc:"主键"` + TenantId int64 `json:"tenantId" dc:"租户ID"` + MerchantId int64 `json:"merchantId" dc:"商户ID"` + UserId int64 `json:"userId" dc:"用户ID"` + OrderSn string `json:"orderSn" dc:"关联订单号"` + Status int `json:"status" dc:"支付状态"` + CreatedAt []*gtime.Time `json:"createdAt" dc:"创建时间"` +} + +func (in *TenantOrderListInp) Filter(ctx context.Context) (err error) { + return +} + +type TenantOrderListModel struct { + Id int64 `json:"id" dc:"主键"` + TenantId int64 `json:"tenantId" dc:"租户ID"` + MerchantId int64 `json:"merchantId" dc:"商户ID"` + UserId int64 `json:"userId" dc:"用户ID"` + ProductName string `json:"productName" dc:"购买产品"` + OrderSn string `json:"orderSn" dc:"关联订单号"` + Money float64 `json:"money" dc:"充值金额"` + Remark string `json:"remark" dc:"备注"` + Status int `json:"status" dc:"支付状态"` + CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"` +} + +// TenantOrderExportModel 导出多租户功能演示 +type TenantOrderExportModel struct { + Id int64 `json:"id" dc:"主键"` + TenantId int64 `json:"tenantId" dc:"租户ID"` + MerchantId int64 `json:"merchantId" dc:"商户ID"` + UserId int64 `json:"userId" dc:"用户ID"` + ProductName string `json:"productName" dc:"购买产品"` + OrderSn string `json:"orderSn" dc:"关联订单号"` + Money float64 `json:"money" dc:"充值金额"` + Remark string `json:"remark" dc:"备注"` + Status int `json:"status" dc:"支付状态"` + CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"` +} diff --git a/server/addons/hgexample/model/input/sysin/tree_table.go b/server/addons/hgexample/model/input/sysin/tree_table.go new file mode 100644 index 0000000..02702c4 --- /dev/null +++ b/server/addons/hgexample/model/input/sysin/tree_table.go @@ -0,0 +1,47 @@ +// Package sysin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sysin + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/os/gtime" + "hotgo/internal/model/entity" + "hotgo/internal/model/input/form" +) + +// TreeTableListInp 获取列表 +type TreeTableListInp struct { + form.PageReq + form.Sorters + Id int64 `json:"id" description:""` + Flag *gjson.Json `json:"flag" description:"标签"` + Title string `json:"title" description:"标题"` + Content string `json:"content" description:"内容"` + Price []float64 `json:"price" description:"价格"` + ActivityAt *gtime.Time `json:"activityAt" description:"活动时间"` + Switch int `json:"switch" description:"开关"` + Hobby *gjson.Json `json:"hobby" description:"爱好"` + Status int `json:"status" description:"状态"` + CreatedAt []*gtime.Time `json:"createdAt" description:"创建时间"` + Pid int64 `json:"pid" description:"上级ID"` +} + +type TreeTableListModel struct { + entity.AddonHgexampleTable + TableCategoryName string `json:"TableCategoryName" description:"分类名称"` + TableCategoryDescription string `json:"TableCategoryDescription" description:"分类描述"` + TableCategoryRemark string `json:"TableCategoryRemark" description:"分类备注"` + SysProvincesTitle string `json:"sysProvincesTitle" description:""` +} + +// TableTree 树 +type TableTree struct { + entity.AddonHgexampleTable + Key int64 `json:"key" dc:"key"` + Label string `json:"label" dc:"标签"` + Value int64 `json:"value" dc:"键值"` + Children []*TableTree `json:"children"` +} diff --git a/server/addons/hgexample/queues/queues.go b/server/addons/hgexample/queues/queues.go new file mode 100644 index 0000000..9f2e7eb --- /dev/null +++ b/server/addons/hgexample/queues/queues.go @@ -0,0 +1,9 @@ +// Package queues +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package queues + +// 消息队列. +// 插件中的消息队列消费者可以统一在这里注册和处理 diff --git a/server/addons/hgexample/router/admin.go b/server/addons/hgexample/router/admin.go new file mode 100644 index 0000000..75884df --- /dev/null +++ b/server/addons/hgexample/router/admin.go @@ -0,0 +1,36 @@ +// Package router +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package router + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "hotgo/addons/hgexample/controller/admin/sys" + "hotgo/addons/hgexample/global" + "hotgo/addons/hgexample/router/genrouter" + "hotgo/internal/consts" + "hotgo/internal/library/addons" + "hotgo/internal/service" +) + +func Admin(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + group.Bind( + sys.Index, + ) + group.Middleware(service.Middleware().AdminAuth) + group.Bind( + sys.Comp, + sys.Config, + sys.Table, + sys.TreeTable, + ) + }) + + // 注册生成路由 + genrouter.Register(ctx, group) +} diff --git a/server/addons/hgexample/router/api.go b/server/addons/hgexample/router/api.go new file mode 100644 index 0000000..60c3626 --- /dev/null +++ b/server/addons/hgexample/router/api.go @@ -0,0 +1,32 @@ +// Package router +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package router + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "hotgo/addons/hgexample/controller/api" + "hotgo/addons/hgexample/global" + "hotgo/internal/consts" + "hotgo/internal/library/addons" + "hotgo/internal/service" +) + +// Api 前台路由 +func Api(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppApi, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + group.Bind( + // 无需验证的路由 + api.Index, + ) + group.Middleware(service.Middleware().ApiAuth) + group.Bind( + // 需要验证的路由 + // ... + ) + }) +} diff --git a/server/addons/hgexample/router/genrouter/init.go b/server/addons/hgexample/router/genrouter/init.go new file mode 100644 index 0000000..d15d513 --- /dev/null +++ b/server/addons/hgexample/router/genrouter/init.go @@ -0,0 +1,34 @@ +// Package genrouter +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package genrouter + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "hotgo/addons/hgexample/global" + "hotgo/internal/consts" + "hotgo/internal/library/addons" + "hotgo/internal/service" +) + +var ( + NoLoginRouter []interface{} // 无需登录 + LoginRequiredRouter []interface{} // 需要登录 +) + +// Register 注册通过代码生成的后台路由 +func Register(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + if len(NoLoginRouter) > 0 { + group.Bind(NoLoginRouter...) + } + group.Middleware(service.Middleware().AdminAuth) + if len(LoginRequiredRouter) > 0 { + group.Bind(LoginRequiredRouter...) + } + }) +} diff --git a/server/addons/hgexample/router/genrouter/tenant_order.go b/server/addons/hgexample/router/genrouter/tenant_order.go new file mode 100644 index 0000000..15aa5b0 --- /dev/null +++ b/server/addons/hgexample/router/genrouter/tenant_order.go @@ -0,0 +1,13 @@ +// Package genrouter +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.13.1 +package genrouter + +import "hotgo/addons/hgexample/controller/admin/sys" + +func init() { + LoginRequiredRouter = append(LoginRequiredRouter, sys.TenantOrder) // 多租户功能演示 +} \ No newline at end of file diff --git a/server/addons/hgexample/router/home.go b/server/addons/hgexample/router/home.go new file mode 100644 index 0000000..d985980 --- /dev/null +++ b/server/addons/hgexample/router/home.go @@ -0,0 +1,25 @@ +// Package router +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package router + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "hotgo/addons/hgexample/controller/home" + "hotgo/addons/hgexample/global" + "hotgo/internal/consts" + "hotgo/internal/library/addons" +) + +// Home 前台页面路由 +func Home(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppHome, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + group.Bind( + home.Index, + ) + }) +} diff --git a/server/addons/hgexample/router/websocket.go b/server/addons/hgexample/router/websocket.go new file mode 100644 index 0000000..b2ec122 --- /dev/null +++ b/server/addons/hgexample/router/websocket.go @@ -0,0 +1,40 @@ +// Package router +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package router + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "hotgo/addons/hgexample/controller/websocket" + "hotgo/addons/hgexample/controller/websocket/handler" + "hotgo/addons/hgexample/global" + "hotgo/internal/consts" + "hotgo/internal/library/addons" + "hotgo/internal/service" + ws "hotgo/internal/websocket" +) + +// WebSocket ws路由配置 +func WebSocket(ctx context.Context, group *ghttp.RouterGroup) { + prefix := addons.RouterPrefix(ctx, consts.AppWebSocket, global.GetSkeleton().Name) + group.Group(prefix, func(group *ghttp.RouterGroup) { + group.Bind( + // 无需验证的路由 + websocket.Index, + ) + // ws连接中间件 + group.Middleware(service.Middleware().WebSocketAuth) + group.Bind( + // 需要验证的路由 + // .. + ) + }) + + // 注册消息路由 + ws.RegisterMsg(ws.EventHandlers{ + "admin/addons/hgexample/testMessage": handler.Index.TestMessage, // 测试消息 + }) +} diff --git a/server/addons/hgexample/service/.gitkeep b/server/addons/hgexample/service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/addons/hgexample/service/sys.go b/server/addons/hgexample/service/sys.go new file mode 100644 index 0000000..9ad290d --- /dev/null +++ b/server/addons/hgexample/service/sys.go @@ -0,0 +1,139 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "hotgo/addons/hgexample/model" + "hotgo/addons/hgexample/model/input/sysin" + "hotgo/internal/library/hgorm/handler" + + "github.com/gogf/gf/v2/database/gdb" +) + +type ( + ISysConfig interface { + // GetBasic 获取基础配置 + GetBasic(ctx context.Context) (conf *model.BasicConfig, err error) + // GetConfigByGroup 获取指定分组配置 + GetConfigByGroup(ctx context.Context, in *sysin.GetConfigInp) (res *sysin.GetConfigModel, err error) + // UpdateConfigByGroup 更新指定分组的配置 + UpdateConfigByGroup(ctx context.Context, in *sysin.UpdateConfigInp) error + } + ISysIndex interface { + // Test 测试 + Test(ctx context.Context, in *sysin.IndexTestInp) (res *sysin.IndexTestModel, err error) + } + ISysTable interface { + // Model Orm模型 + Model(ctx context.Context, option ...*handler.Option) *gdb.Model + // List 获取列表 + List(ctx context.Context, in *sysin.TableListInp) (list []*sysin.TableListModel, totalCount int, err error) + // Export 导出 + Export(ctx context.Context, in *sysin.TableListInp) (err error) + // Edit 修改/新增 + Edit(ctx context.Context, in *sysin.TableEditInp) (err error) + // Delete 删除 + Delete(ctx context.Context, in *sysin.TableDeleteInp) (err error) + // Status 更新状态 + Status(ctx context.Context, in *sysin.TableStatusInp) (err error) + // Switch 更新开关状态 + Switch(ctx context.Context, in *sysin.TableSwitchInp) (err error) + // MaxSort 最大排序 + MaxSort(ctx context.Context, in *sysin.TableMaxSortInp) (res *sysin.TableMaxSortModel, err error) + // View 获取指定信息 + View(ctx context.Context, in *sysin.TableViewInp) (res *sysin.TableViewModel, err error) + } + ISysTenantOrder interface { + // Model 多租户功能演示ORM模型 + Model(ctx context.Context, option ...*handler.Option) *gdb.Model + // List 获取多租户功能演示列表 + List(ctx context.Context, in *sysin.TenantOrderListInp) (list []*sysin.TenantOrderListModel, totalCount int, err error) + // Export 导出多租户功能演示 + Export(ctx context.Context, in *sysin.TenantOrderListInp) (err error) + // Edit 修改/新增多租户功能演示 + Edit(ctx context.Context, in *sysin.TenantOrderEditInp) (err error) + // Delete 删除多租户功能演示 + Delete(ctx context.Context, in *sysin.TenantOrderDeleteInp) (err error) + // View 获取多租户功能演示指定信息 + View(ctx context.Context, in *sysin.TenantOrderViewInp) (res *sysin.TenantOrderViewModel, err error) + } + ISysTreeTable interface { + // Model Orm模型 + Model(ctx context.Context, option ...*handler.Option) *gdb.Model + // List 获取列表 + List(ctx context.Context, in *sysin.TreeTableListInp) (list []*sysin.TreeTableListModel, totalCount int, err error) + // Edit 修改/新增 + Edit(ctx context.Context, in *sysin.TableEditInp) (err error) + // Delete 删除 + Delete(ctx context.Context, in *sysin.TableDeleteInp) (err error) + // Select 关系树选项列表 + Select(ctx context.Context) (list []*sysin.TableTree, err error) + } +) + +var ( + localSysConfig ISysConfig + localSysIndex ISysIndex + localSysTable ISysTable + localSysTenantOrder ISysTenantOrder + localSysTreeTable ISysTreeTable +) + +func SysConfig() ISysConfig { + if localSysConfig == nil { + panic("implement not found for interface ISysConfig, forgot register?") + } + return localSysConfig +} + +func RegisterSysConfig(i ISysConfig) { + localSysConfig = i +} + +func SysIndex() ISysIndex { + if localSysIndex == nil { + panic("implement not found for interface ISysIndex, forgot register?") + } + return localSysIndex +} + +func RegisterSysIndex(i ISysIndex) { + localSysIndex = i +} + +func SysTable() ISysTable { + if localSysTable == nil { + panic("implement not found for interface ISysTable, forgot register?") + } + return localSysTable +} + +func RegisterSysTable(i ISysTable) { + localSysTable = i +} + +func SysTenantOrder() ISysTenantOrder { + if localSysTenantOrder == nil { + panic("implement not found for interface ISysTenantOrder, forgot register?") + } + return localSysTenantOrder +} + +func RegisterSysTenantOrder(i ISysTenantOrder) { + localSysTenantOrder = i +} + +func SysTreeTable() ISysTreeTable { + if localSysTreeTable == nil { + panic("implement not found for interface ISysTreeTable, forgot register?") + } + return localSysTreeTable +} + +func RegisterSysTreeTable(i ISysTreeTable) { + localSysTreeTable = i +} diff --git a/server/addons/modules/.gitkeep b/server/addons/modules/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/addons/modules/hgexample.go b/server/addons/modules/hgexample.go new file mode 100644 index 0000000..eafbc58 --- /dev/null +++ b/server/addons/modules/hgexample.go @@ -0,0 +1,8 @@ +// Package modules +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package modules + +import _ "hotgo/addons/hgexample" diff --git a/server/api/admin/addons/addons.go b/server/api/admin/addons/addons.go new file mode 100644 index 0000000..83dd492 --- /dev/null +++ b/server/api/admin/addons/addons.go @@ -0,0 +1,59 @@ +// Package addons +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package addons + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/addons/list" method:"get" tags:"插件管理" summary:"获取插件列表"` + sysin.AddonsListInp +} + +type ListRes struct { + List []*sysin.AddonsListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// BuildReq 提交生成 +type BuildReq struct { + g.Meta `path:"/addons/build" method:"post" tags:"插件管理" summary:"提交生成"` + sysin.AddonsBuildInp +} + +type BuildRes struct { +} + +// InstallReq 安装模块 +type InstallReq struct { + g.Meta `path:"/addons/install" method:"post" tags:"插件管理" summary:"安装模块"` + sysin.AddonsInstallInp +} + +type InstallRes struct { +} + +// UpgradeReq 更新模块 +type UpgradeReq struct { + g.Meta `path:"/addons/upgrade" method:"post" tags:"插件管理" summary:"更新模块"` + sysin.AddonsUpgradeInp +} + +type UpgradeRes struct { +} + +// UnInstallReq 卸载模块 +type UnInstallReq struct { + g.Meta `path:"/addons/uninstall" method:"post" tags:"插件管理" summary:"卸载模块"` + sysin.AddonsUnInstallInp +} + +type UnInstallRes struct { +} diff --git a/server/api/admin/attachment/attachment.go b/server/api/admin/attachment/attachment.go new file mode 100644 index 0000000..df58a31 --- /dev/null +++ b/server/api/admin/attachment/attachment.go @@ -0,0 +1,49 @@ +// Package attachment +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package attachment + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询附件列表 +type ListReq struct { + g.Meta `path:"/attachment/list" method:"get" tags:"附件" summary:"获取附件列表"` + sysin.AttachmentListInp +} + +type ListRes struct { + List []*sysin.AttachmentListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取附件信息 +type ViewReq struct { + g.Meta `path:"/attachment/view" method:"get" tags:"附件" summary:"获取指定附件信息"` + sysin.AttachmentViewInp +} + +type ViewRes struct { + *sysin.AttachmentViewModel +} + +// DeleteReq 删除附件 +type DeleteReq struct { + g.Meta `path:"/attachment/delete" method:"post" tags:"附件" summary:"删除附件"` + sysin.AttachmentDeleteInp +} + +type DeleteRes struct{} + +// ClearKindReq 清空上传类型 +type ClearKindReq struct { + g.Meta `path:"/attachment/clearKind" method:"post" tags:"附件" summary:"清空上传类型"` + sysin.AttachmentClearKindInp +} + +type ClearKindRes struct{} diff --git a/server/api/admin/blacklist/blacklist.go b/server/api/admin/blacklist/blacklist.go new file mode 100644 index 0000000..97c7475 --- /dev/null +++ b/server/api/admin/blacklist/blacklist.go @@ -0,0 +1,57 @@ +// Package blacklist +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package blacklist + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/blacklist/list" method:"get" tags:"黑名单" summary:"获取黑名单列表"` + sysin.BlacklistListInp +} + +type ListRes struct { + List []*sysin.BlacklistListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取信息 +type ViewReq struct { + g.Meta `path:"/blacklist/view" method:"get" tags:"黑名单" summary:"获取指定信息"` + sysin.BlacklistViewInp +} + +type ViewRes struct { + *sysin.BlacklistViewModel +} + +// EditReq 修改/新增 +type EditReq struct { + g.Meta `path:"/blacklist/edit" method:"post" tags:"黑名单" summary:"修改/新增黑名单"` + sysin.BlacklistEditInp +} + +type EditRes struct{} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/blacklist/delete" method:"post" tags:"黑名单" summary:"删除黑名单"` + sysin.BlacklistDeleteInp +} + +type DeleteRes struct{} + +// StatusReq 更新状态 +type StatusReq struct { + g.Meta `path:"/blacklist/status" method:"post" tags:"黑名单" summary:"更新黑名单状态"` + sysin.BlacklistStatusInp +} + +type StatusRes struct{} diff --git a/server/api/admin/cash/cash.go b/server/api/admin/cash/cash.go new file mode 100644 index 0000000..0d82d1f --- /dev/null +++ b/server/api/admin/cash/cash.go @@ -0,0 +1,49 @@ +// Package cash +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cash + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/adminin" + "hotgo/internal/model/input/form" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/cash/list" method:"get" tags:"提现" summary:"获取提现列表"` + adminin.CashListInp +} + +type ListRes struct { + List []*adminin.CashListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/cash/view" method:"get" tags:"提现" summary:"获取指定信息"` + adminin.CashViewInp +} + +type ViewRes struct { + *adminin.CashViewModel +} + +// ApplyReq 申请提现 +type ApplyReq struct { + g.Meta `path:"/cash/apply" method:"post" tags:"提现" summary:"申请提现"` + Money float64 `json:"money" description:"提现金额"` +} + +type ApplyRes struct{} + +// PaymentReq 提现打款处理 +type PaymentReq struct { + g.Meta `path:"/cash/payment" method:"post" tags:"提现" summary:"提现打款处理"` + adminin.CashPaymentInp +} + +type PaymentRes struct{} diff --git a/server/api/admin/common/console.go b/server/api/admin/common/console.go new file mode 100644 index 0000000..025ba2a --- /dev/null +++ b/server/api/admin/common/console.go @@ -0,0 +1,39 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import "github.com/gogf/gf/v2/frame/g" + +// ConsoleStatReq 控制台统计 +type ConsoleStatReq struct { + g.Meta `path:"/console/stat" method:"get" tags:"控制台" summary:"综合数据统计"` +} + +type ConsoleStatRes struct { + Visits struct { + DayVisits float64 `json:"dayVisits"` + Rise float64 `json:"rise"` + Decline float64 `json:"decline"` + Amount float64 `json:"amount"` + } `json:"visits"` + Saleroom struct { + WeekSaleroom float64 `json:"weekSaleroom"` + Amount float64 `json:"amount"` + Degree float64 `json:"degree"` + } `json:"saleroom"` + OrderLarge struct { + WeekLarge float64 `json:"weekLarge"` + Rise float64 `json:"rise"` + Decline float64 `json:"decline"` + Amount float64 `json:"amount"` + } `json:"orderLarge"` + Volume struct { + WeekLarge float64 `json:"weekLarge"` + Rise float64 `json:"rise"` + Decline float64 `json:"decline"` + Amount float64 `json:"amount"` + } `json:"volume"` +} diff --git a/server/api/admin/common/ems.go b/server/api/admin/common/ems.go new file mode 100644 index 0000000..82a5a53 --- /dev/null +++ b/server/api/admin/common/ems.go @@ -0,0 +1,27 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// SendTestEmailReq 发送测试邮件 +type SendTestEmailReq struct { + g.Meta `path:"/ems/sendTest" tags:"邮件" method:"post" summary:"发送测试邮件"` + To string `json:"to" v:"required#接收者邮件不能为空" dc:"接收者邮件,多个用;隔开"` +} + +type SendTestEmailRes struct { +} + +// SendBindEmsReq 发送换绑邮件 +type SendBindEmsReq struct { + g.Meta `path:"/ems/sendBind" tags:"邮件" method:"post" summary:"发送换绑邮件"` +} + +type SendBindEmsRes struct { +} diff --git a/server/api/admin/common/site.go b/server/api/admin/common/site.go new file mode 100644 index 0000000..7825a4c --- /dev/null +++ b/server/api/admin/common/site.go @@ -0,0 +1,90 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model" + "hotgo/internal/model/input/adminin" +) + +// LoginLogoutReq 注销登录 +type LoginLogoutReq struct { + g.Meta `path:"/site/logout" method:"post" tags:"后台基础" summary:"注销登录"` +} + +type LoginLogoutRes struct{} + +// RegisterReq 提交账号注册 +type RegisterReq struct { + g.Meta `path:"/site/register" method:"post" tags:"后台基础" summary:"账号注册"` + adminin.RegisterInp +} + +type RegisterRes struct { + *adminin.LoginModel +} + +// LoginCaptchaReq 获取登录验证码 +type LoginCaptchaReq struct { + g.Meta `path:"/site/captcha" method:"get" tags:"后台基础" summary:"获取登录验证码"` +} + +type LoginCaptchaRes struct { + Cid string `json:"cid" dc:"验证码ID"` + Base64 string `json:"base64" dc:"验证码"` +} + +// AccountLoginReq 提交账号登录 +type AccountLoginReq struct { + g.Meta `path:"/site/accountLogin" method:"post" tags:"后台基础" summary:"账号登录"` + adminin.AccountLoginInp +} + +type AccountLoginRes struct { + *adminin.LoginModel +} + +// MobileLoginReq 提交手机号登录 +type MobileLoginReq struct { + g.Meta `path:"/site/mobileLogin" method:"post" tags:"后台基础" summary:"手机号登录"` + adminin.MobileLoginInp +} + +type MobileLoginRes struct { + *adminin.LoginModel +} + +// SiteConfigReq 获取配置 +type SiteConfigReq struct { + g.Meta `path:"/site/config" method:"get" tags:"后台基础" summary:"获取配置"` +} + +type SiteConfigRes struct { + Version string `json:"version" dc:"系统版本"` + WsAddr string `json:"wsAddr" dc:"客户端websocket地址"` + Domain string `json:"domain" dc:"对外域名"` + Mode string `json:"mode" dc:"运行模式"` +} + +// SiteLoginConfigReq 获取登录配置 +type SiteLoginConfigReq struct { + g.Meta `path:"/site/loginConfig" method:"get" tags:"后台基础" summary:"获取登录配置"` +} + +type SiteLoginConfigRes struct { + *model.LoginConfig + I18nSwitch bool `json:"i18nSwitch" dc:"国际化开关"` + DefaultLanguage string `json:"defaultLanguage" dc:"默认语言设置"` + ProjectName string `json:"projectName" dc:"项目名称"` +} + +// SitePingReq ping +type SitePingReq struct { + g.Meta `path:"/site/ping" method:"get" tags:"后台基础" summary:"ping"` +} + +type SitePingRes struct{} diff --git a/server/api/admin/common/sms.go b/server/api/admin/common/sms.go new file mode 100644 index 0000000..53ebbd1 --- /dev/null +++ b/server/api/admin/common/sms.go @@ -0,0 +1,37 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/sysin" +) + +// SendTestSmsReq 发送测试短信 +type SendTestSmsReq struct { + g.Meta `path:"/sms/sendTest" tags:"短信" method:"post" summary:"发送测试短信"` + sysin.SendCodeInp +} + +type SendTestSmsRes struct { +} + +// SendBindSmsReq 发送换绑短信 +type SendBindSmsReq struct { + g.Meta `path:"/sms/sendBind" tags:"短信" method:"post" summary:"发送换绑短信"` +} + +type SendBindSmsRes struct { +} + +// SendSmsReq 发送短信 +type SendSmsReq struct { + g.Meta `path:"/sms/send" tags:"短信" method:"post" summary:"发送短信"` + sysin.SendCodeInp +} + +type SendSmsRes struct { +} diff --git a/server/api/admin/common/upload.go b/server/api/admin/common/upload.go new file mode 100644 index 0000000..8f1afb3 --- /dev/null +++ b/server/api/admin/common/upload.go @@ -0,0 +1,48 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/sysin" +) + +// UploadFileReq 上传文件 +type UploadFileReq struct { + g.Meta `path:"/upload/file" tags:"附件" method:"post" summary:"上传附件"` +} + +type UploadFileRes *sysin.AttachmentListModel + +// CheckMultipartReq 检查文件分片 +type CheckMultipartReq struct { + g.Meta `path:"/upload/checkMultipart" tags:"附件" method:"post" summary:"检查文件分片"` + sysin.CheckMultipartInp +} + +type CheckMultipartRes struct { + *sysin.CheckMultipartModel +} + +// UploadPartReq 分片上传 +type UploadPartReq struct { + g.Meta `path:"/upload/uploadPart" tags:"附件" method:"post" summary:"分片上传"` + sysin.UploadPartInp +} + +type UploadPartRes struct { + *sysin.UploadPartModel +} + +// ImageTransferStorageReq 图片链接转存 +type ImageTransferStorageReq struct { + g.Meta `path:"/upload/imageTransferStorage" tags:"附件" method:"post" summary:"图片链接转存"` + sysin.ImageTransferStorageInp +} + +type ImageTransferStorageRes struct { + *sysin.ImageTransferStorageModel +} diff --git a/server/api/admin/common/wechat.go b/server/api/admin/common/wechat.go new file mode 100644 index 0000000..c7af478 --- /dev/null +++ b/server/api/admin/common/wechat.go @@ -0,0 +1,31 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/commonin" +) + +// WechatAuthorizeReq 微信用户授权 +type WechatAuthorizeReq struct { + g.Meta `path:"/wechat/authorize" method:"get" tags:"微信" summary:"微信用户授权"` + commonin.WechatAuthorizeInp +} + +type WechatAuthorizeRes struct { + *commonin.WechatAuthorizeModel +} + +// WechatAuthorizeCallReq 微信用户授权回调 +type WechatAuthorizeCallReq struct { + g.Meta `path:"/wechat/authorizeCall" method:"get" tags:"微信" summary:"微信用户授权"` + commonin.WechatAuthorizeCallInp +} + +type WechatAuthorizeCallRes struct { + *commonin.WechatAuthorizeCallModel +} diff --git a/server/api/admin/config/config.go b/server/api/admin/config/config.go new file mode 100644 index 0000000..cc8b9b5 --- /dev/null +++ b/server/api/admin/config/config.go @@ -0,0 +1,47 @@ +// Package config +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package config + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// GetReq 获取指定分组的配置 +type GetReq struct { + g.Meta `path:"/config/get" method:"get" tags:"配置" summary:"获取指定分组的配置"` + sysin.GetConfigInp +} + +type GetRes struct { + *sysin.GetConfigModel +} + +// UpdateReq 获取指定分组的配置 +type UpdateReq struct { + g.Meta `path:"/config/update" method:"post" tags:"配置" summary:"获取指定分组的配置"` + sysin.UpdateConfigInp +} + +type UpdateRes struct { +} + +// TypeSelectReq 数据类型选项 +type TypeSelectReq struct { + g.Meta `path:"/config/typeSelect" method:"get" tags:"配置" summary:"数据类型选项"` +} + +type TypeSelectRes []form.Select + +// GetCashReq 获取提现配置 +type GetCashReq struct { + g.Meta `path:"/config/getCash" method:"get" tags:"配置" summary:"获取提现配置"` +} + +type GetCashRes struct { + *sysin.GetConfigModel +} diff --git a/server/api/admin/creditslog/creditslog.go b/server/api/admin/creditslog/creditslog.go new file mode 100644 index 0000000..bec4694 --- /dev/null +++ b/server/api/admin/creditslog/creditslog.go @@ -0,0 +1,33 @@ +// Package creditslog +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.5.3 +// @AutoGenerate Date 2023-04-15 15:59:58 +package creditslog + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/adminin" + "hotgo/internal/model/input/form" +) + +// ListReq 查询资产变动列表 +type ListReq struct { + g.Meta `path:"/creditsLog/list" method:"get" tags:"资产变动" summary:"获取资产变动列表"` + adminin.CreditsLogListInp +} + +type ListRes struct { + form.PageRes + List []*adminin.CreditsLogListModel `json:"list" dc:"数据列表"` +} + +// ExportReq 导出资产变动列表 +type ExportReq struct { + g.Meta `path:"/creditsLog/export" method:"get" tags:"资产变动" summary:"导出资产变动列表"` + adminin.CreditsLogListInp +} + +type ExportRes struct{} diff --git a/server/api/admin/cron/cron.go b/server/api/admin/cron/cron.go new file mode 100644 index 0000000..87f7267 --- /dev/null +++ b/server/api/admin/cron/cron.go @@ -0,0 +1,93 @@ +// Package cron +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cron + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/cron/list" method:"get" tags:"定时任务" summary:"获取定时任务列表"` + sysin.CronListInp +} + +type ListRes struct { + List []*sysin.CronListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取信息 +type ViewReq struct { + g.Meta `path:"/cron/view" method:"get" tags:"定时任务" summary:"获取指定信息"` + sysin.CronViewInp +} + +type ViewRes struct { + *sysin.CronViewModel +} + +// EditReq 修改/新增 +type EditReq struct { + g.Meta `path:"/cron/edit" method:"post" tags:"定时任务" summary:"修改/新增定时任务"` + sysin.CronEditInp +} + +type EditRes struct { + *sysin.CronEditModel +} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/cron/delete" method:"post" tags:"定时任务" summary:"删除定时任务"` + sysin.CronDeleteInp +} + +type DeleteRes struct { + *sysin.CronDeleteModel +} + +// MaxSortReq 最大排序 +type MaxSortReq struct { + g.Meta `path:"/cron/maxSort" method:"get" tags:"定时任务" summary:"定时任务最大排序"` + sysin.CronMaxSortInp +} + +type MaxSortRes struct { + *sysin.CronMaxSortModel +} + +// StatusReq 更新状态 +type StatusReq struct { + g.Meta `path:"/cron/status" method:"post" tags:"定时任务" summary:"更新定时任务状态"` + sysin.CronStatusInp +} + +type StatusRes struct { + *sysin.CronStatusModel +} + +// OnlineExecReq 在线执行 +type OnlineExecReq struct { + g.Meta `path:"/cron/onlineExec" method:"post" tags:"定时任务" summary:"在线执行"` + sysin.OnlineExecInp +} + +type OnlineExecRes struct { + *sysin.OnlineExecModel +} + +// DispatchLogReq 调度日志 +type DispatchLogReq struct { + g.Meta `path:"/cron/dispatchLog" method:"post" tags:"定时任务" summary:"调度日志"` + sysin.DispatchLogInp +} + +type DispatchLogRes struct { + *sysin.DispatchLogModel +} diff --git a/server/api/admin/cron/cron_group.go b/server/api/admin/cron/cron_group.go new file mode 100644 index 0000000..fa20089 --- /dev/null +++ b/server/api/admin/cron/cron_group.go @@ -0,0 +1,83 @@ +// Package cron +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cron + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// GroupListReq 查询列表 +type GroupListReq struct { + g.Meta `path:"/cronGroup/list" method:"get" tags:"定时任务分组" summary:"获取定时任务分组列表"` + sysin.CronGroupListInp +} + +type GroupListRes struct { + List []*sysin.CronGroupListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// GroupViewReq 获取信息 +type GroupViewReq struct { + g.Meta `path:"/cronGroup/view" method:"get" tags:"定时任务分组" summary:"获取指定信息"` + sysin.CronGroupViewInp +} + +type GroupViewRes struct { + *sysin.CronGroupViewModel +} + +// GroupEditReq 修改/新增 +type GroupEditReq struct { + g.Meta `path:"/cronGroup/edit" method:"post" tags:"定时任务分组" summary:"修改/新增定时任务分组"` + sysin.CronGroupEditInp +} + +type GroupEditRes struct { + *sysin.CronGroupEditModel +} + +// GroupDeleteReq 删除 +type GroupDeleteReq struct { + g.Meta `path:"/cronGroup/delete" method:"post" tags:"定时任务分组" summary:"删除定时任务分组"` + sysin.CronGroupDeleteInp +} + +type GroupDeleteRes struct { + *sysin.CronGroupDeleteModel +} + +// GroupMaxSortReq 最大排序 +type GroupMaxSortReq struct { + g.Meta `path:"/cronGroup/maxSort" method:"get" tags:"定时任务分组" summary:"定时任务分组最大排序"` + sysin.CronGroupMaxSortInp +} + +type GroupMaxSortRes struct { + *sysin.CronGroupMaxSortModel +} + +// GroupStatusReq 更新状态 +type GroupStatusReq struct { + g.Meta `path:"/cronGroup/status" method:"post" tags:"定时任务分组" summary:"更新定时任务分组状态"` + sysin.CronGroupStatusInp +} + +type GroupStatusRes struct { + *sysin.CronGroupStatusModel +} + +// GroupSelectReq 定时任务分组选项 +type GroupSelectReq struct { + g.Meta `path:"/cronGroup/select" method:"get" tags:"定时任务分组" summary:"定时任务分组选项"` + sysin.CronGroupSelectInp +} + +type GroupSelectRes struct { + *sysin.CronGroupSelectModel +} diff --git a/server/api/admin/curddemo/curddemo.go b/server/api/admin/curddemo/curddemo.go new file mode 100644 index 0000000..f570d4f --- /dev/null +++ b/server/api/admin/curddemo/curddemo.go @@ -0,0 +1,85 @@ +// Package curddemo +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2025 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.18.6 +package curddemo + +import ( + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" + + "github.com/gogf/gf/v2/frame/g" +) + +// ListReq 查询CURD列表列表 +type ListReq struct { + g.Meta `path:"/curdDemo/list" method:"get" tags:"CURD列表" summary:"获取CURD列表列表"` + sysin.CurdDemoListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.CurdDemoListModel `json:"list" dc:"数据列表"` +} + +// ExportReq 导出CURD列表列表 +type ExportReq struct { + g.Meta `path:"/curdDemo/export" method:"get" tags:"CURD列表" summary:"导出CURD列表列表"` + sysin.CurdDemoListInp +} + +type ExportRes struct{} + +// ViewReq 获取CURD列表指定信息 +type ViewReq struct { + g.Meta `path:"/curdDemo/view" method:"get" tags:"CURD列表" summary:"获取CURD列表指定信息"` + sysin.CurdDemoViewInp +} + +type ViewRes struct { + *sysin.CurdDemoViewModel +} + +// EditReq 修改/新增CURD列表 +type EditReq struct { + g.Meta `path:"/curdDemo/edit" method:"post" tags:"CURD列表" summary:"修改/新增CURD列表"` + sysin.CurdDemoEditInp +} + +type EditRes struct{} + +// DeleteReq 删除CURD列表 +type DeleteReq struct { + g.Meta `path:"/curdDemo/delete" method:"post" tags:"CURD列表" summary:"删除CURD列表"` + sysin.CurdDemoDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 获取CURD列表最大排序 +type MaxSortReq struct { + g.Meta `path:"/curdDemo/maxSort" method:"get" tags:"CURD列表" summary:"获取CURD列表最大排序"` + sysin.CurdDemoMaxSortInp +} + +type MaxSortRes struct { + *sysin.CurdDemoMaxSortModel +} + +// StatusReq 更新CURD列表状态 +type StatusReq struct { + g.Meta `path:"/curdDemo/status" method:"post" tags:"CURD列表" summary:"更新CURD列表状态"` + sysin.CurdDemoStatusInp +} + +type StatusRes struct{} + +// SwitchReq 更新CURD列表开关状态 +type SwitchReq struct { + g.Meta `path:"/curdDemo/switch" method:"post" tags:"CURD列表" summary:"更新CURD列表状态"` + sysin.CurdDemoSwitchInp +} + +type SwitchRes struct{} \ No newline at end of file diff --git a/server/api/admin/dept/dept.go b/server/api/admin/dept/dept.go new file mode 100644 index 0000000..565ec74 --- /dev/null +++ b/server/api/admin/dept/dept.go @@ -0,0 +1,75 @@ +// Package dept +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package dept + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/adminin" + "hotgo/internal/model/input/form" + "hotgo/utility/tree" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/dept/list" method:"get" tags:"部门" summary:"获取部门列表"` + adminin.DeptListInp +} + +type ListRes *adminin.DeptListModel + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/dept/view" method:"get" tags:"部门" summary:"获取指定信息"` + adminin.DeptViewInp +} + +type ViewRes struct { + *adminin.DeptViewModel +} + +// EditReq 修改/新增字典数据 +type EditReq struct { + g.Meta `path:"/dept/edit" method:"post" tags:"部门" summary:"修改/新增部门"` + adminin.DeptEditInp +} + +type EditRes struct{} + +// DeleteReq 删除字典类型 +type DeleteReq struct { + g.Meta `path:"/dept/delete" method:"post" tags:"部门" summary:"删除部门"` + adminin.DeptDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 最大排序 +type MaxSortReq struct { + g.Meta `path:"/dept/maxSort" method:"get" tags:"部门" summary:"部门最大排序"` + adminin.DeptMaxSortInp +} + +type MaxSortRes struct { + *adminin.DeptMaxSortModel +} + +// OptionReq 获取当前登录用户可选的部门选项 +type OptionReq struct { + g.Meta `path:"/dept/option" method:"get" tags:"部门" summary:"获取当前登录用户可选的部门选项"` + adminin.DeptOptionInp +} + +type OptionRes struct { + *adminin.DeptOptionModel + form.PageRes +} + +// TreeOptionReq 获取部门关系树选项 +type TreeOptionReq struct { + g.Meta `path:"/dept/treeOption" method:"get" tags:"部门" summary:"获取部门关系树选项"` +} + +type TreeOptionRes []tree.Node diff --git a/server/api/admin/dict/dict_data.go b/server/api/admin/dict/dict_data.go new file mode 100644 index 0000000..8ecdea7 --- /dev/null +++ b/server/api/admin/dict/dict_data.go @@ -0,0 +1,53 @@ +// Package dict +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package dict + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// DataEditReq 修改/新增字典数据 +type DataEditReq struct { + g.Meta `path:"/dictData/edit" method:"post" tags:"字典数据" summary:"修改/新增字典数据"` + sysin.DictDataEditInp +} + +type DataEditRes struct{} + +// DataDeleteReq 删除字典数据 +type DataDeleteReq struct { + g.Meta `path:"/dictData/delete" method:"post" tags:"字典数据" summary:"删除字典数据"` + sysin.DictDataDeleteInp +} + +type DataDeleteRes struct{} + +// DataListReq 查询列表 +type DataListReq struct { + g.Meta `path:"/dictData/list" method:"get" tags:"字典数据" summary:"获取字典数据列表"` + sysin.DictDataListInp +} + +type DataListRes struct { + List []*sysin.DictDataListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +type DataSelectReq struct { + g.Meta `path:"/dictData/option/{Type}" method:"get" tags:"字典数据" summary:"获取指定字典选项"` + sysin.DataSelectInp +} + +type DataSelectRes sysin.DataSelectModel + +type DataSelectsReq struct { + g.Meta `path:"/dictData/options" method:"get" tags:"字典数据" summary:"获取多个字典选项"` + Types []string `json:"types"` +} + +type DataSelectsRes map[string]sysin.DataSelectModel diff --git a/server/api/admin/dict/dict_type.go b/server/api/admin/dict/dict_type.go new file mode 100644 index 0000000..16f09cb --- /dev/null +++ b/server/api/admin/dict/dict_type.go @@ -0,0 +1,36 @@ +// Package dict +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package dict + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/sysin" +) + +// TypeTreeReq 字典类型树 +type TypeTreeReq struct { + g.Meta `path:"/dictType/tree" tags:"字典类型" method:"get" summary:"字典类型树列表"` +} + +type TypeTreeRes struct { + List []*sysin.DictTypeTree `json:"list" dc:"数据列表"` +} + +// TypeEditReq 修改/新增字典数据 +type TypeEditReq struct { + g.Meta `path:"/dictType/edit" method:"post" tags:"字典类型" summary:"修改/新增字典类型"` + sysin.DictTypeEditInp +} + +type TypeEditRes struct{} + +// TypeDeleteReq 删除字典类型 +type TypeDeleteReq struct { + g.Meta `path:"/dictType/delete" method:"post" tags:"字典类型" summary:"删除字典类型"` + sysin.DictTypeDeleteInp +} + +type TypeDeleteRes struct{} diff --git a/server/api/admin/emslog/emslog.go b/server/api/admin/emslog/emslog.go new file mode 100644 index 0000000..3fd1578 --- /dev/null +++ b/server/api/admin/emslog/emslog.go @@ -0,0 +1,65 @@ +// Package emslog +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package emslog + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/emsLog/list" method:"get" tags:"邮件记录" summary:"获取邮件记录列表"` + sysin.EmsLogListInp +} + +type ListRes struct { + List []*sysin.EmsLogListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/emsLog/view" method:"get" tags:"邮件记录" summary:"获取指定信息"` + sysin.EmsLogViewInp +} + +type ViewRes struct { + *sysin.EmsLogViewModel +} + +// EditReq 修改/新增数据 +type EditReq struct { + g.Meta `path:"/emsLog/edit" method:"post" tags:"邮件记录" summary:"修改/新增邮件记录"` + sysin.EmsLogEditInp +} + +type EditRes struct{} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/emsLog/delete" method:"post" tags:"邮件记录" summary:"删除邮件记录"` + sysin.EmsLogDeleteInp +} + +type DeleteRes struct{} + +// StatusReq 更新状态 +type StatusReq struct { + g.Meta `path:"/emsLog/status" method:"post" tags:"邮件记录" summary:"更新邮件记录状态"` + sysin.EmsLogStatusInp +} + +type StatusRes struct{} + +// SendTestReq 更新状态 +type SendTestReq struct { + g.Meta `path:"/emsLog/sendTest" method:"post" tags:"邮件记录" summary:"发送测试邮件"` + sysin.SendEmsInp +} + +type SendTestRes struct{} diff --git a/server/api/admin/gencodes/gencodes.go b/server/api/admin/gencodes/gencodes.go new file mode 100644 index 0000000..7b196c8 --- /dev/null +++ b/server/api/admin/gencodes/gencodes.go @@ -0,0 +1,118 @@ +// Package gencodes +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package gencodes + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/genCodes/list" method:"get" tags:"生成代码" summary:"获取生成代码列表"` + sysin.GenCodesListInp +} + +type ListRes struct { + List []*sysin.GenCodesListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/genCodes/view" method:"get" tags:"生成代码" summary:"获取指定信息"` + sysin.GenCodesViewInp +} + +type ViewRes struct { + *sysin.GenCodesViewModel +} + +// EditReq 修改/新增数据 +type EditReq struct { + g.Meta `path:"/genCodes/edit" method:"post" tags:"生成代码" summary:"修改/新增生成代码"` + sysin.GenCodesEditInp +} + +type EditRes struct { + *sysin.GenCodesEditModel +} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/genCodes/delete" method:"post" tags:"生成代码" summary:"删除生成代码"` + sysin.GenCodesDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 最大排序 +type MaxSortReq struct { + g.Meta `path:"/genCodes/maxSort" method:"get" tags:"生成代码" summary:"生成代码最大排序"` + sysin.GenCodesMaxSortInp +} + +type MaxSortRes struct { + *sysin.GenCodesMaxSortModel +} + +// StatusReq 更新状态 +type StatusReq struct { + g.Meta `path:"/genCodes/status" method:"post" tags:"生成代码" summary:"更新生成代码状态"` + sysin.GenCodesStatusInp +} + +type StatusRes struct{} + +type SelectsReq struct { + g.Meta `path:"/genCodes/selects" method:"get" tags:"生成代码" summary:"生成入口选项"` + sysin.GenCodesSelectsInp +} + +type SelectsRes struct { + *sysin.GenCodesSelectsModel +} + +type TableSelectReq struct { + g.Meta `path:"/genCodes/tableSelect" method:"get" tags:"生成代码" summary:"数据库表选项"` + sysin.GenCodesTableSelectInp +} + +type TableSelectRes []*sysin.GenCodesTableSelectModel + +type ColumnSelectReq struct { + g.Meta `path:"/genCodes/columnSelect" method:"get" tags:"生成代码" summary:"表字段选项"` + sysin.GenCodesColumnSelectInp +} + +type ColumnSelectRes []*sysin.GenCodesColumnSelectModel + +type ColumnListReq struct { + g.Meta `path:"/genCodes/columnList" method:"get" tags:"生成代码" summary:"表字段列表"` + sysin.GenCodesColumnListInp +} + +type ColumnListRes []*sysin.GenCodesColumnListModel + +// PreviewReq 生成预览 +type PreviewReq struct { + g.Meta `path:"/genCodes/preview" method:"post" tags:"生成代码" summary:"生成预览"` + sysin.GenCodesPreviewInp +} + +type PreviewRes struct { + *sysin.GenCodesPreviewModel +} + +// BuildReq 提交生成 +type BuildReq struct { + g.Meta `path:"/genCodes/build" method:"post" tags:"生成代码" summary:"提交生成"` + sysin.GenCodesBuildInp +} + +type BuildRes struct { +} diff --git a/server/api/admin/log/log.go b/server/api/admin/log/log.go new file mode 100644 index 0000000..981751d --- /dev/null +++ b/server/api/admin/log/log.go @@ -0,0 +1,56 @@ +// Package log +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package log + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ClearReq 清空日志 +type ClearReq struct { + g.Meta `path:"/log/clear" method:"post" tags:"访问日志" summary:"清空日志"` +} + +type ClearRes struct{} + +// ExportReq 导出 +type ExportReq struct { + g.Meta `path:"/log/export" method:"get" tags:"访问日志" summary:"导出日志"` + sysin.LogListInp +} + +type ExportRes struct{} + +// ListReq 获取菜单列表 +type ListReq struct { + g.Meta `path:"/log/list" method:"get" tags:"访问日志" summary:"获取日志列表"` + sysin.LogListInp +} + +type ListRes struct { + List []*sysin.LogListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/log/delete" method:"post" tags:"访问日志" summary:"删除日志"` + sysin.LogDeleteInp +} + +type DeleteRes struct{} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/log/view" method:"get" tags:"访问日志" summary:"获取指定信息"` + sysin.LogViewInp +} + +type ViewRes struct { + *sysin.LogViewModel +} diff --git a/server/api/admin/loginlog/loginlog.go b/server/api/admin/loginlog/loginlog.go new file mode 100644 index 0000000..6fd3710 --- /dev/null +++ b/server/api/admin/loginlog/loginlog.go @@ -0,0 +1,39 @@ +// Package loginlog +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package loginlog + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询登录日志列表 +type ListReq struct { + g.Meta `path:"/loginLog/list" method:"get" tags:"登录日志" summary:"获取登录日志列表"` + sysin.LoginLogListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.LoginLogListModel `json:"list" dc:"数据列表"` +} + +// ExportReq 导出登录日志列表 +type ExportReq struct { + g.Meta `path:"/loginLog/export" method:"get" tags:"登录日志" summary:"导出登录日志列表"` + sysin.LoginLogListInp +} + +type ExportRes struct{} + +// DeleteReq 删除登录日志 +type DeleteReq struct { + g.Meta `path:"/loginLog/delete" method:"post" tags:"登录日志" summary:"删除登录日志"` + sysin.LoginLogDeleteInp +} + +type DeleteRes struct{} diff --git a/server/api/admin/member/member.go b/server/api/admin/member/member.go new file mode 100644 index 0000000..49cd1f0 --- /dev/null +++ b/server/api/admin/member/member.go @@ -0,0 +1,138 @@ +// Package member +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package member + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/adminin" + "hotgo/internal/model/input/form" +) + +// UpdateCashReq 更新提现信息 +type UpdateCashReq struct { + g.Meta `path:"/member/updateCash" method:"post" tags:"用户" summary:"更新提现信息"` + adminin.MemberUpdateCashInp +} + +type UpdateCashRes struct{} + +// UpdateEmailReq 换绑邮箱 +type UpdateEmailReq struct { + g.Meta `path:"/member/updateEmail" method:"post" tags:"用户" summary:"换绑邮箱"` + adminin.MemberUpdateEmailInp +} + +type UpdateEmailRes struct{} + +// UpdateMobileReq 换绑手机号 +type UpdateMobileReq struct { + g.Meta `path:"/member/updateMobile" method:"post" tags:"用户" summary:"换绑手机号"` + adminin.MemberUpdateMobileInp +} + +type UpdateMobileRes struct{} + +// UpdateProfileReq 更新用户资料 +type UpdateProfileReq struct { + g.Meta `path:"/member/updateProfile" method:"post" tags:"用户" summary:"更新用户资料"` + adminin.MemberUpdateProfileInp +} + +type UpdateProfileRes struct{} + +// UpdatePwdReq 修改登录密码 +type UpdatePwdReq struct { + g.Meta `path:"/member/updatePwd" method:"post" tags:"用户" summary:"重置密码"` + adminin.MemberUpdatePwdInp +} + +type UpdatePwdRes struct{} + +// ResetPwdReq 重置密码 +type ResetPwdReq struct { + g.Meta `path:"/member/resetPwd" method:"post" tags:"用户" summary:"重置密码"` + adminin.MemberResetPwdInp +} + +type ResetPwdRes struct{} + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/member/list" method:"get" tags:"用户" summary:"获取用户列表"` + adminin.MemberListInp +} + +type ListRes struct { + List []*adminin.MemberListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/member/view" method:"get" tags:"用户" summary:"获取指定信息"` + adminin.MemberViewInp +} + +type ViewRes struct { + *adminin.MemberViewModel +} + +// EditReq 修改/新增 +type EditReq struct { + g.Meta `path:"/member/edit" method:"post" tags:"用户" summary:"修改/新增用户"` + adminin.MemberEditInp +} + +type EditRes struct{} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/member/delete" method:"post" tags:"用户" summary:"删除用户"` + adminin.MemberDeleteInp +} + +type DeleteRes struct{} + +// StatusReq 更新用户状态 +type StatusReq struct { + g.Meta `path:"/member/status" method:"post" tags:"用户" summary:"更新用户状态"` + adminin.MemberStatusInp +} + +type StatusRes struct{} + +// SelectReq 获取可选的后台用户选项 +type SelectReq struct { + g.Meta `path:"/member/option" method:"get" tags:"用户" summary:"获取可选的后台用户选项"` + adminin.MemberSelectInp +} + +type SelectRes []*adminin.MemberSelectModel + +// InfoReq 获取登录用户信息 +type InfoReq struct { + g.Meta `path:"/member/info" method:"get" tags:"用户" summary:"获取登录用户信息"` +} + +type InfoRes struct { + *adminin.LoginMemberInfoModel +} + +// AddBalanceReq 增加余额 +type AddBalanceReq struct { + g.Meta `path:"/member/addBalance" method:"post" tags:"用户" summary:"增加余额"` + adminin.MemberAddBalanceInp +} + +type AddBalanceRes struct{} + +// AddIntegralReq 增加积分 +type AddIntegralReq struct { + g.Meta `path:"/member/addIntegral" method:"post" tags:"用户" summary:"增加积分"` + adminin.MemberAddIntegralInp +} + +type AddIntegralRes struct{} diff --git a/server/api/admin/menu/menu.go b/server/api/admin/menu/menu.go new file mode 100644 index 0000000..45351da --- /dev/null +++ b/server/api/admin/menu/menu.go @@ -0,0 +1,39 @@ +// Package menu +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package menu + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/adminin" + "hotgo/internal/model/input/form" +) + +// EditReq 修改/新增菜单 +type EditReq struct { + g.Meta `path:"/menu/edit" method:"post" tags:"菜单" summary:"修改/新增菜单"` + adminin.MenuEditInp +} + +type EditRes struct{} + +// DeleteReq 删除菜单 +type DeleteReq struct { + g.Meta `path:"/menu/delete" method:"post" tags:"菜单" summary:"删除菜单"` + adminin.MenuDeleteInp +} + +type DeleteRes struct{} + +// ListReq 获取菜单列表 +type ListReq struct { + g.Meta `path:"/menu/list" method:"get" tags:"菜单" summary:"获取菜单列表"` + adminin.MenuListInp +} + +type ListRes struct { + *adminin.MenuListModel + form.PageRes +} diff --git a/server/api/admin/monitor/monitor.go b/server/api/admin/monitor/monitor.go new file mode 100644 index 0000000..d86a812 --- /dev/null +++ b/server/api/admin/monitor/monitor.go @@ -0,0 +1,106 @@ +// Package monitor +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package monitor + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "hotgo/internal/library/network/tcp" + "hotgo/internal/model/input/form" +) + +// UserOfflineReq 下线用户 +type UserOfflineReq struct { + g.Meta `path:"/monitor/userOffline" method:"post" tags:"在线用户" summary:"下线用户"` + Id string `json:"id" v:"required#SID不能为空" description:"SID"` +} + +type UserOfflineRes struct{} + +// UserOnlineListReq 获取在线用户列表 +type UserOnlineListReq struct { + g.Meta `path:"/monitor/userOnlineList" method:"get" tags:"在线用户" summary:"获取在线用户列表"` + form.PageReq + UserId int64 `json:"userId" description:"用户ID"` + Username string `json:"username" description:"用户名"` + IP string `json:"ip" description:"登录IP"` + FirstTime []*gtime.Time `json:"firstTime" description:"登录时间"` +} + +type UserOnlineListRes struct { + List []*UserOnlineModel `json:"list" description:"数据列表"` + form.PageRes +} + +type UserOnlineModel struct { + ID string `json:"id"` // 连接唯一标识 + IP string `json:"ip"` // 客户端IP + Os string `json:"os"` // 客户端系统名称 + Browser string `json:"browser"` // 浏览器 + FirstTime int64 `json:"firstTime"` // 首次连接时间 + HeartbeatTime uint64 `json:"heartbeatTime"` // 用户上次心跳时间 + App string `json:"app"` // 应用名称 + UserId int64 `json:"userId"` // 用户ID + Username string `json:"username"` // 用户名 + Avatar string `json:"avatar"` // 头像 +} + +// NetOnlineListReq 获取在线服务列表 +type NetOnlineListReq struct { + g.Meta `path:"/monitor/netOnlineList" method:"get" tags:"在线服务" summary:"获取在线服务列表"` + form.PageReq + Name string `json:"name" description:"应用名称"` + Group string `json:"group" description:"分组"` + AppId string `json:"appId" description:"APPID"` + Addr string `json:"addr" description:"登录地址"` + FirstTime []*gtime.Time `json:"firstTime" description:"登录时间"` +} + +type NetOnlineListRes struct { + List []*NetOnlineModel `json:"list" description:"数据列表"` + form.PageRes +} + +type NetOnlineModel struct { + *tcp.AuthMeta + Id int64 `json:"id" description:"连接ID"` + IsAuth bool `json:"isAuth" description:"是否认证"` + Addr string `json:"addr" description:"登录地址"` + Port string `json:"port" description:"连接端口"` + FirstTime int64 `json:"firstTime" description:"首次连接时间"` + HeartbeatTime int64 `json:"heartbeatTime" description:"上次心跳时间"` + LicenseId int64 `json:"licenseId" description:"许可ID"` + LicenseName string `json:"licenseName" description:"许可名称"` + LoginTimes int64 `json:"loginTimes" description:"许可累计登录次数"` + Online int `json:"online" description:"许可在线数量"` + OnlineLimit int `json:"onlineLimit" description:"许可在线数量限制"` + Desc string `json:"desc" description:"许可说明"` + Proto string `json:"proto" description:"网络协议"` +} + +// NetOptionReq 获取服务选项 +type NetOptionReq struct { + g.Meta `path:"/monitor/netOption" method:"get" tags:"在线服务" summary:"获取服务选项"` +} + +type NetOptionRes struct { + Routes []*RouteSelect `json:"routes" dc:"路由选项"` +} + +type RouteSelect struct { + Value interface{} `json:"value"` + Label string `json:"label"` + Disabled bool `json:"disabled"` + IsRPC bool `json:"isRPC"` +} + +// NetOfflineReq 下线服务 +type NetOfflineReq struct { + g.Meta `path:"/monitor/netOffline" method:"post" tags:"在线服务" summary:"下线服务"` + Id int64 `json:"id" v:"required#连接ID不能为空" description:"连接ID"` +} + +type NetOfflineRes struct{} diff --git a/server/api/admin/normaltreedemo/normaltreedemo.go b/server/api/admin/normaltreedemo/normaltreedemo.go new file mode 100644 index 0000000..62dff51 --- /dev/null +++ b/server/api/admin/normaltreedemo/normaltreedemo.go @@ -0,0 +1,69 @@ +// Package normaltreedemo +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.15.7 +package normaltreedemo + +import ( + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" + "hotgo/utility/tree" + + "github.com/gogf/gf/v2/frame/g" +) + +// ListReq 查询普通树表列表 +type ListReq struct { + g.Meta `path:"/normalTreeDemo/list" method:"get" tags:"普通树表" summary:"获取普通树表列表"` + sysin.NormalTreeDemoListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.NormalTreeDemoListModel `json:"list" dc:"数据列表"` +} + +// ViewReq 获取普通树表指定信息 +type ViewReq struct { + g.Meta `path:"/normalTreeDemo/view" method:"get" tags:"普通树表" summary:"获取普通树表指定信息"` + sysin.NormalTreeDemoViewInp +} + +type ViewRes struct { + *sysin.NormalTreeDemoViewModel +} + +// EditReq 修改/新增普通树表 +type EditReq struct { + g.Meta `path:"/normalTreeDemo/edit" method:"post" tags:"普通树表" summary:"修改/新增普通树表"` + sysin.NormalTreeDemoEditInp +} + +type EditRes struct{} + +// DeleteReq 删除普通树表 +type DeleteReq struct { + g.Meta `path:"/normalTreeDemo/delete" method:"post" tags:"普通树表" summary:"删除普通树表"` + sysin.NormalTreeDemoDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 获取普通树表最大排序 +type MaxSortReq struct { + g.Meta `path:"/normalTreeDemo/maxSort" method:"get" tags:"普通树表" summary:"获取普通树表最大排序"` + sysin.NormalTreeDemoMaxSortInp +} + +type MaxSortRes struct { + *sysin.NormalTreeDemoMaxSortModel +} + +// TreeOptionReq 获取普通树表关系树选项 +type TreeOptionReq struct { + g.Meta `path:"/normalTreeDemo/treeOption" method:"get" tags:"普通树表" summary:"获取普通树表关系树选项"` +} + +type TreeOptionRes []tree.Node diff --git a/server/api/admin/notice/notice.go b/server/api/admin/notice/notice.go new file mode 100644 index 0000000..75232df --- /dev/null +++ b/server/api/admin/notice/notice.go @@ -0,0 +1,128 @@ +// Package notice +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package notice + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/adminin" + "hotgo/internal/model/input/form" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/notice/list" method:"get" tags:"公告" summary:"获取公告列表"` + adminin.NoticeListInp +} + +type ListRes struct { + List []*adminin.NoticeListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/notice/view" method:"get" tags:"公告" summary:"获取指定信息"` + adminin.NoticeViewInp +} + +type ViewRes struct { + *adminin.NoticeViewModel +} + +// EditReq 修改/新增字典数据 +type EditReq struct { + g.Meta `path:"/notice/edit" method:"post" tags:"公告" summary:"修改/新增公告"` + adminin.NoticeEditInp +} + +type EditRes struct{} + +// DeleteReq 删除字典类型 +type DeleteReq struct { + g.Meta `path:"/notice/delete" method:"post" tags:"公告" summary:"删除公告"` + adminin.NoticeDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 最大排序 +type MaxSortReq struct { + g.Meta `path:"/notice/maxSort" method:"get" tags:"公告" summary:"公告最大排序"` + adminin.NoticeMaxSortInp +} + +type MaxSortRes struct { + *adminin.NoticeMaxSortModel +} + +// StatusReq 更新公告状态 +type StatusReq struct { + g.Meta `path:"/notice/status" method:"post" tags:"公告" summary:"更新公告状态"` + adminin.NoticeStatusInp +} + +type StatusRes struct{} + +// EditNotifyReq 修改/新增通知 +type EditNotifyReq struct { + g.Meta `path:"/notice/editNotify" method:"post" tags:"公告" summary:"修改/新增通知"` + adminin.NoticeEditInp +} + +type EditNotifyRes struct{} + +// EditNoticeReq 修改/新增公告 +type EditNoticeReq struct { + g.Meta `path:"/notice/editNotice" method:"post" tags:"公告" summary:"修改/新增公告"` + adminin.NoticeEditInp +} + +type EditNoticeRes struct{} + +// EditLetterReq 修改/新增公告 +type EditLetterReq struct { + g.Meta `path:"/notice/editLetter" method:"post" tags:"公告" summary:"修改/新增私信"` + adminin.NoticeEditInp +} + +type EditLetterRes struct{} + +// PullMessagesReq 拉取我的消息 +type PullMessagesReq struct { + g.Meta `path:"/notice/pullMessages" method:"get" tags:"公告" summary:"拉取我的消息"` + adminin.PullMessagesInp +} + +type PullMessagesRes struct { + *adminin.PullMessagesModel +} + +// ReadAllReq 全部已读 +type ReadAllReq struct { + g.Meta `path:"/notice/readAll" method:"post" tags:"公告" summary:"全部已读"` + adminin.NoticeReadAllInp +} + +type ReadAllRes struct { +} + +// UpReadReq 更新已读 +type UpReadReq struct { + g.Meta `path:"/notice/upRead" method:"post" tags:"公告" summary:"更新已读"` + adminin.NoticeUpReadInp +} +type UpReadRes struct{} + +// MessageListReq 我的消息列表 +type MessageListReq struct { + g.Meta `path:"/notice/messageList" method:"get" tags:"公告" summary:"我的消息列表"` + adminin.NoticeMessageListInp +} + +type MessageListRes struct { + List []*adminin.NoticeMessageListModel `json:"list" dc:"数据列表"` + form.PageRes +} diff --git a/server/api/admin/optiontreedemo/optiontreedemo.go b/server/api/admin/optiontreedemo/optiontreedemo.go new file mode 100644 index 0000000..70d0c63 --- /dev/null +++ b/server/api/admin/optiontreedemo/optiontreedemo.go @@ -0,0 +1,69 @@ +// Package optiontreedemo +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2025 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.17.8 +package optiontreedemo + +import ( + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" + "hotgo/utility/tree" + + "github.com/gogf/gf/v2/frame/g" +) + +// ListReq 查询选项树表列表 +type ListReq struct { + g.Meta `path:"/optionTreeDemo/list" method:"get" tags:"选项树表" summary:"获取选项树表列表"` + sysin.OptionTreeDemoListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.OptionTreeDemoListModel `json:"list" dc:"数据列表"` +} + +// ViewReq 获取选项树表指定信息 +type ViewReq struct { + g.Meta `path:"/optionTreeDemo/view" method:"get" tags:"选项树表" summary:"获取选项树表指定信息"` + sysin.OptionTreeDemoViewInp +} + +type ViewRes struct { + *sysin.OptionTreeDemoViewModel +} + +// EditReq 修改/新增选项树表 +type EditReq struct { + g.Meta `path:"/optionTreeDemo/edit" method:"post" tags:"选项树表" summary:"修改/新增选项树表"` + sysin.OptionTreeDemoEditInp +} + +type EditRes struct{} + +// DeleteReq 删除选项树表 +type DeleteReq struct { + g.Meta `path:"/optionTreeDemo/delete" method:"post" tags:"选项树表" summary:"删除选项树表"` + sysin.OptionTreeDemoDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 获取选项树表最大排序 +type MaxSortReq struct { + g.Meta `path:"/optionTreeDemo/maxSort" method:"get" tags:"选项树表" summary:"获取选项树表最大排序"` + sysin.OptionTreeDemoMaxSortInp +} + +type MaxSortRes struct { + *sysin.OptionTreeDemoMaxSortModel +} + +// TreeOptionReq 获取选项树表关系树选项 +type TreeOptionReq struct { + g.Meta `path:"/optionTreeDemo/treeOption" method:"get" tags:"选项树表" summary:"获取选项树表关系树选项"` +} + +type TreeOptionRes []tree.Node \ No newline at end of file diff --git a/server/api/admin/order/order.go b/server/api/admin/order/order.go new file mode 100644 index 0000000..425921f --- /dev/null +++ b/server/api/admin/order/order.go @@ -0,0 +1,93 @@ +// Package order +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package order + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/adminin" + "hotgo/internal/model/input/form" +) + +// AcceptRefundReq 受理申请退款 +type AcceptRefundReq struct { + g.Meta `path:"/order/acceptRefund" method:"post" tags:"充值订单" summary:"受理申请退款"` + adminin.OrderAcceptRefundInp +} + +type AcceptRefundRes struct { +} + +// ApplyRefundReq 申请退款 +type ApplyRefundReq struct { + g.Meta `path:"/order/applyRefund" method:"post" tags:"充值订单" summary:"申请退款"` + adminin.OrderApplyRefundInp +} + +type ApplyRefundRes struct { +} + +// CreateReq 创建充值订单 +type CreateReq struct { + g.Meta `path:"/order/create" method:"post" tags:"充值订单" summary:"创建充值订单"` + adminin.OrderCreateInp +} + +type CreateRes struct { + *adminin.OrderCreateModel +} + +// ListReq 查询充值订单列表 +type ListReq struct { + g.Meta `path:"/order/list" method:"get" tags:"充值订单" summary:"获取充值订单列表"` + adminin.OrderListInp +} + +type ListRes struct { + form.PageRes + List []*adminin.OrderListModel `json:"list" dc:"数据列表"` +} + +// ExportReq 导出充值订单列表 +type ExportReq struct { + g.Meta `path:"/order/export" method:"get" tags:"充值订单" summary:"导出充值订单列表"` + adminin.OrderListInp +} + +type ExportRes struct{} + +// ViewReq 获取充值订单指定信息 +type ViewReq struct { + g.Meta `path:"/order/view" method:"get" tags:"充值订单" summary:"获取充值订单指定信息"` + adminin.OrderViewInp +} + +type ViewRes struct { + *adminin.OrderViewModel +} + +// EditReq 修改/新增充值订单 +type EditReq struct { + g.Meta `path:"/order/edit" method:"post" tags:"充值订单" summary:"修改/新增充值订单"` + adminin.OrderEditInp +} + +type EditRes struct{} + +// DeleteReq 删除充值订单 +type DeleteReq struct { + g.Meta `path:"/order/delete" method:"post" tags:"充值订单" summary:"删除充值订单"` + adminin.OrderDeleteInp +} + +type DeleteRes struct{} + +// StatusReq 更新充值订单状态 +type StatusReq struct { + g.Meta `path:"/order/status" method:"post" tags:"充值订单" summary:"更新充值订单状态"` + adminin.OrderStatusInp +} + +type StatusRes struct{} diff --git a/server/api/admin/pay/refund.go b/server/api/admin/pay/refund.go new file mode 100644 index 0000000..dfbab3b --- /dev/null +++ b/server/api/admin/pay/refund.go @@ -0,0 +1,33 @@ +// Package pay +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.5.3 +// @AutoGenerate Date 2023-04-15 15:59:58 +package pay + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/payin" +) + +// RefundListReq 查询交易退款列表 +type RefundListReq struct { + g.Meta `path:"/payRefund/list" method:"get" tags:"交易退款" summary:"获取交易退款列表"` + payin.PayRefundListInp +} + +type RefundListRes struct { + form.PageRes + List []*payin.PayRefundListModel `json:"list" dc:"数据列表"` +} + +// RefundExportReq 导出交易退款列表 +type RefundExportReq struct { + g.Meta `path:"/payRefund/export" method:"get" tags:"交易退款" summary:"导出交易退款列表"` + payin.PayRefundListInp +} + +type RefundExportRes struct{} diff --git a/server/api/admin/post/post.go b/server/api/admin/post/post.go new file mode 100644 index 0000000..e0659a6 --- /dev/null +++ b/server/api/admin/post/post.go @@ -0,0 +1,67 @@ +// Package post +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package post + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/adminin" + "hotgo/internal/model/input/form" +) + +// EditReq 修改/新增岗位 +type EditReq struct { + g.Meta `path:"/post/edit" method:"post" tags:"岗位" summary:"修改/新增岗位"` + adminin.PostEditInp +} + +type EditRes struct{} + +// DeleteReq 删除岗位 +type DeleteReq struct { + g.Meta `path:"/post/delete" method:"post" tags:"岗位" summary:"删除岗位"` + adminin.PostDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 最大排序 +type MaxSortReq struct { + g.Meta `path:"/post/maxSort" method:"get" tags:"岗位" summary:"岗位最大排序"` + adminin.PostMaxSortInp +} + +type MaxSortRes struct { + *adminin.PostMaxSortModel +} + +// ListReq 获取列表 +type ListReq struct { + g.Meta `path:"/post/list" method:"get" tags:"岗位" summary:"获取岗位列表"` + adminin.PostListInp +} + +type ListRes struct { + List []*adminin.PostListModel `json:"list" description:"数据列表"` + form.PageRes +} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/post/view" method:"get" tags:"岗位" summary:"获取指定信息"` + adminin.PostViewInp +} + +type ViewRes struct { + *adminin.PostViewModel +} + +// StatusReq 更新状态 +type StatusReq struct { + g.Meta `path:"/post/status" method:"post" tags:"岗位" summary:"更新岗位状态"` + adminin.PostStatusInp +} + +type StatusRes struct{} diff --git a/server/api/admin/provinces/provinces.go b/server/api/admin/provinces/provinces.go new file mode 100644 index 0000000..d6bc9fd --- /dev/null +++ b/server/api/admin/provinces/provinces.go @@ -0,0 +1,115 @@ +// Package provinces +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package provinces + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/provinces/list" method:"get" tags:"省市区" summary:"获取省市区列表"` + sysin.ProvincesListInp +} + +type ListRes struct { + List []*sysin.ProvincesListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取信息 +type ViewReq struct { + g.Meta `path:"/provinces/view" method:"get" tags:"省市区" summary:"获取指定信息"` + sysin.ProvincesViewInp +} + +type ViewRes struct { + *sysin.ProvincesViewModel +} + +// EditReq 修改/新增 +type EditReq struct { + g.Meta `path:"/provinces/edit" method:"post" tags:"省市区" summary:"修改/新增省市区"` + sysin.ProvincesEditInp +} + +type EditRes struct{} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/provinces/delete" method:"post" tags:"省市区" summary:"删除省市区"` + sysin.ProvincesDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 最大排序 +type MaxSortReq struct { + g.Meta `path:"/provinces/maxSort" method:"get" tags:"省市区" summary:"省市区最大排序"` + sysin.ProvincesMaxSortInp +} + +type MaxSortRes struct { + *sysin.ProvincesMaxSortModel +} + +// StatusReq 更新状态 +type StatusReq struct { + g.Meta `path:"/provinces/status" method:"post" tags:"省市区" summary:"更新省市区状态"` + sysin.ProvincesStatusInp +} + +type StatusRes struct{} + +// TreeReq 关系树选项列表 +type TreeReq struct { + g.Meta `path:"/provinces/tree" tags:"省市区" method:"get" summary:"省市区关系树选项列表"` +} + +type TreeRes struct { + List []*sysin.ProvincesTree `json:"list" dc:"数据列表"` +} + +// ChildrenListReq 获取省市区下级列表 +type ChildrenListReq struct { + g.Meta `path:"/provinces/childrenList" method:"get" tags:"省市区" summary:"获取省市区下级列表"` + sysin.ProvincesChildrenListInp +} + +type ChildrenListRes struct { + List []*sysin.ProvincesChildrenListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// UniqueIdReq 地区ID是否唯一 +type UniqueIdReq struct { + g.Meta `path:"/provinces/uniqueId" method:"get" tags:"省市区" summary:"地区ID是否唯一"` + sysin.ProvincesUniqueIdInp +} + +type UniqueIdRes struct { + *sysin.ProvincesUniqueIdModel +} + +// SelectReq 省市区选项 +type SelectReq struct { + g.Meta `path:"/provinces/select" method:"get" tags:"省市区" summary:"省市区选项"` + sysin.ProvincesSelectInp +} + +type SelectRes struct { + *sysin.ProvincesSelectModel +} + +// CityLabelReq 获取指定城市标签 +type CityLabelReq struct { + g.Meta `path:"/provinces/cityLabel" method:"get" tags:"省市区" summary:"获取指定城市标签" ` + sysin.ProvincesCityLabelInp +} + +type CityLabelRes sysin.ProvincesCityLabelModel diff --git a/server/api/admin/role/role.go b/server/api/admin/role/role.go new file mode 100644 index 0000000..bbae5a1 --- /dev/null +++ b/server/api/admin/role/role.go @@ -0,0 +1,82 @@ +// Package role +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package role + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/consts" + "hotgo/internal/model/input/adminin" + "hotgo/internal/model/input/form" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/role/list" method:"get" tags:"角色" summary:"获取角色列表"` + adminin.RoleListInp +} + +type ListRes struct { + *adminin.RoleListModel + form.PageRes +} + +// DynamicReq 动态路由 +type DynamicReq struct { + g.Meta `path:"/role/dynamic" method:"get" tags:"角色" summary:"获取动态路由" description:"获取登录用户动态路由"` +} + +type DynamicRes struct { + List []*adminin.MenuRoute `json:"list" description:"数据列表"` +} + +type UpdatePermissionsReq struct { + g.Meta `path:"/role/updatePermissions" method:"post" tags:"角色" summary:"编辑角色菜单权限"` + adminin.UpdatePermissionsInp +} + +type UpdatePermissionsRes struct{} + +type GetPermissionsReq struct { + g.Meta `path:"/role/getPermissions" method:"get" tags:"角色" summary:"获取指定角色权限"` + adminin.GetPermissionsInp +} + +type GetPermissionsRes struct { + *adminin.GetPermissionsModel +} + +// EditReq 修改/新增角色 +type EditReq struct { + g.Meta `path:"/role/edit" method:"post" tags:"角色" summary:"修改/新增角色"` + adminin.RoleEditInp +} + +type EditRes struct{} + +// DeleteReq 删除角色 +type DeleteReq struct { + g.Meta `path:"/role/delete" method:"post" tags:"角色" summary:"删除角色"` + adminin.RoleDeleteInp +} + +type DeleteRes struct{} + +// DataScopeSelectReq 获取数据权限选项 +type DataScopeSelectReq struct { + g.Meta `path:"/role/dataScope/select" method:"get" tags:"角色" summary:"获取数据权限选项"` +} + +type DataScopeSelectRes struct { + List []consts.GroupScopeSelect `json:"list" dc:"数据选项"` +} + +// DataScopeEditReq 修改指定角色的数据权限 +type DataScopeEditReq struct { + g.Meta `path:"/role/dataScope/edit" method:"post" tags:"角色" summary:"修改指定角色的数据权限"` + adminin.DataScopeEditInp +} + +type DataScopeEditRes struct{} diff --git a/server/api/admin/servelicense/servelicense.go b/server/api/admin/servelicense/servelicense.go new file mode 100644 index 0000000..78c7f20 --- /dev/null +++ b/server/api/admin/servelicense/servelicense.go @@ -0,0 +1,74 @@ +// Package servelicense +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.7.6 +package servelicense + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询服务许可证列表 +type ListReq struct { + g.Meta `path:"/serveLicense/list" method:"get" tags:"服务许可证" summary:"获取服务许可证列表"` + sysin.ServeLicenseListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.ServeLicenseListModel `json:"list" dc:"数据列表"` +} + +// ExportReq 导出服务许可证列表 +type ExportReq struct { + g.Meta `path:"/serveLicense/export" method:"get" tags:"服务许可证" summary:"导出服务许可证列表"` + sysin.ServeLicenseListInp +} + +type ExportRes struct{} + +// ViewReq 获取服务许可证指定信息 +type ViewReq struct { + g.Meta `path:"/serveLicense/view" method:"get" tags:"服务许可证" summary:"获取服务许可证指定信息"` + sysin.ServeLicenseViewInp +} + +type ViewRes struct { + *sysin.ServeLicenseViewModel +} + +// EditReq 修改/新增服务许可证 +type EditReq struct { + g.Meta `path:"/serveLicense/edit" method:"post" tags:"服务许可证" summary:"修改/新增服务许可证"` + sysin.ServeLicenseEditInp +} + +type EditRes struct{} + +// DeleteReq 删除服务许可证 +type DeleteReq struct { + g.Meta `path:"/serveLicense/delete" method:"post" tags:"服务许可证" summary:"删除服务许可证"` + sysin.ServeLicenseDeleteInp +} + +type DeleteRes struct{} + +// StatusReq 更新服务许可证状态 +type StatusReq struct { + g.Meta `path:"/serveLicense/status" method:"post" tags:"服务许可证" summary:"更新服务许可证状态"` + sysin.ServeLicenseStatusInp +} + +type StatusRes struct{} + +// AssignRouterReq 分配服务许可证路由 +type AssignRouterReq struct { + g.Meta `path:"/serveLicense/assignRouter" method:"post" tags:"服务许可证" summary:"分配服务许可证路由"` + sysin.ServeLicenseAssignRouterInp +} + +type AssignRouterRes struct{} diff --git a/server/api/admin/servelog/servelog.go b/server/api/admin/servelog/servelog.go new file mode 100644 index 0000000..d250cd1 --- /dev/null +++ b/server/api/admin/servelog/servelog.go @@ -0,0 +1,49 @@ +// Package servelog +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package servelog + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询服务日志列表 +type ListReq struct { + g.Meta `path:"/serveLog/list" method:"get" tags:"服务日志" summary:"获取服务日志列表"` + sysin.ServeLogListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.ServeLogListModel `json:"list" dc:"数据列表"` +} + +// ExportReq 导出服务日志列表 +type ExportReq struct { + g.Meta `path:"/serveLog/export" method:"get" tags:"服务日志" summary:"导出服务日志列表"` + sysin.ServeLogListInp +} + +type ExportRes struct{} + +// ViewReq 获取服务日志指定信息 +type ViewReq struct { + g.Meta `path:"/serveLog/view" method:"get" tags:"服务日志" summary:"获取服务日志指定信息"` + sysin.ServeLogViewInp +} + +type ViewRes struct { + *sysin.ServeLogViewModel +} + +// DeleteReq 删除服务日志 +type DeleteReq struct { + g.Meta `path:"/serveLog/delete" method:"post" tags:"服务日志" summary:"删除服务日志"` + sysin.ServeLogDeleteInp +} + +type DeleteRes struct{} diff --git a/server/api/admin/smslog/smslog.go b/server/api/admin/smslog/smslog.go new file mode 100644 index 0000000..ed97c2d --- /dev/null +++ b/server/api/admin/smslog/smslog.go @@ -0,0 +1,41 @@ +// Package smslog +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package smslog + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" +) + +// ListReq 查询列表 +type ListReq struct { + g.Meta `path:"/smsLog/list" method:"get" tags:"短信" summary:"获取短信记录列表"` + sysin.SmsLogListInp +} + +type ListRes struct { + List []*sysin.SmsLogListModel `json:"list" dc:"数据列表"` + form.PageRes +} + +// ViewReq 获取指定信息 +type ViewReq struct { + g.Meta `path:"/smsLog/view" method:"get" tags:"短信" summary:"获取指定短信信息"` + sysin.SmsLogViewInp +} + +type ViewRes struct { + *sysin.SmsLogViewModel +} + +// DeleteReq 删除 +type DeleteReq struct { + g.Meta `path:"/smsLog/delete" method:"post" tags:"短信" summary:"删除短信记录"` + sysin.SmsLogDeleteInp +} + +type DeleteRes struct{} diff --git a/server/api/admin/testcategory/testcategory.go b/server/api/admin/testcategory/testcategory.go new file mode 100644 index 0000000..7a8eca3 --- /dev/null +++ b/server/api/admin/testcategory/testcategory.go @@ -0,0 +1,69 @@ +// Package testcategory +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.15.7 +package testcategory + +import ( + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" + + "github.com/gogf/gf/v2/frame/g" +) + +// ListReq 查询测试分类列表 +type ListReq struct { + g.Meta `path:"/testCategory/list" method:"get" tags:"测试分类" summary:"获取测试分类列表"` + sysin.TestCategoryListInp +} + +type ListRes struct { + form.PageRes + List []*sysin.TestCategoryListModel `json:"list" dc:"数据列表"` +} + +// ViewReq 获取测试分类指定信息 +type ViewReq struct { + g.Meta `path:"/testCategory/view" method:"get" tags:"测试分类" summary:"获取测试分类指定信息"` + sysin.TestCategoryViewInp +} + +type ViewRes struct { + *sysin.TestCategoryViewModel +} + +// EditReq 修改/新增测试分类 +type EditReq struct { + g.Meta `path:"/testCategory/edit" method:"post" tags:"测试分类" summary:"修改/新增测试分类"` + sysin.TestCategoryEditInp +} + +type EditRes struct{} + +// DeleteReq 删除测试分类 +type DeleteReq struct { + g.Meta `path:"/testCategory/delete" method:"post" tags:"测试分类" summary:"删除测试分类"` + sysin.TestCategoryDeleteInp +} + +type DeleteRes struct{} + +// MaxSortReq 获取测试分类最大排序 +type MaxSortReq struct { + g.Meta `path:"/testCategory/maxSort" method:"get" tags:"测试分类" summary:"获取测试分类最大排序"` + sysin.TestCategoryMaxSortInp +} + +type MaxSortRes struct { + *sysin.TestCategoryMaxSortModel +} + +// StatusReq 更新测试分类状态 +type StatusReq struct { + g.Meta `path:"/testCategory/status" method:"post" tags:"测试分类" summary:"更新测试分类状态"` + sysin.TestCategoryStatusInp +} + +type StatusRes struct{} diff --git a/server/api/api/member/member.go b/server/api/api/member/member.go new file mode 100644 index 0000000..d335001 --- /dev/null +++ b/server/api/api/member/member.go @@ -0,0 +1,15 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package member + +import ( + "context" + + "hotgo/api/api/member/v1" +) + +type IMemberV1 interface { + GetIdByCode(ctx context.Context, req *v1.GetIdByCodeReq) (res *v1.GetIdByCodeRes, err error) +} diff --git a/server/api/api/member/v1/member.go b/server/api/api/member/v1/member.go new file mode 100644 index 0000000..0ed4bb6 --- /dev/null +++ b/server/api/api/member/v1/member.go @@ -0,0 +1,16 @@ +// Package member +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package v1 + +import "github.com/gogf/gf/v2/frame/g" + +// GetIdByCodeReq 通过邀请码获取用户ID +type GetIdByCodeReq struct { + g.Meta `path:"/member/getIdByCode" method:"post" tags:"用户" summary:"通过邀请码获取用户ID"` + Code string `json:"code" dc:"邀请码"` +} + +type GetIdByCodeRes struct{} diff --git a/server/api/api/pay/pay.go b/server/api/api/pay/pay.go new file mode 100644 index 0000000..654099c --- /dev/null +++ b/server/api/api/pay/pay.go @@ -0,0 +1,17 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package pay + +import ( + "context" + + "hotgo/api/api/pay/v1" +) + +type IPayV1 interface { + NotifyAliPay(ctx context.Context, req *v1.NotifyAliPayReq) (res *v1.NotifyAliPayRes, err error) + NotifyWxPay(ctx context.Context, req *v1.NotifyWxPayReq) (res *v1.NotifyWxPayRes, err error) + NotifyQQPay(ctx context.Context, req *v1.NotifyQQPayReq) (res *v1.NotifyQQPayRes, err error) +} diff --git a/server/api/api/pay/v1/notify.go b/server/api/api/pay/v1/notify.go new file mode 100644 index 0000000..8ac343b --- /dev/null +++ b/server/api/api/pay/v1/notify.go @@ -0,0 +1,41 @@ +// Package pay +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package v1 + +import ( + "hotgo/internal/model/input/payin" + + "github.com/gogf/gf/v2/frame/g" +) + +// NotifyAliPayReq 支付宝回调 +type NotifyAliPayReq struct { + g.Meta `path:"/pay/notify/alipay" method:"post" tags:"支付异步通知" summary:"支付宝回调"` +} + +type NotifyAliPayRes struct { + g.Meta `mime:"text/html" type:"string" example:""` + *payin.PayNotifyModel +} + +// NotifyWxPayReq 微信支付回调 +type NotifyWxPayReq struct { + g.Meta `path:"/pay/notify/wxpay" method:"post" tags:"支付异步通知" summary:"微信支付回调"` +} + +type NotifyWxPayRes struct { + *payin.PayNotifyModel +} + +// NotifyQQPayReq QQ支付回调 +type NotifyQQPayReq struct { + g.Meta `path:"/pay/notify/qqpay" method:"post" tags:"支付异步通知" summary:"QQ支付回调"` +} + +type NotifyQQPayRes struct { + g.Meta `mime:"text/xml" type:"string"` + *payin.PayNotifyModel +} diff --git a/server/api/home/base/site.go b/server/api/home/base/site.go new file mode 100644 index 0000000..d70f5ba --- /dev/null +++ b/server/api/home/base/site.go @@ -0,0 +1,16 @@ +// Package base +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package base + +import "github.com/gogf/gf/v2/frame/g" + +type SiteIndexReq struct { + g.Meta `path:"/" method:"get" summary:"首页" tags:"首页"` +} + +type SiteIndexRes struct { + g.Meta `mime:"text/html" type:"string" example:""` +} diff --git a/server/api/servmsg/auth.go b/server/api/servmsg/auth.go new file mode 100644 index 0000000..e071144 --- /dev/null +++ b/server/api/servmsg/auth.go @@ -0,0 +1,21 @@ +// Package servmsg +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package servmsg + +import ( + "hotgo/internal/library/network/tcp" + "hotgo/internal/model/input/servmsgin" +) + +// AuthSummaryReq 授权信息 +type AuthSummaryReq struct { +} + +// AuthSummaryRes 响应授权信息 +type AuthSummaryRes struct { + tcp.ServerRes + Data *servmsgin.AuthSummaryModel `json:"data,omitempty" description:"数据集"` +} diff --git a/server/api/servmsg/cron.go b/server/api/servmsg/cron.go new file mode 100644 index 0000000..ab3eafa --- /dev/null +++ b/server/api/servmsg/cron.go @@ -0,0 +1,57 @@ +// Package servmsg +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package servmsg + +import ( + "hotgo/internal/library/network/tcp" + "hotgo/internal/model/input/sysin" +) + +// CronDeleteReq 删除任务 +type CronDeleteReq struct { + *sysin.CronDeleteInp +} + +type CronDeleteRes struct { + tcp.ServerRes +} + +// CronEditReq 编辑任务 +type CronEditReq struct { + *sysin.CronEditInp +} + +type CronEditRes struct { + tcp.ServerRes +} + +// CronStatusReq 修改任务状态 +type CronStatusReq struct { + *sysin.CronStatusInp +} + +type CronStatusRes struct { + tcp.ServerRes +} + +// CronOnlineExecReq 在线执行 +type CronOnlineExecReq struct { + *sysin.OnlineExecInp +} + +type CronOnlineExecRes struct { + tcp.ServerRes +} + +// CronDispatchLogReq 调度日志 +type CronDispatchLogReq struct { + *sysin.DispatchLogInp +} + +type CronDispatchLogRes struct { + tcp.ServerRes + *sysin.DispatchLogModel +} diff --git a/server/api/servmsg/example.go b/server/api/servmsg/example.go new file mode 100644 index 0000000..c469ebf --- /dev/null +++ b/server/api/servmsg/example.go @@ -0,0 +1,33 @@ +// Package servmsg +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package servmsg + +import ( + "hotgo/internal/library/network/tcp" + "hotgo/internal/model/input/servmsgin" +) + +// 一些例子. + +// ExampleHelloReq 一个tcp请求例子 +type ExampleHelloReq struct { + Name string `json:"name" description:"名字"` +} + +type ExampleHelloRes struct { + tcp.ServerRes + Data *servmsgin.ExampleHelloModel `json:"data,omitempty" description:"数据集"` +} + +// ExampleRPCHelloReq 一个rpc请求例子 +type ExampleRPCHelloReq struct { + Name string `json:"name" description:"名字"` +} + +type ExampleRPCHelloRes struct { + tcp.ServerRes + Data *servmsgin.ExampleHelloModel `json:"data,omitempty" description:"数据集"` +} diff --git a/server/api/websocket/base/send.go b/server/api/websocket/base/send.go new file mode 100644 index 0000000..b67d70b --- /dev/null +++ b/server/api/websocket/base/send.go @@ -0,0 +1,20 @@ +// Package base +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package base + +import ( + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model/input/websocketin" +) + +// SendToTagReq 发送标签消息 +type SendToTagReq struct { + g.Meta `path:"/send/toTag" method:"post" tags:"WebSocket" summary:"发送标签消息"` + websocketin.SendToTagInp +} + +type SendToTagRes struct { +} diff --git a/server/go.mod b/server/go.mod new file mode 100644 index 0000000..25bab3f --- /dev/null +++ b/server/go.mod @@ -0,0 +1,162 @@ +module hotgo + +go 1.24.4 + +require ( + github.com/IBM/sarama v1.45.2 + github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 + github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6 + github.com/alibabacloud-go/tea v1.3.9 + github.com/alibabacloud-go/tea-utils/v2 v2.0.7 + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible + github.com/apache/rocketmq-client-go/v2 v2.1.2 + github.com/casbin/casbin/v2 v2.108.0 + github.com/forgoer/openssl v1.6.1 + github.com/go-pay/crypto v0.0.1 + github.com/go-pay/gopay v1.5.114 + github.com/go-pay/smap v0.0.2 + github.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0 + github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0 + github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0 + github.com/gogf/gf/contrib/trace/jaeger/v2 v2.7.4 + github.com/gogf/gf/v2 v2.10.0 + github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f + github.com/golang-jwt/jwt/v5 v5.2.2 + github.com/gorilla/websocket v1.5.3 + github.com/kayon/iploc v0.0.0-20200312105652-bda3e968a794 + github.com/minio/minio-go/v7 v7.0.94 + github.com/mojocn/base64Captcha v1.3.8 + github.com/olekukonko/tablewriter v1.1.0 + github.com/qiniu/go-sdk/v7 v7.25.4 + github.com/schollz/progressbar/v3 v3.18.0 + github.com/shirou/gopsutil/v3 v3.24.5 + github.com/silenceper/wechat/v2 v2.1.9 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1202 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1200 + github.com/tencentyun/cos-go-sdk-v5 v0.7.66 + github.com/ufilesdk-dev/ufile-gosdk v1.0.6 + github.com/xuri/excelize/v2 v2.9.1 + go.opentelemetry.io/otel v1.38.0 + golang.org/x/mod v0.26.0 + golang.org/x/net v0.43.0 + golang.org/x/tools v0.35.0 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + aead.dev/minisign v0.2.0 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 // indirect + github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect + github.com/alibabacloud-go/debug v1.0.1 // indirect + github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect + github.com/alibabacloud-go/openapi-util v0.1.0 // indirect + github.com/alibabacloud-go/tea-utils v1.3.1 // indirect + github.com/aliyun/credentials-go v1.4.5 // indirect + github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect + github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d // indirect + github.com/casbin/govaluate v1.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/clbanning/mxj v1.8.4 // indirect + github.com/clbanning/mxj/v2 v2.7.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/eapache/go-resiliency v1.7.0 // indirect + github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect + github.com/eapache/queue v1.1.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/fatih/structs v1.1.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/gammazero/toposort v0.1.1 // indirect + github.com/go-ini/ini v1.67.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-pay/errgroup v0.0.3 // indirect + github.com/go-pay/util v0.0.4 // indirect + github.com/go-pay/xlog v0.0.3 // indirect + github.com/go-pay/xtime v0.0.2 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-sql-driver/mysql v1.7.1 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/gofrs/flock v0.8.1 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/golang/mock v1.4.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/go-querystring v1.0.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.10 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/minio/crc64nvme v1.0.1 // indirect + github.com/minio/md5-simd v1.1.2 // indirect + github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mozillazg/go-httpheader v0.2.1 // indirect + github.com/olekukonko/errors v1.1.0 // indirect + github.com/olekukonko/ll v0.0.9 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/pkg/errors v0.8.1 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/redis/go-redis/v9 v9.12.1 // indirect + github.com/richardlehane/mscfb v1.0.4 // indirect + github.com/richardlehane/msoleps v1.0.4 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/rs/xid v1.6.0 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/tidwall/gjson v1.14.1 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tiendc/go-deepcopy v1.6.0 // indirect + github.com/tinylib/msgp v1.3.0 // indirect + github.com/tjfoc/gmsm v1.4.1 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/xuri/efp v0.0.1 // indirect + github.com/xuri/nfp v0.0.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.14.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.uber.org/atomic v1.5.1 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/image v0.25.0 // indirect + golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/time v0.12.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + modernc.org/fileutil v1.0.0 // indirect + stathat.com/c/consistent v1.0.0 // indirect +) diff --git a/server/go.sum b/server/go.sum new file mode 100644 index 0000000..ce59b74 --- /dev/null +++ b/server/go.sum @@ -0,0 +1,700 @@ +aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk= +aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/IBM/sarama v1.45.2 h1:8m8LcMCu3REcwpa7fCP6v2fuPuzVwXDAM2DOv3CBrKw= +github.com/IBM/sarama v1.45.2/go.mod h1:ppaoTcVdGv186/z6MEKsMm70A5fwJfRTpstI37kVn3Y= +github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= +github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 h1:7dONQ3WNZ1zy960TmkxJPuwoolZwL7xKtpcM04MBnt4= +github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82/go.mod h1:nLnM0KdK1CmygvjpDUO6m1TjSsiQtL61juhNsvV/JVI= +github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA= +github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g= +github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY= +github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI= +github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE= +github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8= +github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc= +github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 h1:ASXSBga98QrGMxbIThCD6jAti09gedLfvry6yJtsoBE= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7/go.mod h1:TBpgqm3XofZz2LCYjZhektGPU7ArEgascyzbm4SjFo4= +github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg= +github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ= +github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo= +github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg= +github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6 h1:UTl97mt2qfavxveqCkaVg4tKaZUPzA9RKbFIRaIdtdg= +github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6/go.mod h1:UWpcGrWwTbES9QW7OQ7xDffukMJ/l7lzioixIz8+lgY= +github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY= +github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= +github.com/alibabacloud-go/tea v1.3.8/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg= +github.com/alibabacloud-go/tea v1.3.9 h1:bjgt1bvdY780vz/17iWNNtbXl4A77HWntWMeaUF3So0= +github.com/alibabacloud-go/tea v1.3.9/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg= +github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils/v2 v2.0.0/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4= +github.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ= +github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4= +github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0= +github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I= +github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M= +github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= +github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= +github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM= +github.com/aliyun/credentials-go v1.4.5 h1:O76WYKgdy1oQYYiJkERjlA2dxGuvLRrzuO2ScrtGWSk= +github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= +github.com/apache/rocketmq-client-go/v2 v2.1.2 h1:yt73olKe5N6894Dbm+ojRf/JPiP0cxfDNNffKwhpJVg= +github.com/apache/rocketmq-client-go/v2 v2.1.2/go.mod h1:6I6vgxHR3hzrvn+6n/4mrhS+UTulzK/X9LB2Vk1U5gE= +github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= +github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d h1:pVrfxiGfwelyab6n21ZBkbkmbevaf+WvMIiR7sr97hw= +github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/casbin/casbin/v2 v2.108.0 h1:aMc3I81wfLpQe/uzMdElB1OBhEmPZoWMPb2nfEaKygY= +github.com/casbin/casbin/v2 v2.108.0/go.mod h1:Ee33aqGrmES+GNL17L0h9X28wXuo829wnNUnS0edAco= +github.com/casbin/govaluate v1.3.0 h1:VA0eSY0M2lA86dYd5kPPuNZMUD9QkWnOCnavGrw9myc= +github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM= +github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= +github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU= +github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/forgoer/openssl v1.6.1 h1:pBfyCd0p5Htd0CzKhtZ5kPLzRk9XeMdRVnC27AIRKmM= +github.com/forgoer/openssl v1.6.1/go.mod h1:9DZ4yOsQmveP0aXC/BpQ++Y5TKaz5yR9+emcxmIZNZs= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/gammazero/toposort v0.1.1 h1:OivGxsWxF3U3+U80VoLJ+f50HcPU1MIqE1JlKzoJ2Eg= +github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw= +github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-pay/crypto v0.0.1 h1:B6InT8CLfSLc6nGRVx9VMJRBBazFMjr293+jl0lLXUY= +github.com/go-pay/crypto v0.0.1/go.mod h1:41oEIvHMKbNcYlWUlRWtsnC6+ASgh7u29z0gJXe5bes= +github.com/go-pay/errgroup v0.0.3 h1:DB4s8e8oWYDyETKQ1y1riMJ7y29zE1uIsMCSjEOFSbU= +github.com/go-pay/errgroup v0.0.3/go.mod h1:0+4b8mvFMS71MIzsaC+gVvB4x37I93lRb2dqrwuU8x8= +github.com/go-pay/gopay v1.5.114 h1:jNYpcylr7WJev6i/MBeer0Z58E0x5NyqG4FfZrar3pQ= +github.com/go-pay/gopay v1.5.114/go.mod h1:p48xvWeepPolZuakAjCeucWynWwW7msoXsqahcoJpKE= +github.com/go-pay/smap v0.0.2 h1:kKflYor5T5FgZltPFBMTFfjJvqYMHr5VnIFSEyhVTcA= +github.com/go-pay/smap v0.0.2/go.mod h1:HW9oAo0okuyDYsbpbj5fJFxnNj/BZorRGFw26SxrNWw= +github.com/go-pay/util v0.0.4 h1:TuwSU9o3Qd7m9v1PbzFuIA/8uO9FJnA6P7neG/NwPyk= +github.com/go-pay/util v0.0.4/go.mod h1:Tsdhs8Ib9J9b4+NKNO1PHh5hWHhlg98PthsX0ckq6PM= +github.com/go-pay/xlog v0.0.3 h1:avyMhCL/JgBHreoGx/am/kHxfs1udDOAeVqbmzP/Yes= +github.com/go-pay/xlog v0.0.3/go.mod h1:mH47xbobrdsSHWsmFtSF5agWbMHFP+tK0ZbVCk5OAEw= +github.com/go-pay/xtime v0.0.2 h1:7YR4/iuELsEHpJ6LUO0SVK80hQxDO9MLCfuVYIiTCRM= +github.com/go-pay/xtime v0.0.2/go.mod h1:W1yRbJaSt4CSBcdAtLBQ8xajiN/Pl5hquGczUcUE9xE= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.7.0/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0 h1:UvqxwinkelKxwdwnKUfdy51/ls4RL7MCeJqAZOVAy0I= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0/go.mod h1:6v7oGBF9wv59WERJIOJxXmLhkUcxwON3tPYW3AZ7wbY= +github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0 h1:39+jbTenm7KBj4hO2C8ANAxVHpX/7OuRDs1VcGC9ylA= +github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0/go.mod h1:B0s0fVzn0W220E8UTpSGzrrGKsop5KcB90twBeLCiz0= +github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0 h1:N/F9CuDdUZLoM1nVRqrDE/33pDZuhVxpNY4wYdeIaBs= +github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0/go.mod h1:x6uoJGfZOtirIRQls8xUlYzC6f7T/eULPUa9er368X0= +github.com/gogf/gf/contrib/trace/jaeger/v2 v2.7.4 h1:JnUjXb7C9vmwcZFwXqnxi9H4/I0rir9LmRryIX7xNds= +github.com/gogf/gf/contrib/trace/jaeger/v2 v2.7.4/go.mod h1:A3NhV8u45twLq5VdqObhYNhT4szLFLCROw4LzHM+lYg= +github.com/gogf/gf/v2 v2.10.0 h1:rzDROlyqGMe/eM6dCalSR8dZOuMIdLhmxKSH1DGhbFs= +github.com/gogf/gf/v2 v2.10.0/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0= +github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f h1:7xfXR/BhG3JDqO1s45n65Oyx9t4E/UqDOXep6jXdLCM= +github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f/go.mod h1:HnYoio6S7VaFJdryKcD/r9HgX+4QzYfr00XiXUo/xz0= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= +github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kayon/iploc v0.0.0-20200312105652-bda3e968a794 h1:dWJxw+KQOMeVcoyxqG9I5fppPld1hh1FG8ngv0fKNsQ= +github.com/kayon/iploc v0.0.0-20200312105652-bda3e968a794/go.mod h1:IwrOeG3O3K9vVXmcVvc9T0XLabw67QePi5pKQt5U+Kw= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY= +github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= +github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= +github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= +github.com/minio/minio-go/v7 v7.0.94 h1:1ZoksIKPyaSt64AVOyaQvhDOgVC3MfZsWM6mZXRUGtM= +github.com/minio/minio-go/v7 v7.0.94/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mojocn/base64Captcha v1.3.8 h1:rrN9BhCwXKS8ht1e21kvR3iTaMgf4qPC9sRoV52bqEg= +github.com/mojocn/base64Captcha v1.3.8/go.mod h1:QFZy927L8HVP3+VV5z2b1EAEiv1KxVJKZbAucVgLUy4= +github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= +github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= +github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI= +github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= +github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY= +github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk= +github.com/qiniu/go-sdk/v7 v7.25.4 h1:ulCKlTEyrZzmNytXweOrnva49+Q4+ASjYBCSXhkRWTo= +github.com/qiniu/go-sdk/v7 v7.25.4/go.mod h1:dmKtJ2ahhPWFVi9o1D5GemmWoh/ctuB9peqTowyTO8o= +github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg= +github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= +github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= +github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00= +github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA= +github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/silenceper/wechat/v2 v2.1.9 h1:wc092gUkGbbBRTdzPxROhQhOH5iE98stnfzKA73mnTo= +github.com/silenceper/wechat/v2 v2.1.9/go.mod h1:7Iu3EhQYVtDUJAj+ZVRy8yom75ga7aDWv8RurLkVm0s= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1200/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1202 h1:3QTQZXLLGLALyHNHs6WAsFCWvElMEXfOdaFM01/3Zjo= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1202/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1200 h1:bu2Jqn/rc5CQslIgTCyG4CTqMpkz2luIOq7dzuLp4G8= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1200/go.mod h1:JzzUsHoueCXnMEYcgorKxyfR0OZAI416XKgHEpgyO7o= +github.com/tencentyun/cos-go-sdk-v5 v0.7.66 h1:O4O6EsozBoDjxWbltr3iULgkI7WPj/BFNlYTXDuE64E= +github.com/tencentyun/cos-go-sdk-v5 v0.7.66/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0= +github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo= +github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tiendc/go-deepcopy v1.6.0 h1:0UtfV/imoCwlLxVsyfUd4hNHnB3drXsfle+wzSCA5Wo= +github.com/tiendc/go-deepcopy v1.6.0/go.mod h1:toXoeQoUqXOOS/X4sKuiAoSk6elIdqc0pN7MTgOOo2I= +github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww= +github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= +github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= +github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/ufilesdk-dev/ufile-gosdk v1.0.6 h1:YhTZfA0U5zjKUe6qYrIs72jjxSZryTMbS9wE76fIxMs= +github.com/ufilesdk-dev/ufile-gosdk v1.0.6/go.mod h1:s1LIpscsgVNx0JRNbDElNNQhyNXJiumVpzvPzVNS/XI= +github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8= +github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/excelize/v2 v2.9.1 h1:VdSGk+rraGmgLHGFaGG9/9IWu1nj4ufjJ7uwMDtj8Qw= +github.com/xuri/excelize/v2 v2.9.1/go.mod h1:x7L6pKz2dvo9ejrRuD8Lnl98z4JLt0TGAwjhW+EiP8s= +github.com/xuri/nfp v0.0.1 h1:MDamSGatIvp8uOmDP8FnmjuQpu90NzdJxo7242ANR9Q= +github.com/xuri/nfp v0.0.1/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ= +github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/jaeger v1.14.0 h1:CjbUNd4iN2hHmWekmOqZ+zSCU+dzZppG8XsV+A3oc8Q= +go.opentelemetry.io/otel/exporters/jaeger v1.14.0/go.mod h1:4Ay9kk5vELRrbg5z4cpP9EtmQRFap2Wb0woPG4lujZA= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= +golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= +golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= +gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +modernc.org/fileutil v1.0.0 h1:Z1AFLZwl6BO8A5NldQg/xTSjGLetp+1Ubvl4alfGx8w= +modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= +stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c= +stathat.com/c/consistent v1.0.0/go.mod h1:QkzMWzcbB+yQBL2AttO6sgsQS/JSTapcDISJalmCDS0= diff --git a/server/hack/config.yaml b/server/hack/config.yaml new file mode 100644 index 0000000..f779bf5 --- /dev/null +++ b/server/hack/config.yaml @@ -0,0 +1,48 @@ +# CLI tool, only in development environment. +# https://goframe.org/pages/viewpage.action?pageId=3673173 +gfcli: + build: + name: "hotgo" # 编译后的可执行文件名称 + arch: "amd64" # 不填默认当前系统架构,可选:386,amd64,arm,all + system: "linux" # 不填默认当前系统平台,可选:linux,darwin,windows,all + mod: "none" + cgo: 0 + packSrc: "resource" # 将resource目录打包进可执行文件,静态资源无需单独部署 + packDst: "internal/packed/packed.go" # 打包后生成的Go文件路径,一般使用相对路径指定到本项目目录中 + version: "" + output: "./temp/hotgo" # 可执行文件生成路径 + extra: "" + + + docker: + build: "-a amd64 -s linux -p temp -ew" # 构建参数 + tagPrefixes: # 该docker的标记前缀,用于docker推送,请替换成你自己的 + - ccr.ccs.tencentyun.com/bufanyun + + + gen: + dao: + - link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true&charset=utf8mb4" +# - link: "pgsql:postgres:hg123456@tcp(127.0.0.1:5432)/hotgo" + group: "default" # 分组 使用hotgo代码生成功能时必须填 + # tables: "" # 指定当前数据库中需要执行代码生成的数据表。如果为空,表示数据库的所有表都会生成。 + tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。 + removePrefix: "hg_" + descriptionTag: true + noModelComment: true + jsonCase: "CamelLower" + gJsonSupport: true + clear: false + + +# service: # 生成业务配置 +# srcFolder: "internal/logic" +# dstFolder: "internal/service" +# dstFileNameCase: "CamelLower" +# clear: true + ctrl: + # api/api下的接口可以使用gf gen ctrl自动生成控制器相关代码 + srcFolder: "api/api" + dstFolder: "internal/controller/api" + clear: true + merge: false diff --git a/server/internal/cmd/auth.go b/server/internal/cmd/auth.go new file mode 100644 index 0000000..dc3e045 --- /dev/null +++ b/server/internal/cmd/auth.go @@ -0,0 +1,35 @@ +// Package cmd +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cmd + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gcmd" + "hotgo/internal/service" +) + +var ( + Auth = &gcmd.Command{ + Name: "auth", + Brief: "系统授权,当为第三方客户开发应用项目不想将源码和可执行文件让其随意使用时,可以通过授权的方式约束使用方。", + Description: `目前已实现,一对一、一对多、有效期授权,具体使用可以参考现有逻辑结合实际场景进行改造`, + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + service.AuthClient().Start(ctx) + + serverWg.Add(1) + + // 信号监听 + signalListen(ctx, signalHandlerForOverall) + + <-serverCloseSignal + service.AuthClient().Stop(ctx) + g.Log().Debug(ctx, "auth successfully closed ..") + serverWg.Done() + return + }, + } +) diff --git a/server/internal/cmd/cmd.go b/server/internal/cmd/cmd.go new file mode 100644 index 0000000..154016c --- /dev/null +++ b/server/internal/cmd/cmd.go @@ -0,0 +1,86 @@ +// Package cmd +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cmd + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gcmd" + "hotgo/utility/simple" +) + +var ( + Main = &gcmd.Command{ + Description: `默认启动所有服务`, + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + return All.Func(ctx, parser) + }, + } + + Help = &gcmd.Command{ + Name: "help", + Brief: "查看帮助", + Description: ` + 命令提示符 + --------------------------------------------------------------------------------- + 启动服务 + >> 所有服务 [go run main.go] 热编译 [gf run main.go] + >> HTTP服务 [go run main.go http] + >> 消息队列 [go run main.go queue] + >> 定时任务 [go run main.go cron] + >> 查看帮助 [go run main.go help] + + --------------------------------------------------------------------------------- + 工具 + >> 释放casbin权限,用于清理无效的权限设置 [go run main.go tools -m=casbin -a1=refresh] + >> 打印所有打包的资源文件列表 [go run main.go tools -m=gres -a1=dump] + >> 打印指定打包的资源文件内容 [go run main.go tools -m=gres -a1=content -a2=resource/template/home/index.html] + --------------------------------------------------------------------------------- + 升级更新 + >> 修复菜单关系树 [go run main.go up -m=fix -a1=menuTree] + --------------------------------------------------------------------------------- + 更多 + github地址:https://github.com/bufanyun/hotgo + 文档地址:https://github.com/bufanyun/hotgo/tree/v2.0/docs/guide-zh-CN + HotGo框架交流1群:190966648 + `, + } + + All = &gcmd.Command{ + Name: "all", + Brief: "start all server", + Description: "this is the command entry for starting all server", + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + g.Log().Debug(ctx, "starting all server") + + // 需要启动的服务 + var allServers = []*gcmd.Command{Http, Queue, Cron} + + for _, server := range allServers { + var cmd = server + simple.SafeGo(ctx, func(ctx context.Context) { + if err := cmd.Func(ctx, parser); err != nil { + g.Log().Fatalf(ctx, "%v start fail:%v", cmd.Name, err) + } + }) + } + + // 信号监听 + signalListen(ctx, signalHandlerForOverall) + + <-serverCloseSignal + serverWg.Wait() + g.Log().Debug(ctx, "all service successfully closed ..") + return + }, + } +) + +func init() { + if err := Main.AddCommand(All, Http, Queue, Cron, Auth, Tools, Up, Help); err != nil { + panic(err) + } +} diff --git a/server/internal/cmd/cron.go b/server/internal/cmd/cron.go new file mode 100644 index 0000000..0b2fd49 --- /dev/null +++ b/server/internal/cmd/cron.go @@ -0,0 +1,45 @@ +// Package cmd +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cmd + +import ( + "context" + "github.com/gogf/gf/v2/os/gcmd" + _ "hotgo/internal/crons" + "hotgo/internal/global" + "hotgo/internal/library/cron" + "hotgo/internal/service" +) + +var ( + Cron = &gcmd.Command{ + Name: "cron", + Brief: "定时任务,用来部署一些可独立运行的定时任务,通过tcp方式和后台保持长连接通讯,动态调整任务属性。", + Description: ``, + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + // 服务日志处理 + cron.Logger().SetHandlers(global.LoggingServeLogHandler) + + // 启动定时任务 + service.SysCron().StartCron(ctx) + + // tcp客户端 + service.CronClient().Start(ctx) + + serverWg.Add(1) + + // 信号监听 + signalListen(ctx, signalHandlerForOverall) + + <-serverCloseSignal + service.CronClient().Stop(ctx) + cron.StopALL() + cron.Logger().Debug(ctx, "cron successfully closed ..") + serverWg.Done() + return + }, + } +) diff --git a/server/internal/cmd/handler_shutdown.go b/server/internal/cmd/handler_shutdown.go new file mode 100644 index 0000000..61a51ba --- /dev/null +++ b/server/internal/cmd/handler_shutdown.go @@ -0,0 +1,44 @@ +// Package cmd +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cmd + +import ( + "context" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/os/gproc" + "hotgo/internal/consts" + "hotgo/utility/simple" + "os" + "sync" +) + +var ( + serverCloseSignal = make(chan struct{}, 1) + serverWg = sync.WaitGroup{} + once sync.Once +) + +// signalHandlerForOverall 关闭信号处理 +func signalHandlerForOverall(sig os.Signal) { + serverCloseEvent(gctx.GetInitCtx()) + serverCloseSignal <- struct{}{} +} + +// signalListen 信号监听 +func signalListen(ctx context.Context, handler ...gproc.SigHandler) { + simple.SafeGo(ctx, func(ctx context.Context) { + gproc.AddSigHandlerShutdown(handler...) + gproc.Listen() + }) +} + +// serverCloseEvent 关闭事件 +// 区别于服务收到退出信号后的处理,只会执行一次 +func serverCloseEvent(ctx context.Context) { + once.Do(func() { + simple.Event().Call(consts.EventServerClose, ctx) + }) +} diff --git a/server/internal/cmd/http.go b/server/internal/cmd/http.go new file mode 100644 index 0000000..7a4cb3e --- /dev/null +++ b/server/internal/cmd/http.go @@ -0,0 +1,106 @@ +// Package cmd +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cmd + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gcmd" + "github.com/gogf/gf/v2/util/gmode" + "hotgo/internal/library/addons" + "hotgo/internal/library/casbin" + "hotgo/internal/library/hggen" + "hotgo/internal/router" + "hotgo/internal/service" + "hotgo/internal/websocket" +) + +var ( + Http = &gcmd.Command{ + Name: "http", + Usage: "http", + Brief: "HTTP服务,也可以称为主服务,包含http、websocket、tcpserver多个可对外服务", + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + // 初始化http服务 + s := g.Server() + + // 初始化请求前回调 + s.BindHookHandler("/*any", ghttp.HookBeforeServe, service.Hook().BeforeServe) + + // 请求响应结束后回调 + s.BindHookHandler("/*any", ghttp.HookAfterOutput, service.Hook().AfterOutput) + + // 注册全局中间件 + s.BindMiddleware("/*any", []ghttp.HandlerFunc{ + service.Middleware().Ctx, // 初始化请求上下文,一般需要第一个进行加载,后续中间件存在依赖关系 + service.Middleware().CORS, // 跨域中间件,自动处理跨域问题 + service.Middleware().Blacklist, // IP黑名单中间件,如果请求IP被后台拉黑,所有请求将被拒绝 + service.Middleware().DemoLimit, // 演示系統操作限制,当开启演示模式时,所有POST请求将被拒绝 + service.Middleware().PreFilter, // 请求输入预处理,api使用gf规范路由并且XxxReq结构体实现了validate.Filter接口即可隐式预处理 + service.Middleware().ResponseHandler, // HTTP响应预处理,在业务处理完成后,对响应结果进行格式化和错误过滤,将处理后的数据发送给请求方 + }...) + + s.Group("/", func(group *ghttp.RouterGroup) { + // 注册后台路由 + router.Admin(ctx, group) + + // 注册Api路由 + router.Api(ctx, group) + + // 注册websocket路由 + router.WebSocket(ctx, group) + + // 注册前台页面路由 + router.Home(ctx, group) + }) + + // 启动插件 + if err = addons.StartModules(ctx, &addons.Option{Server: s}); err != nil { + return err + } + + // 初始化casbin权限 + casbin.InitEnforcer(ctx) + + // 初始化生成代码配置 + if !gmode.IsProduct() { + hggen.InIt(ctx) + } + + // 启动tcp服务 + service.TCPServer().Start(ctx) + + // 启动服务监控 + service.AdminMonitor().StartMonitor(ctx) + + // 加载ip访问黑名单 + service.SysBlacklist().Load(ctx) + + // 注册支付成功回调方法 + service.Pay().RegisterNotifyCall() + + serverWg.Add(1) + + // 信号监听 + signalListen(ctx, signalHandlerForOverall) + + go func() { + <-serverCloseSignal + websocket.Stop() // 关闭websocket + service.TCPServer().Stop(ctx) // 关闭tcp服务器 + addons.StopModules(ctx) // 停止插件 + _ = s.Shutdown() // 关闭http服务,主服务建议放在最后一个关闭 + g.Log().Debug(ctx, "http successfully closed ..") + serverWg.Done() + }() + + // Just run the server. + s.Run() + return + }, + } +) diff --git a/server/internal/cmd/queue.go b/server/internal/cmd/queue.go new file mode 100644 index 0000000..a8dbb5d --- /dev/null +++ b/server/internal/cmd/queue.go @@ -0,0 +1,43 @@ +// Package cmd +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cmd + +import ( + "context" + "github.com/gogf/gf/v2/os/gcmd" + "hotgo/internal/global" + "hotgo/internal/library/queue" + _ "hotgo/internal/queues" + "hotgo/utility/simple" +) + +var ( + Queue = &gcmd.Command{ + Name: "queue", + Brief: "消息队列", + Description: ``, + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + // 服务日志处理 + queue.Logger().SetHandlers(global.LoggingServeLogHandler) + + simple.SafeGo(ctx, func(ctx context.Context) { + queue.Logger().Debug(ctx, "start queue consumer..") + queue.StartConsumersListener(ctx) + queue.Logger().Debug(ctx, "start queue consumer success..") + }) + + serverWg.Add(1) + + // 信号监听 + signalListen(ctx, signalHandlerForOverall) + + <-serverCloseSignal + queue.Logger().Debug(ctx, "queue successfully closed ..") + serverWg.Done() + return + }, + } +) diff --git a/server/internal/cmd/tools.go b/server/internal/cmd/tools.go new file mode 100644 index 0000000..c098f08 --- /dev/null +++ b/server/internal/cmd/tools.go @@ -0,0 +1,107 @@ +// Package cmd +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cmd + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gcmd" + "github.com/gogf/gf/v2/os/gres" + "hotgo/internal/library/casbin" +) + +var ( + Tools = &gcmd.Command{ + Name: "tools", + Brief: "常用工具", + Description: ``, + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + args := parser.GetOptAll() + g.Log().Debugf(ctx, "tools args:%v", args) + if len(args) == 0 { + err = gerror.New("tools args cannot be empty.") + return + } + + method, ok := args["m"] + if !ok { + err = gerror.New("tools method cannot be empty.") + return + } + + switch method { + case "casbin": + err = handleCasbin(ctx, args) + case "gres": + err = handleGRes(ctx, args) + default: + err = gerror.Newf("tools method[%v] does not exist", method) + } + + if err == nil { + g.Log().Info(ctx, "tools exec successful!") + } + return + }, + } +) + +// handleCasbin casbin. +func handleCasbin(ctx context.Context, args map[string]string) (err error) { + a1, ok := args["a1"] + if !ok { + err = gerror.New("casbin args cannot be empty.") + return + } + + casbin.InitEnforcer(ctx) + switch a1 { + case "clear": + err = casbin.Clear(ctx) + case "refresh": + err = casbin.Refresh(ctx) + default: + err = gerror.Newf("casbin a1 is invalid, a1:%v", a1) + } + return +} + +func handleGRes(ctx context.Context, args map[string]string) (err error) { + a1, ok := args["a1"] + if !ok { + err = gerror.New("gres args cannot be empty.") + return + } + + switch a1 { + case "dump": + gres.Dump() + case "content": + path, ok := args["a2"] + if !ok { + err = gerror.New("缺少查看文件路径参数:`a2`") + return + } + + if !gres.Contains(path) { + err = gerror.Newf("没有找到资源文件:%v", path) + return + } + content := string(gres.GetContent(path)) + + if len(content) == 0 { + err = gerror.Newf("没有找到资源文件内容,请确认传入`a2`参数是一个文件,a2:%v", path) + return + } + fmt.Println("以下是资源文件内容:") + fmt.Println(content) + default: + err = gerror.Newf("handleGRes a1 is invalid, a1:%v", a1) + } + return +} diff --git a/server/internal/cmd/up.go b/server/internal/cmd/up.go new file mode 100644 index 0000000..cbfc045 --- /dev/null +++ b/server/internal/cmd/up.go @@ -0,0 +1,65 @@ +// Package cmd +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package cmd + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gcmd" + "hotgo/internal/cmd/upgrade/fix" +) + +var ( + Up = &gcmd.Command{ + Name: "up", + Brief: "处理hotgo版本升级更新带来的兼容问题", + Description: ``, + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + args := parser.GetOptAll() + g.Log().Debugf(ctx, "up args:%v", args) + if len(args) == 0 { + err = gerror.New("up args cannot be empty.") + return + } + + method, ok := args["m"] + if !ok { + err = gerror.New("up method cannot be empty.") + return + } + + switch method { + case "fix": + err = handleUpgradeFix(ctx, args) + default: + err = gerror.Newf("up method[%v] does not exist", method) + } + + if err == nil { + g.Log().Info(ctx, "up exec successful!") + } + return + }, + } +) + +// handleUpgradeFix 处理修复脚本 +func handleUpgradeFix(ctx context.Context, args map[string]string) (err error) { + a1, ok := args["a1"] + if !ok { + err = gerror.New("fix args cannot be empty.") + return + } + + switch a1 { + case "menuTree": + fix.UpdateAdminMenuTree(ctx) + default: + err = gerror.Newf("fix a1 is invalid, a1:%v", a1) + } + return +} diff --git a/server/internal/cmd/upgrade/fix/admin_menu_tree.go b/server/internal/cmd/upgrade/fix/admin_menu_tree.go new file mode 100644 index 0000000..e5c7d66 --- /dev/null +++ b/server/internal/cmd/upgrade/fix/admin_menu_tree.go @@ -0,0 +1,48 @@ +// Package fix +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package fix + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "hotgo/internal/dao" + "hotgo/internal/library/hgorm" + "hotgo/internal/model/entity" +) + +// UpdateAdminMenuTree 更新菜单关系树 +// 根据树等级从上到下依次检查,将无效的关系树进行修复更新 +func UpdateAdminMenuTree(ctx context.Context) { + var list []*entity.AdminMenu + err := dao.AdminMenu.Ctx(ctx).OrderAsc("level").Scan(&list) + if err != nil { + g.Log().Fatal(ctx, err) + } + + genUpdateData := func(v *entity.AdminMenu) g.Map { + update := g.Map{"updated_at": gtime.Now()} + if v.Pid <= 0 { + update["level"] = 1 + update["tree"] = "" + return update + } + + // 生成下级关系树 + update["pid"], update["level"], update["tree"], err = hgorm.GenSubTree(ctx, &dao.AdminMenu, v.Pid) + return update + } + + for _, v := range list { + update := genUpdateData(v) + if v.Level == update["level"] && v.Tree == update["tree"] { + continue + } + if _, err = dao.AdminMenu.Ctx(ctx).WherePri(v.Id).Data(genUpdateData(v)).Update(); err != nil { + g.Log().Fatal(ctx, err) + } + } +} diff --git a/server/internal/consts/addons.go b/server/internal/consts/addons.go new file mode 100644 index 0000000..3384bbf --- /dev/null +++ b/server/internal/consts/addons.go @@ -0,0 +1,80 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +func init() { + dict.RegisterEnums("addonsGroupOptions", "插件分组", AddonsGroupOptions) + dict.RegisterEnums("addonsInstallStatus", "插件安装状态", AddonsInstallStatusOptions) + dict.RegisterEnums("addonsExtend", "插件扩展", AddonsExtendOptions) +} + +const ( + AddonsTag = "addons_" // 插件标签前缀 + AddonsDir = "addons" // 插件路径 +) + +const ( + AddonsGroupPlug = 1 // 功能扩展 + AddonsGroupBusiness = 2 // 主要业务 + AddonsGroupThirdParty = 3 // 第三方插件 + AddonsGroupMiniApp = 4 // 小程序 + AddonsGroupCustomer = 5 // 客户关系 + AddonsGroupActivity = 6 // 营销及活动 + AddonsGroupServices = 7 // 常用服务及工具 + AddonsGroupBiz = 8 // 行业解决方案 +) + +// AddonsGroupOptions 插件分组选项 +var AddonsGroupOptions = []*model.Option{ + dict.GenInfoOption(AddonsGroupPlug, "功能扩展"), + dict.GenInfoOption(AddonsGroupBusiness, "主要业务"), + dict.GenInfoOption(AddonsGroupThirdParty, "第三方插件"), + dict.GenInfoOption(AddonsGroupMiniApp, "小程序"), + dict.GenInfoOption(AddonsGroupCustomer, "客户关系"), + dict.GenInfoOption(AddonsGroupActivity, "营销及活动"), + dict.GenInfoOption(AddonsGroupServices, "常用服务及工具"), + dict.GenInfoOption(AddonsGroupBiz, "行业解决方案"), +} + +var AddonsGroupIconMap = map[int]string{ + AddonsGroupPlug: "AppstoreAddOutlined", + AddonsGroupBusiness: "FireOutlined", + AddonsGroupThirdParty: "ApiOutlined", + AddonsGroupMiniApp: "RocketOutlined", + AddonsGroupCustomer: "UserSwitchOutlined", + AddonsGroupActivity: "TagOutlined", + AddonsGroupServices: "ToolOutlined", + AddonsGroupBiz: "CheckCircleOutlined", +} + +const ( + AddonsInstallStatusOk = 1 // 已安装 + AddonsInstallStatusNo = 2 // 未安装 + AddonsInstallStatusUn = 3 // 已卸载 +) + +// AddonsInstallStatusOptions 插件安装状态 +var AddonsInstallStatusOptions = []*model.Option{ + dict.GenInfoOption(AddonsInstallStatusOk, "已安装"), + dict.GenInfoOption(AddonsInstallStatusNo, "未安装"), + dict.GenInfoOption(AddonsInstallStatusUn, "已卸载"), +} + +const ( + AddonsExtendResourcePublic = "resourcePublic" + AddonsExtendResourceTemplate = "resourceTemplate" +) + +// AddonsExtendOptions 插件扩展选项 +var AddonsExtendOptions = []*model.Option{ + dict.GenInfoOption(AddonsExtendResourcePublic, "创建静态目录"), + dict.GenInfoOption(AddonsExtendResourceTemplate, "创建模板目录"), +} diff --git a/server/internal/consts/app.go b/server/internal/consts/app.go new file mode 100644 index 0000000..9b57213 --- /dev/null +++ b/server/internal/consts/app.go @@ -0,0 +1,15 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 应用类型 +const ( + AppAdmin = "admin" + AppApi = "api" + AppHome = "home" + AppWebSocket = "websocket" + AppDefault = "default" +) diff --git a/server/internal/consts/cache.go b/server/internal/consts/cache.go new file mode 100644 index 0000000..e1313b8 --- /dev/null +++ b/server/internal/consts/cache.go @@ -0,0 +1,13 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// cache +const ( + CacheToken = "token" // 登录token + CacheTokenBind = "token_bind" // 登录用户身份绑定 + CacheMultipartUpload = "multipart_upload" // 分片上传 +) diff --git a/server/internal/consts/captcha.go b/server/internal/consts/captcha.go new file mode 100644 index 0000000..c5c7a75 --- /dev/null +++ b/server/internal/consts/captcha.go @@ -0,0 +1,6 @@ +package consts + +const ( + CaptchaTypeString = iota + 1 // 字符串 + CaptchaTypeMath // 数字计算 +) diff --git a/server/internal/consts/cash.go b/server/internal/consts/cash.go new file mode 100644 index 0000000..f215d85 --- /dev/null +++ b/server/internal/consts/cash.go @@ -0,0 +1,13 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 提现状态 +const ( + CashStatusWait = 1 // 处理中 + CashStatusOk = 2 // 提现成功 + CashStatusFail = 3 // 提现异常 +) diff --git a/server/internal/consts/config.go b/server/internal/consts/config.go new file mode 100644 index 0000000..1a85e77 --- /dev/null +++ b/server/internal/consts/config.go @@ -0,0 +1,117 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "github.com/gogf/gf/v2/util/gconv" +) + +// RequestEncryptKey +// 请求加密密钥用于敏感数据加密,16位字符,前后端需保持一致 +// 安全起见,生产环境运行时请注意修改 +var RequestEncryptKey = []byte("f080a463654b2279") + +// 配置数据类型 +const ( + ConfigTypeString = "string" + ConfigTypeInt = "int" + ConfigTypeInt8 = "int8" + ConfigTypeInt16 = "int16" + ConfigTypeInt32 = "int32" + ConfigTypeInt64 = "int64" + ConfigTypeUint = "uint" + ConfigTypeUint8 = "uint8" + ConfigTypeUint16 = "uint16" + ConfigTypeUint32 = "uint32" + ConfigTypeUint64 = "uint64" + ConfigTypeFloat32 = "float32" + ConfigTypeFloat64 = "float64" + ConfigTypeBool = "bool" + ConfigTypeDate = "date" + ConfigTypeDateTime = "datetime" + ConfigTypeSliceString = "[]string" + ConfigTypeSliceInt = "[]int" + ConfigTypeSliceInt64 = "[]int64" +) + +var ConfigTypes = []string{ConfigTypeString, + ConfigTypeInt, ConfigTypeInt8, ConfigTypeInt16, ConfigTypeInt32, ConfigTypeInt64, + ConfigTypeUint, ConfigTypeUint8, ConfigTypeUint16, ConfigTypeUint32, ConfigTypeUint64, + ConfigTypeFloat32, ConfigTypeFloat64, + ConfigTypeBool, + ConfigTypeDate, ConfigTypeDateTime, + ConfigTypeSliceString, ConfigTypeSliceInt, ConfigTypeSliceInt64, +} + +// ConfigMaskDemoField 演示环境下需要隐藏的配置 +var ConfigMaskDemoField = map[string]struct{}{ + // 邮箱 + "smtpUser": {}, "smtpPass": {}, + + // 云存储 + "uploadUCloudPublicKey": {}, "uploadUCloudPrivateKey": {}, "uploadCosSecretId": {}, "uploadCosSecretKey": {}, + "uploadOssSecretId": {}, "uploadOssSecretKey": {}, "uploadQiNiuAccessKey": {}, "uploadQiNiuSecretKey": {}, + + // 地图 + "geoAmapWebKey": {}, + + // 短信 + "smsAliYunAccessKeyID": {}, "smsAliYunAccessKeySecret": {}, "smsTencentSecretId": {}, "smsTencentSecretKey": {}, + + // 支付 + "payWxPayMchId": {}, "payWxPaySerialNo": {}, "payWxPayAPIv3Key": {}, "payWxPayPrivateKey": {}, "payQQPayMchId": {}, "payQQPayApiKey": {}, + + // 微信 + "officialAccountAppSecret": {}, "officialAccountToken": {}, "officialAccountEncodingAESKey": {}, "openPlatformAppSecret": {}, + "openPlatformToken": {}, "openPlatformEncodingAESKey": {}, +} + +// ConvType 类型转换 +func ConvType(val interface{}, t string) interface{} { + switch t { + case ConfigTypeString: + val = gconv.String(val) + case ConfigTypeInt: + val = gconv.Int(val) + case ConfigTypeInt8: + val = gconv.Int8(val) + case ConfigTypeInt16: + val = gconv.Int16(val) + case ConfigTypeInt32: + val = gconv.Int32(val) + case ConfigTypeInt64: + val = gconv.Int64(val) + case ConfigTypeUint: + val = gconv.Uint(val) + case ConfigTypeUint8: + val = gconv.Uint8(val) + case ConfigTypeUint16: + val = gconv.Uint16(val) + case ConfigTypeUint32: + val = gconv.Uint32(val) + case ConfigTypeUint64: + val = gconv.Uint64(val) + case ConfigTypeFloat32: + val = gconv.Float32(val) + case ConfigTypeFloat64: + val = gconv.Float64(val) + case ConfigTypeBool: + val = gconv.Bool(val) + case ConfigTypeDate: + val = gconv.Time(val, "Y-m-d") + case ConfigTypeDateTime: + val = gconv.Time(val, "Y-m-d H:i:s") + case ConfigTypeSliceInt: + val = gconv.SliceInt(val) + case ConfigTypeSliceInt64: + val = gconv.SliceInt64(val) + case ConfigTypeSliceString: + val = gconv.SliceStr(val) + default: + val = gconv.String(val) + } + return val +} diff --git a/server/internal/consts/context.go b/server/internal/consts/context.go new file mode 100644 index 0000000..38acd81 --- /dev/null +++ b/server/internal/consts/context.go @@ -0,0 +1,15 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +type CtxKey string + +// ContextKey 上下文 +const ( + ContextHTTPKey CtxKey = "httpContext" // http上下文变量名称 + ContextKeyCronArgs CtxKey = "cronArgs" // 定时任务参数 + ContextKeyCronSn CtxKey = "cronSn" // 定时任务序列号 +) diff --git a/server/internal/consts/credit_log.go b/server/internal/consts/credit_log.go new file mode 100644 index 0000000..c06d654 --- /dev/null +++ b/server/internal/consts/credit_log.go @@ -0,0 +1,48 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +func init() { + dict.RegisterEnums("creditType", "资金变动类型", CreditTypeOptions) + dict.RegisterEnums("creditGroup", "资金变动分组", CreditGroupOptions) +} + +const ( + CreditTypeBalance = "balance" // 余额 + CreditTypeIntegral = "integral" // 积分 +) + +const ( + CreditGroupDecr = "decr" // 扣款 + CreditGroupIncr = "incr" // 加款 + CreditGroupOpDecr = "op_decr" // 操作扣款 + CreditGroupOpIncr = "op_incr" // 操作加款 + CreditGroupBalanceRecharge = "balance_recharge" // 余额充值 + CreditGroupBalanceRefund = "balance_refund" // 余额退款 + CreditGroupApplyCash = "apply_cash" // 申请提现 +) + +// CreditTypeOptions 变动类型 +var CreditTypeOptions = []*model.Option{ + dict.GenSuccessOption(CreditTypeBalance, "余额"), + dict.GenInfoOption(CreditTypeIntegral, "积分"), +} + +// CreditGroupOptions 变动分组 +var CreditGroupOptions = []*model.Option{ + dict.GenWarningOption(CreditGroupDecr, "扣款"), + dict.GenSuccessOption(CreditGroupIncr, "加款"), + dict.GenWarningOption(CreditGroupOpDecr, "操作扣款"), + dict.GenSuccessOption(CreditGroupOpIncr, "操作加款"), + dict.GenWarningOption(CreditGroupBalanceRefund, "余额退款"), + dict.GenSuccessOption(CreditGroupBalanceRecharge, "余额充值"), + dict.GenInfoOption(CreditGroupApplyCash, "申请提现"), +} diff --git a/server/internal/consts/cron.go b/server/internal/consts/cron.go new file mode 100644 index 0000000..3898160 --- /dev/null +++ b/server/internal/consts/cron.go @@ -0,0 +1,16 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 定时任务 + +const ( + CronSplitStr = "," // 变量分割符 + CronPolicySame = 1 // 并行策略 + CronPolicySingle = 2 // 单例策略 + CronPolicyOnce = 3 // 单次策略 + CronPolicyTimes = 4 // 多次策略 +) diff --git a/server/internal/consts/debris.go b/server/internal/consts/debris.go new file mode 100644 index 0000000..531c34c --- /dev/null +++ b/server/internal/consts/debris.go @@ -0,0 +1,37 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2025 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 碎片 + +const ( + DemoTips = "演示系统已隐藏" // 演示系统敏感数据打码 + NilJsonToString = "{}" // 空json初始化值 + RegionSpilt = " / " // 地区分隔符 + Unknown = "Unknown" // Unknown + SuperRoleKey = "super" // 超管角色唯一标识符,通过角色验证超管 + MaxServeLogContentLen = 2048 // 最大保留服务日志内容大小 + SysDefaultLanguage = "zh_CN" // 系统默认语言,当配置文件没有国际化配置时生效 +) + +// curd. +const ( + DefaultPage = 10 // 默认列表分页加载数量 + DefaultPageSize = 1 // 默认列表分页加载页码 + MaxSortIncr = 10 // 最大排序值增量 +) + +// TenantField 租户字段 +const ( + TenantId = "tenant_id" // 租户ID + MerchantId = "merchant_id" // 商户ID + UserId = "user_id" // 用户ID +) + +const ( + DBMysql = "mysql" + DBPgsql = "pgsql" +) diff --git a/server/internal/consts/dept.go b/server/internal/consts/dept.go new file mode 100644 index 0000000..7c2f2d6 --- /dev/null +++ b/server/internal/consts/dept.go @@ -0,0 +1,30 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +func init() { + dict.RegisterEnums("deptType", "部门类型选项", DeptTypeOptions) +} + +const ( + DeptTypeCompany = "company" // 公司 + DeptTypeTenant = "tenant" // 租户 + DeptTypeMerchant = "merchant" // 商户 + DeptTypeUser = "user" // 用户 +) + +// DeptTypeOptions 部门类型选项 +var DeptTypeOptions = []*model.Option{ + dict.GenSuccessOption(DeptTypeCompany, "公司"), + dict.GenErrorOption(DeptTypeTenant, "租户"), + dict.GenInfoOption(DeptTypeMerchant, "商户"), + dict.GenWarningOption(DeptTypeUser, "用户"), +} diff --git a/server/internal/consts/ems.go b/server/internal/consts/ems.go new file mode 100644 index 0000000..5191153 --- /dev/null +++ b/server/internal/consts/ems.go @@ -0,0 +1,38 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import "github.com/gogf/gf/v2/frame/g" + +// 邮件内置模板 +const ( + EmsTemplateText = "text" // 通用文本 + EmsTemplateCode = "code" // 通用验证码 + EmsTemplateLogin = "login" // 登录 + EmsTemplateRegister = "register" // 注册 + EmsTemplateResetPwd = "resetPwd" // 重置密码 + EmsTemplateBind = "bind" // 绑定邮箱 + EmsTemplateCash = "cash" // 申请提现 +) + +var EmsSubjectMap = g.MapStrStr{ + EmsTemplateText: "这是一封来自HotGo的邮件", + EmsTemplateCode: "验证码", + EmsTemplateLogin: "登录验证码", + EmsTemplateRegister: "注册验证码", + EmsTemplateResetPwd: "重置密码", + EmsTemplateBind: "绑定邮箱验证码", + EmsTemplateCash: "申请提现验证码", +} + +// IsCodeEmsTemplate 是否是验证码类型的模板 +func IsCodeEmsTemplate(template string) bool { + return template == EmsTemplateCode || + template == EmsTemplateLogin || + template == EmsTemplateRegister || + template == EmsTemplateBind || + template == EmsTemplateCash +} diff --git a/server/internal/consts/error.go b/server/internal/consts/error.go new file mode 100644 index 0000000..fa392ed --- /dev/null +++ b/server/internal/consts/error.go @@ -0,0 +1,35 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "github.com/gogf/gf/v2/text/gstr" +) + +// 错误解释 +const ( + ErrorORM = "sql执行异常" + ErrorNotData = "数据不存在" + ErrorRotaPointer = "指针转换异常" +) + +// 需要隐藏真实错误的Wrap,开启访问日志后仍然会将真实错误记录 +var concealErrorSlice = []string{ErrorORM, ErrorRotaPointer} + +// ErrorMessage 错误显示信息,非debug模式有效 +func ErrorMessage(err error) (message string) { + if err == nil { + return "操作失败!~" + } + + message = err.Error() + for _, e := range concealErrorSlice { + if gstr.Contains(message, e) { + return "操作失败,请稍后重试!~" + } + } + return +} diff --git a/server/internal/consts/event.go b/server/internal/consts/event.go new file mode 100644 index 0000000..e3e6ca3 --- /dev/null +++ b/server/internal/consts/event.go @@ -0,0 +1,10 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +const ( + EventServerClose = "server.close" // 服务关闭事件 +) diff --git a/server/internal/consts/gencodes.go b/server/internal/consts/gencodes.go new file mode 100644 index 0000000..88da4e7 --- /dev/null +++ b/server/internal/consts/gencodes.go @@ -0,0 +1,96 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +// 生成代码类型 +const ( + GenCodesTypeCurd = 10 // 增删改查列表 + GenCodesTypeTree = 11 // 树列表 + GenCodesTypeQueue = 20 // 队列消费者 + GenCodesTypeCron = 30 // 定时任务 +) + +var GenCodesTypeNameMap = map[int]string{ + GenCodesTypeCurd: "增删改查列表", + GenCodesTypeTree: "关系树列表", + GenCodesTypeQueue: "队列消费者(未实现)", + GenCodesTypeCron: "定时任务(未实现)", +} + +var GenCodesTypeConfMap = map[int]string{ + GenCodesTypeCurd: "crud", + GenCodesTypeTree: "tree", + GenCodesTypeQueue: "queue", + GenCodesTypeCron: "cron", +} + +// 生成代码状态 +const ( + GenCodesStatusOk = 1 // 生成成功 + GenCodesStatusWait = 2 // 未生成 + GenCodesStatusFail = 3 // 生成失败 +) + +var GenCodesStatusNameMap = map[int]string{ + GenCodesStatusOk: "生成成功", + GenCodesStatusWait: "未生成", + GenCodesStatusFail: "生成失败", +} + +// 生成代码关联表方式 +const ( + GenCodesJoinLeft = 1 // 左关联 + GenCodesJoinRight = 2 // 右关联 + GenCodesJoinInner = 3 // 内关联 +) + +var GenCodesJoinNameMap = map[int]string{ + GenCodesJoinLeft: "左关联", + GenCodesJoinRight: "右关联", + GenCodesJoinInner: "内关联", +} + +var GenCodesJoinLinkMap = map[int]string{ + GenCodesJoinLeft: "LeftJoin", + GenCodesJoinRight: "RightJoin", + GenCodesJoinInner: "InnerJoin", +} + +// 生成代码的生成方式 +const ( + GenCodesBuildMethCreate = 1 // 创建 + GenCodesBuildMethCover = 2 // 覆盖 + GenCodesBuildMethSkip = 3 // 跳过 + GenCodesBuildIgnore = 4 // 不生成 +) + +var GenCodesBuildMethNameMap = map[int]string{ + GenCodesBuildMethCreate: "创建文件", + GenCodesBuildMethCover: "强制覆盖", + GenCodesBuildMethSkip: "已存在跳过", + GenCodesBuildIgnore: "不生成", +} + +const ( + GenCodesIndexPK = "PRI" // 主键索引 + GenCodesIndexUNI = "UNI" // 唯一索引 +) + +const ( + GenCodesTreeStyleTypeNormal = 1 // 普通树表格 + GenCodesTreeStyleTypeOption = 2 // 选项式树表 +) + +// GenCodesTreeStyleTypeOptions 树表样式选项 +var GenCodesTreeStyleTypeOptions = []*model.Option{ + dict.GenSuccessOption(GenCodesTreeStyleTypeNormal, "普通树表格"), + dict.GenInfoOption(GenCodesTreeStyleTypeOption, "选项式树表"), +} diff --git a/server/internal/consts/http.go b/server/internal/consts/http.go new file mode 100644 index 0000000..019168e --- /dev/null +++ b/server/internal/consts/http.go @@ -0,0 +1,63 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "fmt" + "hotgo/internal/library/dict" + "hotgo/internal/model" + "net/http" + + "github.com/gogf/gf/v2/errors/gcode" +) + +func init() { + dict.RegisterEnums("HTTPMethod", "HTTP请求方式选项", HTTPMethodOptions) + dict.RegisterEnums("HTTPHandlerTime", "HTTP处理耗时选项", HTTPHandlerTimeOptions) + dict.RegisterEnums("HTTPApiCode", "HTTP接口状态码选项", HTTPApiCodeOptions) +} + +const ( + HTTPContentTypeXml = "text/xml" + HTTPContentTypeHtml = "text/html" + HTTPContentTypeStream = "text/event-stream" + HTTPContentTypeJson = "application/json" + HTTPContentTypeOctetStream = "application/octet-stream" +) + +// HTTPMethodOptions HTTP请求方式选项 +var HTTPMethodOptions = []*model.Option{ + dict.GenSuccessOption(http.MethodGet, "GET"), + dict.GenInfoOption(http.MethodPost, "POST"), + dict.GenSuccessOption(http.MethodPut, "PUT"), + dict.GenInfoOption(http.MethodDelete, "DELETE"), +} + +const ( + HTTPHandlerTime50 = "< 50" + HTTPHandlerTime200 = "< 200" + HTTPHandlerTime200To500 = "BETWEEN 200 AND 500" + HTTPHandlerTime500To1000 = "BETWEEN 500 AND 1000" + HTTPHandlerTime1000To10000 = "BETWEEN 1000 AND 10000" + HTTPHandlerTime10000UP = "> 10000" +) + +// HTTPHandlerTimeOptions HTTP处理耗时选项 +var HTTPHandlerTimeOptions = []*model.Option{ + dict.GenSuccessOption(HTTPHandlerTime50, "50ms以内"), + dict.GenInfoOption(HTTPHandlerTime200, "200ms以内"), + dict.GenSuccessOption(HTTPHandlerTime200To500, "200~500ms"), + dict.GenSuccessOption(HTTPHandlerTime500To1000, "500~1000ms"), + dict.GenInfoOption(HTTPHandlerTime1000To10000, "1000~10000ms"), + dict.GenInfoOption(HTTPHandlerTime10000UP, "10000ms以上"), +} + +// HTTPApiCodeOptions HTTP接口状态码选项 +var HTTPApiCodeOptions = []*model.Option{ + dict.GenSuccessOption(gcode.CodeOK.Code(), fmt.Sprintf("%v %v", gcode.CodeOK.Code(), "成功")), + dict.GenWarningOption(gcode.CodeNil.Code(), fmt.Sprintf("%v %v", gcode.CodeNil.Code(), "失败")), + dict.GenWarningOption(gcode.CodeSecurityReason.Code(), fmt.Sprintf("%v %v", gcode.CodeSecurityReason.Code(), "无访问权限")), +} diff --git a/server/internal/consts/notice.go b/server/internal/consts/notice.go new file mode 100644 index 0000000..ff4ea63 --- /dev/null +++ b/server/internal/consts/notice.go @@ -0,0 +1,13 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 公告类型 +const ( + NoticeTypeNotify = 1 // 通知 + NoticeTypeNotice = 2 // 公告 + NoticeTypeLetter = 3 // 私信 +) diff --git a/server/internal/consts/order.go b/server/internal/consts/order.go new file mode 100644 index 0000000..007a1f2 --- /dev/null +++ b/server/internal/consts/order.go @@ -0,0 +1,66 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +func init() { + dict.RegisterEnums("orderStatus", "订单状态", OrderStatusOptions) + dict.RegisterEnums("acceptRefundStatus", "订单退款受理状态", OrderAcceptRefundOptions) +} + +// 订单分组 +// 为不同的业务订单设置不同的分组,分组可以设置不同的业务回调方法 + +const ( + OrderGroupDefault = "order" // 普通订单 + OrderGroupAdminOrder = "admin_order" // 后台充值订单 + // 还可以设置其他,方便后期扩展.. +) + +// 订单类型 + +const ( + OrderTypeBalance = "balance" // 余额充值 + OrderTypeProduct = "product" // 购买产品 +) + +const ( + OrderStatusALL = -1 // 全部状态 + OrderStatusNotPay = 1 // 待付款 + OrderStatusPay = 2 // 已付款 + OrderStatusShipments = 3 // 已发货 + OrderStatusDone = 4 // 已完成 + OrderStatusClose = 5 // 已关闭 + OrderStatusReturnRequest = 6 // 申请退款 + OrderStatusReturning = 7 // 退款中 + OrderStatusReturned = 8 // 已退款 + OrderStatusReturnReject = 9 // 拒绝退款 +) + +// OrderStatusOptions 订单状态选项 +var OrderStatusOptions = []*model.Option{ + dict.GenInfoOption(OrderStatusALL, "全部"), + dict.GenInfoOption(OrderStatusNotPay, "待付款"), + dict.GenInfoOption(OrderStatusPay, "已付款"), + dict.GenInfoOption(OrderStatusShipments, "已发货"), + dict.GenSuccessOption(OrderStatusDone, "已完成"), + dict.GenDefaultOption(OrderStatusClose, "已关闭"), + dict.GenWarningOption(OrderStatusReturnRequest, "申请退款"), + dict.GenDefaultOption(OrderStatusReturning, "退款中"), + dict.GenErrorOption(OrderStatusReturned, "已退款"), + dict.GenWarningOption(OrderStatusReturnReject, "拒绝退款"), +} + +// OrderAcceptRefundOptions 订单退款受理状态 +var OrderAcceptRefundOptions = []*model.Option{ + dict.GenWarningOption(OrderStatusReturnRequest, "申请退款"), + dict.GenSuccessOption(OrderStatusReturned, "已退款"), + dict.GenErrorOption(OrderStatusReturnReject, "拒绝退款"), +} diff --git a/server/internal/consts/pay.go b/server/internal/consts/pay.go new file mode 100644 index 0000000..084dd4c --- /dev/null +++ b/server/internal/consts/pay.go @@ -0,0 +1,96 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +// 支付方式 + +func init() { + dict.RegisterEnums("payType", "支付方式", PayTypeOptions) + dict.RegisterEnums("payStatus", "支付状态", PayStatusOptions) +} + +const ( + PayTypeALL = "" // 全部 + PayTypeWxPay = "wxpay" // 微信支付 + PayTypeAliPay = "alipay" // 支付宝 + PayTypeQQPay = "qqpay" // QQ支付 +) + +var ( + PayTypeSlice = []string{ + PayTypeWxPay, PayTypeAliPay, PayTypeQQPay, + } + + PayTypeNameMap = map[string]string{ + PayTypeALL: "全部", + PayTypeWxPay: "微信支付", + PayTypeAliPay: "支付宝", + PayTypeQQPay: "QQ支付", + } +) + +// 交易方式 + +const ( + // 微信 + TradeTypeWxMP = "mp" // 公众号 + TradeTypeWxMini = "mini" // 小程序 + TradeTypeWxApp = "app" // APP + TradeTypeWxScan = "scan" // 二维码扫码 + TradeTypeWxPos = "pos" // 二维码收款 + TradeTypeWxH5 = "h5" // H5 + + // 支付宝 + TradeTypeAliWeb = "web" // 电脑网页 + TradeTypeAliApp = "app" // APP + TradeTypeAliScan = "scan" // 二维码扫码 + TradeTypeAliWap = "wap" // 手机网页 + TradeTypeAliPos = "pos" // 二维码收款 + + // QQ + TradeTypeQQWeb = "qqweb" // PC网页 + TradeTypeQQWap = "qqwap" // 移动端 +) + +var ( + TradeTypeWxSlice = []string{TradeTypeWxMP, TradeTypeWxMini, TradeTypeWxApp, TradeTypeWxScan, TradeTypeWxPos, TradeTypeWxH5} + TradeTypeAliSlice = []string{TradeTypeAliWeb, TradeTypeAliApp, TradeTypeAliScan, TradeTypeAliWap, TradeTypeAliPos} + TradeTypeQQSlice = []string{TradeTypeQQWeb, TradeTypeQQWap} +) + +// 支付状态 + +const ( + PayStatusWait = 1 // 待支付 + PayStatusOk = 2 // 已支付 +) + +// PayStatusOptions 支付状态选项 +var PayStatusOptions = []*model.Option{ + dict.GenDefaultOption(PayStatusWait, "待支付"), + dict.GenSuccessOption(PayStatusOk, "已支付"), +} + +// 退款状态 + +const ( + RefundStatusNo = 1 // 未退款 + RefundStatusApply = 2 // 申请退款 + RefundStatusReject = 3 // 拒绝退款 + RefundStatusAgree = 4 // 同意退款,已退款 +) + +// PayTypeOptions 支付方式选项 +var PayTypeOptions = []*model.Option{ + dict.GenSuccessOption(PayTypeWxPay, "微信支付"), + dict.GenInfoOption(PayTypeAliPay, "支付宝"), + dict.GenDefaultOption(PayTypeQQPay, "QQ支付"), +} diff --git a/server/internal/consts/pubsub.go b/server/internal/consts/pubsub.go new file mode 100644 index 0000000..eff5e9c --- /dev/null +++ b/server/internal/consts/pubsub.go @@ -0,0 +1,12 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +const ( + ClusterSyncSysconfig = "cluster.sync.sysConfig" // 系统配置 + ClusterSyncSysBlacklist = "cluster.sync.sysBlacklist" // 系统黑名单 + ClusterSyncSysSuperAdmin = "cluster.sync.superAdmin" // 超管 +) diff --git a/server/internal/consts/queue.go b/server/internal/consts/queue.go new file mode 100644 index 0000000..0aa91a4 --- /dev/null +++ b/server/internal/consts/queue.go @@ -0,0 +1,13 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 消息队列 +const ( + QueueLogTopic = `request_log` // 访问日志 + QueueLoginLogTopic = `login_log` // 登录日志 + QueueServeLogTopic = `serve_log` // 服务日志 +) diff --git a/server/internal/consts/role.go b/server/internal/consts/role.go new file mode 100644 index 0000000..eb2e846 --- /dev/null +++ b/server/internal/consts/role.go @@ -0,0 +1,90 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 数据范围 +const ( + RoleDataAll = 1 // 全部权限 + + // 通过部门划分 + RoleDataNowDept = 2 // 当前部门 + RoleDataDeptAndSub = 3 // 当前部门及以下部门 + RoleDataDeptCustom = 4 // 自定义部门 + + // 通过上下级关系划分 + RoleDataSelf = 5 // 仅自己 + RoleDataSelfAndSub = 6 // 自己和直属下级 + RoleDataSelfAndAllSub = 7 // 自己和全部下级 +) + +var RoleDataNameMap = map[int]string{ + RoleDataAll: "全部权限", + RoleDataNowDept: "当前部门", + RoleDataDeptAndSub: "当前及以下部门", + RoleDataDeptCustom: "自定义部门", + RoleDataSelf: "仅自己", + RoleDataSelfAndSub: "自己和直属下级", + RoleDataSelfAndAllSub: "自己和全部下级", +} + +type GroupScopeSelect struct { + Type string `json:"type,omitempty"` + Label string `json:"label"` + Key int `json:"key"` + Value int `json:"value,omitempty"` + Children []ScopeSelect `json:"children,omitempty"` +} + +type ScopeSelect struct { + Label string `json:"label"` + Value int `json:"value"` +} + +var DataScopeSelect = []GroupScopeSelect{ + { + Label: RoleDataNameMap[RoleDataAll], + Key: RoleDataAll, + Value: RoleDataAll, + }, + { + Type: "group", + Label: "按部门划分", + Key: -1, + Children: []ScopeSelect{ + { + Label: RoleDataNameMap[RoleDataNowDept], + Value: RoleDataNowDept, + }, + { + Label: RoleDataNameMap[RoleDataDeptAndSub], + Value: RoleDataDeptAndSub, + }, + { + Label: RoleDataNameMap[RoleDataDeptCustom], + Value: RoleDataDeptCustom, + }, + }, + }, + { + Type: "group", + Label: "按上下级关系划分", + Key: -2, + Children: []ScopeSelect{ + { + Label: RoleDataNameMap[RoleDataSelf], + Value: RoleDataSelf, + }, + { + Label: RoleDataNameMap[RoleDataSelfAndSub], + Value: RoleDataSelfAndSub, + }, + { + Label: RoleDataNameMap[RoleDataSelfAndAllSub], + Value: RoleDataSelfAndAllSub, + }, + }, + }, +} diff --git a/server/internal/consts/servelicense.go b/server/internal/consts/servelicense.go new file mode 100644 index 0000000..96e9dc8 --- /dev/null +++ b/server/internal/consts/servelicense.go @@ -0,0 +1,29 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +func init() { + dict.RegisterEnums("ServerLicenseGroupOptions", "服务授权分组选项", ServerLicenseGroupOptions) +} + +// 授权分组 +const ( + LicenseGroupDefault = "default" // 默认组 + LicenseGroupCron = "cron" // 定时任务 + LicenseGroupAuth = "auth" // 服务授权 +) + +// ServerLicenseGroupOptions 服务授权分组选项 +var ServerLicenseGroupOptions = []*model.Option{ + dict.GenWarningOption(LicenseGroupDefault, "默认组"), + dict.GenSuccessOption(LicenseGroupCron, "定时任务"), + dict.GenSuccessOption(LicenseGroupAuth, "服务授权"), +} diff --git a/server/internal/consts/sms.go b/server/internal/consts/sms.go new file mode 100644 index 0000000..2836e24 --- /dev/null +++ b/server/internal/consts/sms.go @@ -0,0 +1,33 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 短信驱动 +const ( + SmsDriveAliYun = "aliyun" // 阿里云 + SmsDriveTencent = "tencent" // 腾讯云 +) + +// 短信内置模板 +const ( + SmsTemplateCode = "code" // 通用验证码 + SmsTemplateLogin = "login" // 登录 + SmsTemplateRegister = "register" // 注册 + SmsTemplateResetPwd = "resetPwd" // 重置密码 + SmsTemplateBind = "bind" // 绑定手机号 + SmsTemplateCash = "cash" // 申请提现 +) + +var ( + SmsTemplateEventMap = map[string]string{ + SmsTemplateCode: "通用验证码", + SmsTemplateLogin: "登录", + SmsTemplateRegister: "注册", + SmsTemplateResetPwd: "重置密码", + SmsTemplateBind: "绑定手机号", + SmsTemplateCash: "申请提现", + } +) diff --git a/server/internal/consts/status.go b/server/internal/consts/status.go new file mode 100644 index 0000000..eb379f9 --- /dev/null +++ b/server/internal/consts/status.go @@ -0,0 +1,49 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +import ( + "hotgo/internal/library/dict" + "hotgo/internal/model" +) + +func init() { + dict.RegisterEnums("CodeStatusOptions", "验证码状态选项", CodeStatusOptions) + dict.RegisterEnums("BlacklistStatusOptions", "黑名单拉黑状态选项", BlacklistStatusOptions) +} + +// 状态码 +const ( + StatusALL int = -1 // 全部状态 + StatusEnabled int = 1 // 启用 + StatusDisable int = 2 // 禁用 + StatusDelete int = 3 // 已删除 +) + +var StatusSlice = []int{StatusALL, StatusEnabled, StatusDisable, StatusDelete} + +// 验证码状态 +const ( + CodeStatusNotUsed = 1 // 未使用 + CodeStatusUsed = 2 // 已使用 +) + +// CodeStatusOptions 验证码状态选项 +var CodeStatusOptions = []*model.Option{ + dict.GenWarningOption(CodeStatusNotUsed, "未使用"), + dict.GenSuccessOption(CodeStatusUsed, "已使用"), +} + +const ( + BlacklistStatusDisable = 1 // 封禁中 + BlacklistStatusEnabled = 2 // 已解封 +) + +// BlacklistStatusOptions 黑名单拉黑状态选项 +var BlacklistStatusOptions = []*model.Option{ + dict.GenWarningOption(BlacklistStatusDisable, "封禁中"), + dict.GenSuccessOption(BlacklistStatusEnabled, "已解封"), +} diff --git a/server/internal/consts/upload.go b/server/internal/consts/upload.go new file mode 100644 index 0000000..b760381 --- /dev/null +++ b/server/internal/consts/upload.go @@ -0,0 +1,16 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 上传存储驱动 +const ( + UploadDriveLocal = "local" // 本地驱动 + UploadDriveUCloud = "ucloud" // ucloud对象存储 + UploadDriveCos = "cos" // 腾讯云cos + UploadDriveOss = "oss" // 阿里云oss + UploadDriveQiNiu = "qiniu" // 七牛云对象存储 + UploadDriveMinio = "minio" // minio对象存储 +) diff --git a/server/internal/consts/version.go b/server/internal/consts/version.go new file mode 100644 index 0000000..0c77457 --- /dev/null +++ b/server/internal/consts/version.go @@ -0,0 +1,11 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2025 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// VersionApp HotGo版本 +const ( + VersionApp = "2.18.9" +) diff --git a/server/internal/consts/wechat.go b/server/internal/consts/wechat.go new file mode 100644 index 0000000..54565fd --- /dev/null +++ b/server/internal/consts/wechat.go @@ -0,0 +1,18 @@ +// Package consts +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package consts + +// 授权类型 +const ( + WechatAuthorizeOpenId = "openId" // 设置openid + WechatAuthorizeBindLogin = "bindLogin" // 绑定微信登录 +) + +// 应用授权作用域 +const ( + WechatScopeBase = "snsapi_base" // 只获取openid,无需用户授权 + WechatScopeUserinfo = "snsapi_userinfo" // 获取用户信息,需要授权 +) diff --git a/server/internal/controller/admin/admin/cash.go b/server/internal/controller/admin/admin/cash.go new file mode 100644 index 0000000..124b034 --- /dev/null +++ b/server/internal/controller/admin/admin/cash.go @@ -0,0 +1,60 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "context" + "hotgo/api/admin/cash" + "hotgo/internal/library/contexts" + "hotgo/internal/model/input/adminin" + "hotgo/internal/service" +) + +var ( + Cash = cCash{} +) + +type cCash struct{} + +// View 获取指定信息 +func (c *cCash) View(ctx context.Context, req *cash.ViewReq) (res *cash.ViewRes, err error) { + data, err := service.AdminCash().View(ctx, &req.CashViewInp) + if err != nil { + return + } + + res = new(cash.ViewRes) + res.CashViewModel = data + return +} + +// List 查看列表 +func (c *cCash) List(ctx context.Context, req *cash.ListReq) (res *cash.ListRes, err error) { + list, totalCount, err := service.AdminCash().List(ctx, &req.CashListInp) + if err != nil { + return + } + + res = new(cash.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Apply 申请提现 +func (c *cCash) Apply(ctx context.Context, req *cash.ApplyReq) (res *cash.ApplyRes, err error) { + err = service.AdminCash().Apply(ctx, &adminin.CashApplyInp{ + Money: req.Money, + MemberId: contexts.GetUserId(ctx), + }) + return +} + +// Payment 提现打款处理 +func (c *cCash) Payment(ctx context.Context, req *cash.PaymentReq) (res *cash.PaymentRes, err error) { + err = service.AdminCash().Payment(ctx, &req.CashPaymentInp) + return +} diff --git a/server/internal/controller/admin/admin/credits_log.go b/server/internal/controller/admin/admin/credits_log.go new file mode 100644 index 0000000..003fc82 --- /dev/null +++ b/server/internal/controller/admin/admin/credits_log.go @@ -0,0 +1,39 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.5.3 +// @AutoGenerate Date 2023-04-15 15:59:58 +package admin + +import ( + "context" + "hotgo/api/admin/creditslog" + "hotgo/internal/service" +) + +var ( + CreditsLog = cCreditsLog{} +) + +type cCreditsLog struct{} + +// List 查看资产变动列表 +func (c *cCreditsLog) List(ctx context.Context, req *creditslog.ListReq) (res *creditslog.ListRes, err error) { + list, totalCount, err := service.AdminCreditsLog().List(ctx, &req.CreditsLogListInp) + if err != nil { + return + } + + res = new(creditslog.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出资产变动列表 +func (c *cCreditsLog) Export(ctx context.Context, req *creditslog.ExportReq) (res *creditslog.ExportRes, err error) { + err = service.AdminCreditsLog().Export(ctx, &req.CreditsLogListInp) + return +} diff --git a/server/internal/controller/admin/admin/dept.go b/server/internal/controller/admin/admin/dept.go new file mode 100644 index 0000000..5730ce6 --- /dev/null +++ b/server/internal/controller/admin/admin/dept.go @@ -0,0 +1,75 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "context" + "hotgo/api/admin/dept" + "hotgo/internal/service" +) + +var ( + Dept = cDept{} +) + +type cDept struct{} + +// Delete 删除 +func (c *cDept) Delete(ctx context.Context, req *dept.DeleteReq) (res *dept.DeleteRes, err error) { + err = service.AdminDept().Delete(ctx, &req.DeptDeleteInp) + return +} + +// Edit 更新 +func (c *cDept) Edit(ctx context.Context, req *dept.EditReq) (res *dept.EditRes, err error) { + err = service.AdminDept().Edit(ctx, &req.DeptEditInp) + return +} + +// MaxSort 最大排序 +func (c *cDept) MaxSort(ctx context.Context, req *dept.MaxSortReq) (res *dept.MaxSortRes, err error) { + res = new(dept.MaxSortRes) + res.DeptMaxSortModel, err = service.AdminDept().MaxSort(ctx, &req.DeptMaxSortInp) + return +} + +// View 获取指定信息 +func (c *cDept) View(ctx context.Context, req *dept.ViewReq) (res *dept.ViewRes, err error) { + res = new(dept.ViewRes) + res.DeptViewModel, err = service.AdminDept().View(ctx, &req.DeptViewInp) + return +} + +// List 查看列表 +func (c *cDept) List(ctx context.Context, req *dept.ListReq) (res *dept.ListRes, err error) { + data, err := service.AdminDept().List(ctx, &req.DeptListInp) + if err != nil || data == nil { + return + } + + res = (*dept.ListRes)(&data) + return +} + +// Option 获取部门选项树 +func (c *cDept) Option(ctx context.Context, req *dept.OptionReq) (res *dept.OptionRes, err error) { + list, totalCount, err := service.AdminDept().Option(ctx, &req.DeptOptionInp) + if err != nil { + return + } + + res = new(dept.OptionRes) + res.DeptOptionModel = list + res.PageRes.Pack(req, totalCount) + return +} + +// TreeOption 获取部门管理关系树选项 +func (c *cDept) TreeOption(ctx context.Context, req *dept.TreeOptionReq) (res *dept.TreeOptionRes, err error) { + data, err := service.AdminDept().TreeOption(ctx) + res = (*dept.TreeOptionRes)(&data) + return +} diff --git a/server/internal/controller/admin/admin/member.go b/server/internal/controller/admin/admin/member.go new file mode 100644 index 0000000..6724e58 --- /dev/null +++ b/server/internal/controller/admin/admin/member.go @@ -0,0 +1,145 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "hotgo/api/admin/member" + "hotgo/internal/library/contexts" + "hotgo/internal/model/input/adminin" + "hotgo/internal/service" +) + +var ( + Member = cMember{} +) + +type cMember struct{} + +// UpdateCash 修改代理商提现信息 +func (c *cMember) UpdateCash(ctx context.Context, req *member.UpdateCashReq) (res *member.UpdateCashRes, err error) { + err = service.AdminMember().UpdateCash(ctx, &req.MemberUpdateCashInp) + return +} + +// UpdateEmail 换绑邮箱 +func (c *cMember) UpdateEmail(ctx context.Context, req *member.UpdateEmailReq) (res *member.UpdateEmailRes, err error) { + err = service.AdminMember().UpdateEmail(ctx, &req.MemberUpdateEmailInp) + return +} + +// UpdateMobile 换绑手机号 +func (c *cMember) UpdateMobile(ctx context.Context, req *member.UpdateMobileReq) (res *member.UpdateMobileRes, err error) { + err = service.AdminMember().UpdateMobile(ctx, &req.MemberUpdateMobileInp) + return +} + +// UpdateProfile 更新用户资料 +func (c *cMember) UpdateProfile(ctx context.Context, req *member.UpdateProfileReq) (res *member.UpdateProfileRes, err error) { + err = service.AdminMember().UpdateProfile(ctx, &req.MemberUpdateProfileInp) + return +} + +// UpdatePwd 修改登录密码 +func (c *cMember) UpdatePwd(ctx context.Context, req *member.UpdatePwdReq) (res *member.UpdatePwdRes, err error) { + var memberId = contexts.Get(ctx).User.Id + if memberId <= 0 { + err = gerror.New("获取用户信息失败!") + return + } + + err = service.AdminMember().UpdatePwd(ctx, &adminin.MemberUpdatePwdInp{ + Id: memberId, + OldPassword: req.OldPassword, + NewPassword: req.NewPassword, + }) + return +} + +// ResetPwd 重置密码 +func (c *cMember) ResetPwd(ctx context.Context, req *member.ResetPwdReq) (res *member.ResetPwdRes, err error) { + err = service.AdminMember().ResetPwd(ctx, &req.MemberResetPwdInp) + return +} + +// MemberInfo 登录用户信息 +func (c *cMember) MemberInfo(ctx context.Context, _ *member.InfoReq) (res *member.InfoRes, err error) { + data, err := service.AdminMember().LoginMemberInfo(ctx) + if err != nil { + return + } + + res = new(member.InfoRes) + res.LoginMemberInfoModel = data + return +} + +// Delete 删除用户 +func (c *cMember) Delete(ctx context.Context, req *member.DeleteReq) (res *member.DeleteRes, err error) { + err = service.AdminMember().Delete(ctx, &req.MemberDeleteInp) + return +} + +// Edit 修改/新增用户 +func (c *cMember) Edit(ctx context.Context, req *member.EditReq) (res *member.EditRes, err error) { + err = service.AdminMember().Edit(ctx, &req.MemberEditInp) + return +} + +// View 获取指定用户信息 +func (c *cMember) View(ctx context.Context, req *member.ViewReq) (res *member.ViewRes, err error) { + data, err := service.AdminMember().View(ctx, &req.MemberViewInp) + if err != nil { + return + } + + res = new(member.ViewRes) + res.MemberViewModel = data + return +} + +// List 查看用户列表 +func (c *cMember) List(ctx context.Context, req *member.ListReq) (res *member.ListRes, err error) { + list, totalCount, err := service.AdminMember().List(ctx, &req.MemberListInp) + if err != nil { + return + } + + res = new(member.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Status 更新用户状态 +func (c *cMember) Status(ctx context.Context, req *member.StatusReq) (res *member.StatusRes, err error) { + err = service.AdminMember().Status(ctx, &req.MemberStatusInp) + return +} + +// Select 获取可选的后台用户选项 +func (c *cMember) Select(ctx context.Context, req *member.SelectReq) (res *member.SelectRes, err error) { + data, err := service.AdminMember().Select(ctx, &req.MemberSelectInp) + if err != nil { + return + } + + res = (*member.SelectRes)(&data) + return +} + +// AddBalance 增加用户余额 +func (c *cMember) AddBalance(ctx context.Context, req *member.AddBalanceReq) (res *member.AddBalanceRes, err error) { + err = service.AdminMember().AddBalance(ctx, &req.MemberAddBalanceInp) + return +} + +// AddIntegral 增加用户积分 +func (c *cMember) AddIntegral(ctx context.Context, req *member.AddIntegralReq) (res *member.AddIntegralRes, err error) { + err = service.AdminMember().AddIntegral(ctx, &req.MemberAddIntegralInp) + return +} diff --git a/server/internal/controller/admin/admin/menu.go b/server/internal/controller/admin/admin/menu.go new file mode 100644 index 0000000..3bd2de5 --- /dev/null +++ b/server/internal/controller/admin/admin/menu.go @@ -0,0 +1,37 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "context" + "hotgo/api/admin/menu" + "hotgo/internal/service" +) + +// Menu 菜单 +var ( + Menu = cMenu{} +) + +type cMenu struct{} + +// Delete 删除 +func (c *cMenu) Delete(ctx context.Context, req *menu.DeleteReq) (res *menu.DeleteRes, err error) { + err = service.AdminMenu().Delete(ctx, &req.MenuDeleteInp) + return +} + +// Edit 更新 +func (c *cMenu) Edit(ctx context.Context, req *menu.EditReq) (res *menu.EditRes, err error) { + err = service.AdminMenu().Edit(ctx, &req.MenuEditInp) + return +} + +// List 获取列表 +func (c *cMenu) List(ctx context.Context, req *menu.ListReq) (res menu.ListRes, err error) { + res.MenuListModel, err = service.AdminMenu().List(ctx, &req.MenuListInp) + return +} diff --git a/server/internal/controller/admin/admin/monitor.go b/server/internal/controller/admin/admin/monitor.go new file mode 100644 index 0000000..2a8a936 --- /dev/null +++ b/server/internal/controller/admin/admin/monitor.go @@ -0,0 +1,243 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gstr" + "hotgo/api/admin/monitor" + "hotgo/internal/consts" + "hotgo/internal/dao" + "hotgo/internal/model/entity" + "hotgo/internal/model/input/form" + "hotgo/internal/service" + "hotgo/internal/websocket" + "hotgo/utility/simple" + "hotgo/utility/useragent" + "sort" +) + +// Monitor 监控 +var Monitor = cMonitor{ + wsManager: websocket.Manager(), +} + +type cMonitor struct { + wsManager *websocket.ClientManager +} + +// UserOffline 下线用户 +func (c *cMonitor) UserOffline(ctx context.Context, req *monitor.UserOfflineReq) (res *monitor.UserOfflineRes, err error) { + client := c.wsManager.GetClient(req.Id) + if client == nil { + err = gerror.New("客户端已离线") + return + } + + simple.SafeGo(ctx, func(ctx context.Context) { + websocket.SendSuccess(client, "kick") + websocket.Close(client) + }) + return +} + +// UserOnlineList 获取用户在线列表 +func (c *cMonitor) UserOnlineList(ctx context.Context, req *monitor.UserOnlineListReq) (res *monitor.UserOnlineListRes, err error) { + var ( + clients []*monitor.UserOnlineModel + i int + ) + + if c.wsManager.GetClientsLen() == 0 { + return + } + + for conn := range c.wsManager.GetClients() { + if conn.SendClose || conn.User == nil { + continue + } + + if req.UserId > 0 && req.UserId != conn.User.Id { + continue + } + + if req.Username != "" && req.Username != conn.User.Username { + continue + } + + if req.IP != "" && !gstr.Contains(conn.IP, req.IP) { + continue + } + + if len(req.FirstTime) == 2 && (conn.User.LoginAt.Before(req.FirstTime[0]) || conn.User.LoginAt.After(req.FirstTime[1])) { + continue + } + + clients = append(clients, &monitor.UserOnlineModel{ + ID: conn.ID, + IP: conn.IP, + Os: useragent.GetOs(conn.UserAgent), + Browser: useragent.GetBrowser(conn.UserAgent), + FirstTime: conn.User.LoginAt.Unix(), + HeartbeatTime: conn.HeartbeatTime, + App: conn.User.App, + UserId: conn.User.Id, + Username: conn.User.Username, + Avatar: conn.User.Avatar, + }) + } + + res = new(monitor.UserOnlineListRes) + res.PageRes.Pack(req, len(clients)) + + sort.Slice(clients, func(i, j int) bool { + if clients[i].FirstTime == clients[j].FirstTime { + return clients[i].ID < clients[j].ID + } + return clients[i].FirstTime < clients[j].FirstTime + }) + + _, perPage, offset := form.CalPage(req.Page, req.PerPage) + for k, v := range clients { + if k >= offset && i <= perPage { + if simple.IsDemo(ctx) { + v.IP = consts.DemoTips + } + res.List = append(res.List, v) + i++ + } + } + return +} + +// NetOnlineList 获取服务在线列表 +func (c *cMonitor) NetOnlineList(ctx context.Context, req *monitor.NetOnlineListReq) (res *monitor.NetOnlineListRes, err error) { + var ( + clients []*monitor.NetOnlineModel + i int + cols = dao.SysServeLicense.Columns() + serv = service.TCPServer().Instance() + models *entity.SysServeLicense + ) + + conns := serv.GetClients() + if len(conns) == 0 { + res = new(monitor.NetOnlineListRes) + res.PageRes.Pack(req, 0) + return + } + + for _, conn := range conns { + v := &monitor.NetOnlineModel{ + AuthMeta: conn.Auth, + Id: conn.CID, + IsAuth: conn.Auth != nil, + Addr: conn.RemoteAddr().String(), + Port: gstr.SubStrFromEx(conn.LocalAddr().String(), `:`), + FirstTime: conn.FirstTime, + HeartbeatTime: conn.Heartbeat, + Proto: "TCP", + } + + if v.IsAuth { + if err = dao.SysServeLicense.Ctx(ctx).Where(cols.Appid, conn.Auth.AppId).Where(cols.Group, conn.Auth.Group).Scan(&models); err != nil { + return + } + + if models == nil { + continue + } + + v.LicenseId = models.Id + v.LicenseName = models.Name + v.LoginTimes = models.LoginTimes + v.Online = serv.GetAppIdOnline(models.Appid) + v.OnlineLimit = models.OnlineLimit + } + + if req.Addr != "" && !gstr.Contains(v.Addr, req.Addr) { + continue + } + + if req.Name != "" && !gstr.Contains(v.Name, req.Name) { + continue + } + + if req.Group != "" && (!v.IsAuth || v.Group != req.Group) { + continue + } + + if req.AppId != "" && (!v.IsAuth || v.AppId != req.AppId) { + continue + } + + ft := gtime.New(conn.FirstTime) + if len(req.FirstTime) == 2 && (ft.Before(req.FirstTime[0]) || ft.After(req.FirstTime[1])) { + continue + } + clients = append(clients, v) + } + + res = new(monitor.NetOnlineListRes) + res.PageRes.Pack(req, len(clients)) + + sort.Slice(clients, func(i, j int) bool { + return clients[i].Id > clients[j].Id + }) + + _, perPage, offset := form.CalPage(req.Page, req.PerPage) + for k, v := range clients { + if k >= offset && i <= perPage { + res.List = append(res.List, v) + i++ + } + } + return +} + +// NetOption 获取服务选项 +func (c *cMonitor) NetOption(ctx context.Context, req *monitor.NetOptionReq) (res *monitor.NetOptionRes, err error) { + res = new(monitor.NetOptionRes) + + for _, v := range service.TCPServer().Instance().GetRoutes() { + // 无需勾选的路由 + disabled := false + if v.Id == "ServerLoginReq" || v.Id == "ServerHeartbeatReq" { + disabled = true + } + + res.Routes = append(res.Routes, &monitor.RouteSelect{ + Value: v.Id, + Label: v.Id, + Disabled: disabled, + IsRPC: v.IsRPC, + }) + } + + sort.Slice(res.Routes, func(i, j int) bool { + if res.Routes[i].IsRPC && !res.Routes[j].IsRPC { + return true + } else if !res.Routes[i].IsRPC && res.Routes[j].IsRPC { + return false + } + return res.Routes[i].Label < res.Routes[j].Label + }) + return +} + +// NetOffline 下线服务 +func (c *cMonitor) NetOffline(ctx context.Context, req *monitor.NetOfflineReq) (res *monitor.NetOfflineRes, err error) { + conn := service.TCPServer().Instance().GetClientById(req.Id) + if conn == nil { + err = gerror.New("客户端不在线") + return + } + // 关闭连接 + conn.Close() + return +} diff --git a/server/internal/controller/admin/admin/notice.go b/server/internal/controller/admin/admin/notice.go new file mode 100644 index 0000000..068e71c --- /dev/null +++ b/server/internal/controller/admin/admin/notice.go @@ -0,0 +1,127 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "context" + "hotgo/api/admin/notice" + "hotgo/internal/consts" + "hotgo/internal/service" +) + +var ( + Notice = cNotice{} +) + +type cNotice struct{} + +// Delete 删除 +func (c *cNotice) Delete(ctx context.Context, req *notice.DeleteReq) (res *notice.DeleteRes, err error) { + err = service.AdminNotice().Delete(ctx, &req.NoticeDeleteInp) + return +} + +// Edit 更新 +func (c *cNotice) Edit(ctx context.Context, req *notice.EditReq) (res *notice.EditRes, err error) { + err = service.AdminNotice().Edit(ctx, &req.NoticeEditInp) + return +} + +// MaxSort 最大排序 +func (c *cNotice) MaxSort(ctx context.Context, req *notice.MaxSortReq) (res *notice.MaxSortRes, err error) { + res = new(notice.MaxSortRes) + res.NoticeMaxSortModel, err = service.AdminNotice().MaxSort(ctx, &req.NoticeMaxSortInp) + return +} + +// View 获取指定信息 +func (c *cNotice) View(ctx context.Context, req *notice.ViewReq) (res *notice.ViewRes, err error) { + data, err := service.AdminNotice().View(ctx, &req.NoticeViewInp) + if err != nil { + return + } + + res = new(notice.ViewRes) + res.NoticeViewModel = data + return +} + +// List 查看列表 +func (c *cNotice) List(ctx context.Context, req *notice.ListReq) (res *notice.ListRes, err error) { + list, totalCount, err := service.AdminNotice().List(ctx, &req.NoticeListInp) + if err != nil { + return nil, err + } + + res = new(notice.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Status 更新状态 +func (c *cNotice) Status(ctx context.Context, req *notice.StatusReq) (res *notice.StatusRes, err error) { + err = service.AdminNotice().Status(ctx, &req.NoticeStatusInp) + return +} + +// Notify 更新通知 +func (c *cNotice) Notify(ctx context.Context, req *notice.EditNotifyReq) (res *notice.EditNotifyRes, err error) { + req.Type = consts.NoticeTypeNotify + err = service.AdminNotice().Edit(ctx, &req.NoticeEditInp) + return +} + +// Notice 更新公告 +func (c *cNotice) Notice(ctx context.Context, req *notice.EditNoticeReq) (res *notice.EditNoticeRes, err error) { + req.Type = consts.NoticeTypeNotice + err = service.AdminNotice().Edit(ctx, &req.NoticeEditInp) + return +} + +// Letter 更新私信 +func (c *cNotice) Letter(ctx context.Context, req *notice.EditLetterReq) (res *notice.EditLetterRes, err error) { + req.Type = consts.NoticeTypeLetter + err = service.AdminNotice().Edit(ctx, &req.NoticeEditInp) + return +} + +// UpRead 更新已读 +func (c *cNotice) UpRead(ctx context.Context, req *notice.UpReadReq) (res *notice.UpReadRes, err error) { + err = service.AdminNotice().UpRead(ctx, &req.NoticeUpReadInp) + return +} + +// PullMessages 拉取未读消息列表 +func (c *cNotice) PullMessages(ctx context.Context, req *notice.PullMessagesReq) (res *notice.PullMessagesRes, err error) { + data, err := service.AdminNotice().PullMessages(ctx, &req.PullMessagesInp) + if err != nil { + return + } + + res = new(notice.PullMessagesRes) + res.PullMessagesModel = data + return +} + +// ReadAll 全部已读 +func (c *cNotice) ReadAll(ctx context.Context, req *notice.ReadAllReq) (res *notice.ReadAllRes, err error) { + err = service.AdminNotice().ReadAll(ctx, &req.NoticeReadAllInp) + return +} + +// MessageList 我的消息列表 +func (c *cNotice) MessageList(ctx context.Context, req *notice.MessageListReq) (res *notice.MessageListRes, err error) { + list, totalCount, err := service.AdminNotice().MessageList(ctx, &req.NoticeMessageListInp) + if err != nil { + return + } + + res = new(notice.MessageListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} diff --git a/server/internal/controller/admin/admin/order.go b/server/internal/controller/admin/admin/order.go new file mode 100644 index 0000000..5f6e2de --- /dev/null +++ b/server/internal/controller/admin/admin/order.go @@ -0,0 +1,91 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "context" + "hotgo/api/admin/order" + "hotgo/internal/service" +) + +var ( + Order = cOrder{} +) + +type cOrder struct{} + +// AcceptRefund 受理申请退款 +func (c *cOrder) AcceptRefund(ctx context.Context, req *order.AcceptRefundReq) (res *order.AcceptRefundRes, err error) { + err = service.AdminOrder().AcceptRefund(ctx, &req.OrderAcceptRefundInp) + return +} + +// ApplyRefund 申请退款 +func (c *cOrder) ApplyRefund(ctx context.Context, req *order.ApplyRefundReq) (res *order.ApplyRefundRes, err error) { + err = service.AdminOrder().ApplyRefund(ctx, &req.OrderApplyRefundInp) + return +} + +// Create 创建充值订单 +func (c *cOrder) Create(ctx context.Context, req *order.CreateReq) (res *order.CreateRes, err error) { + data, err := service.AdminOrder().Create(ctx, &req.OrderCreateInp) + if err != nil { + return + } + + res = new(order.CreateRes) + res.OrderCreateModel = data + return +} + +// List 查看充值订单列表 +func (c *cOrder) List(ctx context.Context, req *order.ListReq) (res *order.ListRes, err error) { + list, totalCount, err := service.AdminOrder().List(ctx, &req.OrderListInp) + if err != nil { + return + } + + res = new(order.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出充值订单列表 +func (c *cOrder) Export(ctx context.Context, req *order.ExportReq) (res *order.ExportRes, err error) { + err = service.AdminOrder().Export(ctx, &req.OrderListInp) + return +} + +// Edit 更新充值订单 +func (c *cOrder) Edit(ctx context.Context, req *order.EditReq) (res *order.EditRes, err error) { + err = service.AdminOrder().Edit(ctx, &req.OrderEditInp) + return +} + +// View 获取指定充值订单信息 +func (c *cOrder) View(ctx context.Context, req *order.ViewReq) (res *order.ViewRes, err error) { + data, err := service.AdminOrder().View(ctx, &req.OrderViewInp) + if err != nil { + return + } + + res = new(order.ViewRes) + res.OrderViewModel = data + return +} + +// Delete 删除充值订单 +func (c *cOrder) Delete(ctx context.Context, req *order.DeleteReq) (res *order.DeleteRes, err error) { + err = service.AdminOrder().Delete(ctx, &req.OrderDeleteInp) + return +} + +// Status 更新充值订单状态 +func (c *cOrder) Status(ctx context.Context, req *order.StatusReq) (res *order.StatusRes, err error) { + err = service.AdminOrder().Status(ctx, &req.OrderStatusInp) + return +} diff --git a/server/internal/controller/admin/admin/post.go b/server/internal/controller/admin/admin/post.go new file mode 100644 index 0000000..2c2faf8 --- /dev/null +++ b/server/internal/controller/admin/admin/post.go @@ -0,0 +1,67 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "context" + "hotgo/api/admin/post" + "hotgo/internal/service" +) + +// Post 岗位 +var Post = cPost{} + +type cPost struct{} + +// Delete 删除 +func (c *cPost) Delete(ctx context.Context, req *post.DeleteReq) (res *post.DeleteRes, err error) { + err = service.AdminPost().Delete(ctx, &req.PostDeleteInp) + return +} + +// Edit 修改/新增 +func (c *cPost) Edit(ctx context.Context, req *post.EditReq) (res *post.EditRes, err error) { + err = service.AdminPost().Edit(ctx, &req.PostEditInp) + return +} + +// MaxSort 最大排序 +func (c *cPost) MaxSort(ctx context.Context, req *post.MaxSortReq) (res *post.MaxSortRes, err error) { + res = new(post.MaxSortRes) + res.PostMaxSortModel, err = service.AdminPost().MaxSort(ctx, &req.PostMaxSortInp) + return +} + +// View 获取指定信息 +func (c *cPost) View(ctx context.Context, req *post.ViewReq) (res *post.ViewRes, err error) { + data, err := service.AdminPost().View(ctx, &req.PostViewInp) + if err != nil { + return + } + + res = new(post.ViewRes) + res.PostViewModel = data + return +} + +// List 获取列表 +func (c *cPost) List(ctx context.Context, req *post.ListReq) (res *post.ListRes, err error) { + list, totalCount, err := service.AdminPost().List(ctx, &req.PostListInp) + if err != nil { + return + } + + res = new(post.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Status 更新状态 +func (c *cPost) Status(ctx context.Context, req *post.StatusReq) (res *post.StatusRes, err error) { + err = service.AdminPost().Status(ctx, &req.PostStatusInp) + return +} diff --git a/server/internal/controller/admin/admin/role.go b/server/internal/controller/admin/admin/role.go new file mode 100644 index 0000000..92e626c --- /dev/null +++ b/server/internal/controller/admin/admin/role.go @@ -0,0 +1,81 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "context" + "hotgo/api/admin/role" + "hotgo/internal/consts" + "hotgo/internal/library/contexts" + "hotgo/internal/service" +) + +var ( + Role = cRole{} +) + +type cRole struct{} + +// List 获取列表 +func (c *cRole) List(ctx context.Context, req *role.ListReq) (res *role.ListRes, err error) { + list, totalCount, err := service.AdminRole().List(ctx, &req.RoleListInp) + if err != nil { + return + } + + res = new(role.ListRes) + res.RoleListModel = list + res.PageRes.Pack(req, totalCount) + return +} + +// Edit 修改角色 +func (c *cRole) Edit(ctx context.Context, req *role.EditReq) (res *role.EditRes, err error) { + err = service.AdminRole().Edit(ctx, &req.RoleEditInp) + return +} + +// Delete 删除 +func (c *cRole) Delete(ctx context.Context, req *role.DeleteReq) (res *role.DeleteRes, err error) { + err = service.AdminRole().Delete(ctx, &req.RoleDeleteInp) + return +} + +// Dynamic 动态路由 +func (c *cRole) Dynamic(ctx context.Context, _ *role.DynamicReq) (res *role.DynamicRes, err error) { + return service.AdminMenu().GetMenuList(ctx, contexts.GetUserId(ctx)) +} + +// GetPermissions 获取指定角色权限 +func (c *cRole) GetPermissions(ctx context.Context, req *role.GetPermissionsReq) (res *role.GetPermissionsRes, err error) { + data, err := service.AdminRole().GetPermissions(ctx, &req.GetPermissionsInp) + if err != nil { + return + } + + res = new(role.GetPermissionsRes) + res.GetPermissionsModel = data + return +} + +// UpdatePermissions 修改角色菜单权限 +func (c *cRole) UpdatePermissions(ctx context.Context, req *role.UpdatePermissionsReq) (res *role.UpdatePermissionsRes, err error) { + err = service.AdminRole().UpdatePermissions(ctx, &req.UpdatePermissionsInp) + return +} + +// DataScopeSelect 获取数据权限选项 +func (c *cRole) DataScopeSelect(_ context.Context, _ *role.DataScopeSelectReq) (res *role.DataScopeSelectRes, err error) { + res = new(role.DataScopeSelectRes) + res.List = consts.DataScopeSelect + return +} + +// DataScopeEdit 获取数据权限选项 +func (c *cRole) DataScopeEdit(ctx context.Context, req *role.DataScopeEditReq) (res *role.DataScopeEditRes, err error) { + err = service.AdminRole().DataScopeEdit(ctx, &req.DataScopeEditInp) + return +} diff --git a/server/internal/controller/admin/common/console.go b/server/internal/controller/admin/common/console.go new file mode 100644 index 0000000..9b2eaf6 --- /dev/null +++ b/server/internal/controller/admin/common/console.go @@ -0,0 +1,42 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "context" + "hotgo/api/admin/common" +) + +var Console = cConsole{} + +type cConsole struct{} + +// Stat 综合数据统计 +func (c *cConsole) Stat(_ context.Context, _ *common.ConsoleStatReq) (res *common.ConsoleStatRes, err error) { + res = new(common.ConsoleStatRes) + + // 此处均为模拟数据,可以根据实际业务情况替换成真实数据 + + res.Visits.DayVisits = 12010 + res.Visits.Rise = 13501 + res.Visits.Decline = 10502 + res.Visits.Amount = 10403 + + res.Saleroom.WeekSaleroom = 20501 + res.Saleroom.Amount = 21002 + res.Saleroom.Degree = 83.66 + + res.OrderLarge.WeekLarge = 39901 + res.OrderLarge.Rise = 31012 + res.OrderLarge.Decline = 30603 + res.OrderLarge.Amount = 36084 + + res.Volume.WeekLarge = 40021 + res.Volume.Rise = 40202 + res.Volume.Decline = 45003 + res.Volume.Amount = 49004 + return +} diff --git a/server/internal/controller/admin/common/ems.go b/server/internal/controller/admin/common/ems.go new file mode 100644 index 0000000..5c70c4e --- /dev/null +++ b/server/internal/controller/admin/common/ems.go @@ -0,0 +1,75 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "hotgo/api/admin/common" + "hotgo/internal/consts" + "hotgo/internal/dao" + "hotgo/internal/library/contexts" + "hotgo/internal/model/entity" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var Ems = new(cEms) + +type cEms struct{} + +// SendTest 发送测试邮件 +func (c *cEms) SendTest(ctx context.Context, req *common.SendTestEmailReq) (res *common.SendTestEmailRes, err error) { + err = service.SysEmsLog().Send(ctx, &sysin.SendEmsInp{ + Event: consts.EmsTemplateText, + Email: req.To, + Content: ` + + + + + 这是一封来自HotGo的测试邮件 + + + 这是您通过HotGo后台发送的测试邮件。当你收到这封邮件的时候,说明已经联调成功了,恭喜你! + + `, + }) + return +} + +// SendBindEms 发送换绑邮件 +func (c *cEms) SendBindEms(ctx context.Context, _ *common.SendBindEmsReq) (res *common.SendBindEmsRes, err error) { + var ( + memberId = contexts.GetUserId(ctx) + models *entity.AdminMember + ) + + if memberId <= 0 { + err = gerror.New("用户身份异常,请重新登录!") + return + } + + if err = dao.AdminMember.Ctx(ctx).Fields(dao.AdminMember.Columns().Email).Where(dao.AdminMember.Columns().Id, memberId).Scan(&models); err != nil { + return + } + + if models == nil { + err = gerror.New("用户信息不存在") + return + } + + if models.Email == "" { + err = gerror.New("未绑定邮箱无需发送") + return + } + + err = service.SysEmsLog().Send(ctx, &sysin.SendEmsInp{ + Event: consts.EmsTemplateBind, + Email: models.Email, + }) + return +} diff --git a/server/internal/controller/admin/common/site.go b/server/internal/controller/admin/common/site.go new file mode 100644 index 0000000..6dc1a31 --- /dev/null +++ b/server/internal/controller/admin/common/site.go @@ -0,0 +1,156 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "context" + "github.com/gogf/gf/v2/i18n/gi18n" + "hotgo/api/admin/common" + "hotgo/internal/consts" + "hotgo/internal/library/captcha" + "hotgo/internal/library/token" + "hotgo/internal/service" + "hotgo/utility/validate" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gmode" +) + +var Site = cSite{} + +type cSite struct{} + +// Ping ping +func (c *cSite) Ping(_ context.Context, _ *common.SitePingReq) (res *common.SitePingRes, err error) { + return +} + +// Config 获取配置 +func (c *cSite) Config(ctx context.Context, _ *common.SiteConfigReq) (res *common.SiteConfigRes, err error) { + request := ghttp.RequestFromCtx(ctx) + res = &common.SiteConfigRes{ + Version: consts.VersionApp, + WsAddr: c.getWsAddr(ctx, request), + Domain: c.getDomain(ctx, request), + Mode: gmode.Mode(), + } + return +} + +func (c *cSite) getWsAddr(ctx context.Context, request *ghttp.Request) string { + // 如果是本地IP访问,则认为是调试模式,走实际请求地址,否则走配置中的地址 + // 尝试读取hostname,兼容本地运行模式 + ip := ghttp.RequestFromCtx(ctx).GetHeader("hostname") + if len(ip) == 0 { + ip = ghttp.RequestFromCtx(ctx).GetHost() + } + + if validate.IsLocalIPAddr(ip) { + return "ws://" + ip + ":" + gstr.StrEx(request.Host, ":") + g.Cfg().MustGet(ctx, "router.websocket.prefix").String() + } + + basic, err := service.SysConfig().GetBasic(ctx) + if err != nil || basic == nil { + return "" + } + return basic.WsAddr +} + +func (c *cSite) getDomain(ctx context.Context, request *ghttp.Request) string { + // 如果是本地IP访问,则认为是调试模式,走实际请求地址,否则走配置中的地址 + // 尝试读取hostname,兼容本地运行模式 + ip := ghttp.RequestFromCtx(ctx).GetHeader("hostname") + if len(ip) == 0 { + ip = ghttp.RequestFromCtx(ctx).GetHost() + } + + if validate.IsLocalIPAddr(ip) { + return "http://" + ip + ":" + gstr.StrEx(request.Host, ":") + } + + basic, err := service.SysConfig().GetBasic(ctx) + if err != nil || basic == nil { + return "" + } + return basic.Domain +} + +// LoginConfig 登录配置 +func (c *cSite) LoginConfig(ctx context.Context, _ *common.SiteLoginConfigReq) (res *common.SiteLoginConfigRes, err error) { + res = new(common.SiteLoginConfigRes) + login, err := service.SysConfig().GetLogin(ctx) + if err != nil { + return + } + + res.LoginConfig = login + res.I18nSwitch = g.Cfg().MustGet(ctx, "system.i18n.switch", true).Bool() + res.DefaultLanguage = g.Cfg().MustGet(ctx, "system.i18n.defaultLanguage", consts.SysDefaultLanguage).String() + res.ProjectName = gi18n.T(ctx, "HotGo管理系统") + return +} + +// Captcha 登录验证码 +func (c *cSite) Captcha(ctx context.Context, _ *common.LoginCaptchaReq) (res *common.LoginCaptchaRes, err error) { + loginConf, err := service.SysConfig().GetLogin(ctx) + if err != nil { + return + } + cid, base64 := captcha.Generate(ctx, loginConf.CaptchaType) + res = &common.LoginCaptchaRes{Cid: cid, Base64: base64} + return +} + +// Register 账号注册 +func (c *cSite) Register(ctx context.Context, req *common.RegisterReq) (res *common.RegisterRes, err error) { + err = service.AdminSite().Register(ctx, &req.RegisterInp) + return +} + +// AccountLogin 账号登录 +func (c *cSite) AccountLogin(ctx context.Context, req *common.AccountLoginReq) (res *common.AccountLoginRes, err error) { + login, err := service.SysConfig().GetLogin(ctx) + if err != nil { + return + } + + if !req.IsLock && login.CaptchaSwitch == consts.StatusEnabled { + // 校验 验证码 + if !captcha.Verify(req.Cid, req.Code) { + err = gerror.New("验证码错误") + return + } + } + + model, err := service.AdminSite().AccountLogin(ctx, &req.AccountLoginInp) + if err != nil { + return + } + + err = gconv.Scan(model, &res) + return +} + +// MobileLogin 手机号登录 +func (c *cSite) MobileLogin(ctx context.Context, req *common.MobileLoginReq) (res *common.MobileLoginRes, err error) { + model, err := service.AdminSite().MobileLogin(ctx, &req.MobileLoginInp) + if err != nil { + return + } + + err = gconv.Scan(model, &res) + return +} + +// Logout 注销登录 +func (c *cSite) Logout(ctx context.Context, _ *common.LoginLogoutReq) (res *common.LoginLogoutRes, err error) { + err = token.Logout(ghttp.RequestFromCtx(ctx)) + return +} diff --git a/server/internal/controller/admin/common/sms.go b/server/internal/controller/admin/common/sms.go new file mode 100644 index 0000000..c1f5c6a --- /dev/null +++ b/server/internal/controller/admin/common/sms.go @@ -0,0 +1,67 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "hotgo/api/admin/common" + "hotgo/internal/consts" + "hotgo/internal/dao" + "hotgo/internal/library/contexts" + "hotgo/internal/model/entity" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var Sms = new(cSms) + +type cSms struct{} + +// SendTest 发送测试短信 +func (c *cSms) SendTest(ctx context.Context, req *common.SendTestSmsReq) (res *common.SendTestSmsRes, err error) { + err = service.SysSmsLog().SendCode(ctx, &req.SendCodeInp) + return +} + +// SendBindSms 发送换绑短信 +func (c *cSms) SendBindSms(ctx context.Context, _ *common.SendBindSmsReq) (res *common.SendBindSmsRes, err error) { + var ( + memberId = contexts.GetUserId(ctx) + models *entity.AdminMember + ) + + if memberId <= 0 { + err = gerror.New("用户身份异常,请重新登录!") + return + } + + if err = dao.AdminMember.Ctx(ctx).Fields(dao.AdminMember.Columns().Mobile).Where(dao.AdminMember.Columns().Id, memberId).Scan(&models); err != nil { + return + } + + if models == nil { + err = gerror.New("用户信息不存在") + return + } + + if models.Mobile == "" { + err = gerror.New("未绑定手机号无需发送") + return + } + + err = service.SysSmsLog().SendCode(ctx, &sysin.SendCodeInp{ + Event: consts.SmsTemplateBind, + Mobile: models.Mobile, + }) + return +} + +// SendSms 发送短信 +func (c *cSms) SendSms(ctx context.Context, req *common.SendSmsReq) (res *common.SendSmsRes, err error) { + err = service.SysSmsLog().SendCode(ctx, &req.SendCodeInp) + return +} diff --git a/server/internal/controller/admin/common/upload.go b/server/internal/controller/admin/common/upload.go new file mode 100644 index 0000000..82f00aa --- /dev/null +++ b/server/internal/controller/admin/common/upload.go @@ -0,0 +1,66 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "hotgo/api/admin/common" + "hotgo/internal/library/storager" + "hotgo/internal/service" + "hotgo/utility/validate" +) + +var Upload = new(cUpload) + +type cUpload struct{} + +// UploadFile 上传文件 +func (c *cUpload) UploadFile(ctx context.Context, _ *common.UploadFileReq) (res common.UploadFileRes, err error) { + r := g.RequestFromCtx(ctx) + uploadType := r.Header.Get("uploadType") + if uploadType != "default" && !validate.InSlice(storager.KindSlice, uploadType) { + err = gerror.New("上传类型是无效的") + return + } + + file := r.GetUploadFile("file") + if file == nil { + err = gerror.New("没有找到上传的文件") + return + } + return service.CommonUpload().UploadFile(ctx, uploadType, file) +} + +// CheckMultipart 检查文件分片 +func (c *cUpload) CheckMultipart(ctx context.Context, req *common.CheckMultipartReq) (res *common.CheckMultipartRes, err error) { + data, err := service.CommonUpload().CheckMultipart(ctx, &req.CheckMultipartInp) + if err != nil { + return nil, err + } + res = new(common.CheckMultipartRes) + res.CheckMultipartModel = data + return +} + +// UploadPart 上传分片 +func (c *cUpload) UploadPart(ctx context.Context, req *common.UploadPartReq) (res *common.UploadPartRes, err error) { + data, err := service.CommonUpload().UploadPart(ctx, &req.UploadPartInp) + if err != nil { + return nil, err + } + res = new(common.UploadPartRes) + res.UploadPartModel = data + return +} + +// ImageTransferStorage 图片链接转存 +func (c *cUpload) ImageTransferStorage(ctx context.Context, req *common.ImageTransferStorageReq) (res *common.ImageTransferStorageRes, err error) { + res = new(common.ImageTransferStorageRes) + res.ImageTransferStorageModel, err = service.CommonUpload().ImageTransferStorage(ctx, &req.ImageTransferStorageInp) + return +} diff --git a/server/internal/controller/admin/common/wechat.go b/server/internal/controller/admin/common/wechat.go new file mode 100644 index 0000000..4e658d3 --- /dev/null +++ b/server/internal/controller/admin/common/wechat.go @@ -0,0 +1,28 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "context" + "hotgo/api/admin/common" + "hotgo/internal/service" +) + +var ( + Wechat = cWechat{} +) + +type cWechat struct{} + +func (c *cWechat) Authorize(ctx context.Context, req *common.WechatAuthorizeReq) (res *common.WechatAuthorizeRes, err error) { + _, err = service.CommonWechat().Authorize(ctx, &req.WechatAuthorizeInp) + return +} + +func (c *cWechat) AuthorizeCall(ctx context.Context, req *common.WechatAuthorizeCallReq) (res *common.WechatAuthorizeCallRes, err error) { + _, err = service.CommonWechat().AuthorizeCall(ctx, &req.WechatAuthorizeCallInp) + return +} diff --git a/server/internal/controller/admin/pay/refund.go b/server/internal/controller/admin/pay/refund.go new file mode 100644 index 0000000..1facbfe --- /dev/null +++ b/server/internal/controller/admin/pay/refund.go @@ -0,0 +1,39 @@ +// Package pay +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.5.3 +// @AutoGenerate Date 2023-04-15 15:59:58 +package pay + +import ( + "context" + "hotgo/api/admin/pay" + "hotgo/internal/service" +) + +var ( + Refund = cRefund{} +) + +type cRefund struct{} + +// List 查看交易退款列表 +func (c *cRefund) List(ctx context.Context, req *pay.RefundListReq) (res *pay.RefundListRes, err error) { + list, totalCount, err := service.PayRefund().List(ctx, &req.PayRefundListInp) + if err != nil { + return + } + + res = new(pay.RefundListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出交易退款列表 +func (c *cRefund) Export(ctx context.Context, req *pay.RefundExportReq) (res *pay.RefundExportRes, err error) { + err = service.PayRefund().Export(ctx, &req.PayRefundListInp) + return +} diff --git a/server/internal/controller/admin/sys/addons.go b/server/internal/controller/admin/sys/addons.go new file mode 100644 index 0000000..73ba447 --- /dev/null +++ b/server/internal/controller/admin/sys/addons.go @@ -0,0 +1,61 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/addons" + "hotgo/internal/service" +) + +var ( + Addons = cAddons{} +) + +type cAddons struct{} + +// List 查看列表 +func (c *cAddons) List(ctx context.Context, req *addons.ListReq) (res *addons.ListRes, err error) { + list, totalCount, err := service.SysAddons().List(ctx, &req.AddonsListInp) + if err != nil { + return + } + + res = new(addons.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Build 生成预览 +func (c *cAddons) Build(ctx context.Context, req *addons.BuildReq) (res *addons.BuildRes, err error) { + err = service.SysAddons().Build(ctx, &req.AddonsBuildInp) + return +} + +// Install 安装模块 +func (c *cAddons) Install(ctx context.Context, req *addons.InstallReq) (res *addons.InstallRes, err error) { + if err = service.SysAddons().Install(ctx, &req.AddonsInstallInp); err != nil { + return + } + return +} + +// Upgrade 更新模块 +func (c *cAddons) Upgrade(ctx context.Context, req *addons.UpgradeReq) (res *addons.UpgradeRes, err error) { + if err = service.SysAddons().Upgrade(ctx, &req.AddonsUpgradeInp); err != nil { + return + } + return +} + +// UnInstall 卸载模块 +func (c *cAddons) UnInstall(ctx context.Context, req *addons.UnInstallReq) (res *addons.UnInstallRes, err error) { + if err = service.SysAddons().UnInstall(ctx, &req.AddonsUnInstallInp); err != nil { + return + } + return +} diff --git a/server/internal/controller/admin/sys/attachment.go b/server/internal/controller/admin/sys/attachment.go new file mode 100644 index 0000000..9380887 --- /dev/null +++ b/server/internal/controller/admin/sys/attachment.go @@ -0,0 +1,55 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/attachment" + "hotgo/internal/service" +) + +var ( + Attachment = cAttachment{} +) + +type cAttachment struct{} + +// Delete 删除附件 +func (c *cAttachment) Delete(ctx context.Context, req *attachment.DeleteReq) (res *attachment.DeleteRes, err error) { + err = service.SysAttachment().Delete(ctx, &req.AttachmentDeleteInp) + return +} + +// View 获取指定附件信息 +func (c *cAttachment) View(ctx context.Context, req *attachment.ViewReq) (res *attachment.ViewRes, err error) { + data, err := service.SysAttachment().View(ctx, &req.AttachmentViewInp) + if err != nil { + return + } + + res = new(attachment.ViewRes) + res.AttachmentViewModel = data + return +} + +// List 查看附件列表 +func (c *cAttachment) List(ctx context.Context, req *attachment.ListReq) (res *attachment.ListRes, err error) { + list, totalCount, err := service.SysAttachment().List(ctx, &req.AttachmentListInp) + if err != nil { + return + } + + res = new(attachment.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// ClearKind 清空上传类型 +func (c *cAttachment) ClearKind(ctx context.Context, req *attachment.ClearKindReq) (res *attachment.ClearKindRes, err error) { + err = service.SysAttachment().ClearKind(ctx, &req.AttachmentClearKindInp) + return +} diff --git a/server/internal/controller/admin/sys/blacklist.go b/server/internal/controller/admin/sys/blacklist.go new file mode 100644 index 0000000..cac7c3d --- /dev/null +++ b/server/internal/controller/admin/sys/blacklist.go @@ -0,0 +1,61 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/blacklist" + "hotgo/internal/service" +) + +var ( + Blacklist = cBlacklist{} +) + +type cBlacklist struct{} + +// Delete 删除 +func (c *cBlacklist) Delete(ctx context.Context, req *blacklist.DeleteReq) (res *blacklist.DeleteRes, err error) { + err = service.SysBlacklist().Delete(ctx, &req.BlacklistDeleteInp) + return +} + +// Edit 更新 +func (c *cBlacklist) Edit(ctx context.Context, req *blacklist.EditReq) (res *blacklist.EditRes, err error) { + err = service.SysBlacklist().Edit(ctx, &req.BlacklistEditInp) + return +} + +// View 获取指定信息 +func (c *cBlacklist) View(ctx context.Context, req *blacklist.ViewReq) (res *blacklist.ViewRes, err error) { + data, err := service.SysBlacklist().View(ctx, &req.BlacklistViewInp) + if err != nil { + return + } + + res = new(blacklist.ViewRes) + res.BlacklistViewModel = data + return +} + +// List 查看列表 +func (c *cBlacklist) List(ctx context.Context, req *blacklist.ListReq) (res *blacklist.ListRes, err error) { + list, totalCount, err := service.SysBlacklist().List(ctx, &req.BlacklistListInp) + if err != nil { + return + } + + res = new(blacklist.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Status 更新黑名单状态 +func (c *cBlacklist) Status(ctx context.Context, req *blacklist.StatusReq) (res *blacklist.StatusRes, err error) { + err = service.SysBlacklist().Status(ctx, &req.BlacklistStatusInp) + return +} diff --git a/server/internal/controller/admin/sys/config.go b/server/internal/controller/admin/sys/config.go new file mode 100644 index 0000000..a831c80 --- /dev/null +++ b/server/internal/controller/admin/sys/config.go @@ -0,0 +1,53 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/config" + "hotgo/internal/consts" + "hotgo/internal/model/input/form" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var ( + Config = cConfig{} +) + +type cConfig struct{} + +// GetConfig 获取指定分组的配置 +func (c *cConfig) GetConfig(ctx context.Context, req *config.GetReq) (res *config.GetRes, err error) { + res = new(config.GetRes) + res.GetConfigModel, err = service.SysConfig().GetConfigByGroup(ctx, &req.GetConfigInp) + return +} + +// UpdateConfig 更新指定分组的配置 +func (c *cConfig) UpdateConfig(ctx context.Context, req *config.UpdateReq) (res *config.UpdateRes, err error) { + err = service.SysConfig().UpdateConfigByGroup(ctx, &req.UpdateConfigInp) + return +} + +// TypeSelect 数据类型选项 +func (c *cConfig) TypeSelect(_ context.Context, _ *config.TypeSelectReq) (res config.TypeSelectRes, err error) { + for _, v := range consts.ConfigTypes { + res = append(res, form.Select{ + Value: v, + Name: v, + Label: v, + }) + } + return +} + +// GetCash 获取提现的配置 +func (c *cConfig) GetCash(ctx context.Context, _ *config.GetCashReq) (res *config.GetCashRes, err error) { + res = new(config.GetCashRes) + res.GetConfigModel, err = service.SysConfig().GetConfigByGroup(ctx, &sysin.GetConfigInp{Group: "cash"}) + return +} diff --git a/server/internal/controller/admin/sys/cron.go b/server/internal/controller/admin/sys/cron.go new file mode 100644 index 0000000..e87e98b --- /dev/null +++ b/server/internal/controller/admin/sys/cron.go @@ -0,0 +1,97 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "hotgo/api/admin/cron" + "hotgo/api/servmsg" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var ( + Cron = cCron{} +) + +type cCron struct{} + +// Delete 删除 +func (c *cCron) Delete(ctx context.Context, req *cron.DeleteReq) (res *cron.DeleteRes, err error) { + err = service.TCPServer().CronDelete(ctx, &servmsg.CronDeleteReq{CronDeleteInp: &req.CronDeleteInp}) + return +} + +// Edit 更新 +func (c *cCron) Edit(ctx context.Context, req *cron.EditReq) (res *cron.EditRes, err error) { + err = service.TCPServer().CronEdit(ctx, &servmsg.CronEditReq{CronEditInp: &req.CronEditInp}) + return +} + +// MaxSort 最大排序 +func (c *cCron) MaxSort(ctx context.Context, req *cron.MaxSortReq) (res *cron.MaxSortRes, err error) { + res = new(cron.MaxSortRes) + res.CronMaxSortModel, err = service.SysCron().MaxSort(ctx, &req.CronMaxSortInp) + return +} + +// View 获取指定信息 +func (c *cCron) View(ctx context.Context, req *cron.ViewReq) (res *cron.ViewRes, err error) { + data, err := service.SysCron().View(ctx, &req.CronViewInp) + if err != nil { + return + } + + res = new(cron.ViewRes) + res.CronViewModel = data + return +} + +// List 查看列表 +func (c *cCron) List(ctx context.Context, req *cron.ListReq) (res *cron.ListRes, err error) { + list, totalCount, err := service.SysCron().List(ctx, &req.CronListInp) + if err != nil { + return + } + + res = new(cron.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Status 更新状态 +func (c *cCron) Status(ctx context.Context, req *cron.StatusReq) (res *cron.StatusRes, err error) { + if req.Id <= 0 { + return nil, gerror.New("定时任务ID不能为空") + } + + err = service.TCPServer().CronStatus(ctx, &servmsg.CronStatusReq{CronStatusInp: &req.CronStatusInp}) + return +} + +// OnlineExec 在线执行 +func (c *cCron) OnlineExec(ctx context.Context, req *cron.OnlineExecReq) (res *cron.OnlineExecRes, err error) { + if req.Id <= 0 { + return nil, gerror.New("定时任务ID不能为空") + } + + err = service.TCPServer().CronOnlineExec(ctx, &servmsg.CronOnlineExecReq{OnlineExecInp: &req.OnlineExecInp}) + return +} + +// DispatchLog 调度日志 +func (c *cCron) DispatchLog(ctx context.Context, req *cron.DispatchLogReq) (res *cron.DispatchLogRes, err error) { + if req.Id <= 0 { + return nil, gerror.New("定时任务ID不能为空") + } + + res = new(cron.DispatchLogRes) + res.DispatchLogModel = new(sysin.DispatchLogModel) + res.Log, err = service.TCPServer().DispatchLog(ctx, &servmsg.CronDispatchLogReq{DispatchLogInp: &req.DispatchLogInp}) + return +} diff --git a/server/internal/controller/admin/sys/cron_group.go b/server/internal/controller/admin/sys/cron_group.go new file mode 100644 index 0000000..8362c95 --- /dev/null +++ b/server/internal/controller/admin/sys/cron_group.go @@ -0,0 +1,80 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/cron" + "hotgo/internal/service" +) + +var ( + CronGroup = cCronGroup{} +) + +type cCronGroup struct{} + +// Delete 删除 +func (c *cCronGroup) Delete(ctx context.Context, req *cron.GroupDeleteReq) (res *cron.GroupDeleteRes, err error) { + err = service.SysCronGroup().Delete(ctx, &req.CronGroupDeleteInp) + return +} + +// Edit 更新 +func (c *cCronGroup) Edit(ctx context.Context, req *cron.GroupEditReq) (res *cron.GroupEditRes, err error) { + err = service.SysCronGroup().Edit(ctx, &req.CronGroupEditInp) + return +} + +// MaxSort 最大排序 +func (c *cCronGroup) MaxSort(ctx context.Context, req *cron.GroupMaxSortReq) (res *cron.GroupMaxSortRes, err error) { + res = new(cron.GroupMaxSortRes) + res.CronGroupMaxSortModel, err = service.SysCronGroup().MaxSort(ctx, &req.CronGroupMaxSortInp) + return +} + +// View 获取指定信息 +func (c *cCronGroup) View(ctx context.Context, req *cron.GroupViewReq) (res *cron.GroupViewRes, err error) { + data, err := service.SysCronGroup().View(ctx, &req.CronGroupViewInp) + if err != nil { + return + } + + res = new(cron.GroupViewRes) + res.CronGroupViewModel = data + return +} + +// List 查看列表 +func (c *cCronGroup) List(ctx context.Context, req *cron.GroupListReq) (res *cron.GroupListRes, err error) { + list, totalCount, err := service.SysCronGroup().List(ctx, &req.CronGroupListInp) + if err != nil { + return + } + + res = new(cron.GroupListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Status 更新状态 +func (c *cCronGroup) Status(ctx context.Context, req *cron.GroupStatusReq) (res *cron.GroupStatusRes, err error) { + err = service.SysCronGroup().Status(ctx, &req.CronGroupStatusInp) + return +} + +// Select 选项 +func (c *cCronGroup) Select(ctx context.Context, req *cron.GroupSelectReq) (res *cron.GroupSelectRes, err error) { + data, err := service.SysCronGroup().Select(ctx, &req.CronGroupSelectInp) + if err != nil { + return + } + + res = new(cron.GroupSelectRes) + res.CronGroupSelectModel = data + return +} diff --git a/server/internal/controller/admin/sys/curd_demo.go b/server/internal/controller/admin/sys/curd_demo.go new file mode 100644 index 0000000..9f73e8a --- /dev/null +++ b/server/internal/controller/admin/sys/curd_demo.go @@ -0,0 +1,91 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2025 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.18.6 +package sys + +import ( + "context" + "hotgo/api/admin/curddemo" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var ( + CurdDemo = cCurdDemo{} +) + +type cCurdDemo struct{} + +// List 查看CURD列表列表 +func (c *cCurdDemo) List(ctx context.Context, req *curddemo.ListReq) (res *curddemo.ListRes, err error) { + list, totalCount, err := service.SysCurdDemo().List(ctx, &req.CurdDemoListInp) + if err != nil { + return + } + + if list == nil { + list = []*sysin.CurdDemoListModel{} + } + + res = new(curddemo.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出CURD列表列表 +func (c *cCurdDemo) Export(ctx context.Context, req *curddemo.ExportReq) (res *curddemo.ExportRes, err error) { + err = service.SysCurdDemo().Export(ctx, &req.CurdDemoListInp) + return +} + +// Edit 更新CURD列表 +func (c *cCurdDemo) Edit(ctx context.Context, req *curddemo.EditReq) (res *curddemo.EditRes, err error) { + err = service.SysCurdDemo().Edit(ctx, &req.CurdDemoEditInp) + return +} + +// MaxSort 获取CURD列表最大排序 +func (c *cCurdDemo) MaxSort(ctx context.Context, req *curddemo.MaxSortReq) (res *curddemo.MaxSortRes, err error) { + data, err := service.SysCurdDemo().MaxSort(ctx, &req.CurdDemoMaxSortInp) + if err != nil { + return + } + + res = new(curddemo.MaxSortRes) + res.CurdDemoMaxSortModel = data + return +} + +// View 获取指定CURD列表信息 +func (c *cCurdDemo) View(ctx context.Context, req *curddemo.ViewReq) (res *curddemo.ViewRes, err error) { + data, err := service.SysCurdDemo().View(ctx, &req.CurdDemoViewInp) + if err != nil { + return + } + + res = new(curddemo.ViewRes) + res.CurdDemoViewModel = data + return +} + +// Delete 删除CURD列表 +func (c *cCurdDemo) Delete(ctx context.Context, req *curddemo.DeleteReq) (res *curddemo.DeleteRes, err error) { + err = service.SysCurdDemo().Delete(ctx, &req.CurdDemoDeleteInp) + return +} + +// Status 更新CURD列表状态 +func (c *cCurdDemo) Status(ctx context.Context, req *curddemo.StatusReq) (res *curddemo.StatusRes, err error) { + err = service.SysCurdDemo().Status(ctx, &req.CurdDemoStatusInp) + return +} + +// Switch 更新CURD列表开关状态 +func (c *cCurdDemo) Switch(ctx context.Context, req *curddemo.SwitchReq) (res *curddemo.SwitchRes, err error) { + err = service.SysCurdDemo().Switch(ctx, &req.CurdDemoSwitchInp) + return +} diff --git a/server/internal/controller/admin/sys/dict_data.go b/server/internal/controller/admin/sys/dict_data.go new file mode 100644 index 0000000..1e067da --- /dev/null +++ b/server/internal/controller/admin/sys/dict_data.go @@ -0,0 +1,68 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/dict" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var ( + DictData = cDictData{} +) + +type cDictData struct{} + +// Delete 删除 +func (c *cDictData) Delete(ctx context.Context, req *dict.DataDeleteReq) (res *dict.DataDeleteRes, err error) { + err = service.SysDictData().Delete(ctx, &req.DictDataDeleteInp) + return +} + +// Edit 更新 +func (c *cDictData) Edit(ctx context.Context, req *dict.DataEditReq) (res *dict.DataEditRes, err error) { + err = service.SysDictData().Edit(ctx, &req.DictDataEditInp) + return +} + +// List 查看列表 +func (c *cDictData) List(ctx context.Context, req *dict.DataListReq) (res *dict.DataListRes, err error) { + list, totalCount, err := service.SysDictData().List(ctx, &req.DictDataListInp) + if err != nil { + return + } + + res = new(dict.DataListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Select 指定选项 +func (c *cDictData) Select(ctx context.Context, req *dict.DataSelectReq) (res dict.DataSelectRes, err error) { + list, err := service.SysDictData().Select(ctx, &req.DataSelectInp) + if err != nil { + return + } + + res = dict.DataSelectRes(list) + return +} + +// Selects 多个选项 +func (c *cDictData) Selects(ctx context.Context, req *dict.DataSelectsReq) (res dict.DataSelectsRes, err error) { + res = make(dict.DataSelectsRes) + for _, v := range req.Types { + option, err := service.SysDictData().Select(ctx, &sysin.DataSelectInp{Type: v}) + if err != nil { + return nil, err + } + res[v] = option + } + return +} diff --git a/server/internal/controller/admin/sys/dict_type.go b/server/internal/controller/admin/sys/dict_type.go new file mode 100644 index 0000000..ededd0a --- /dev/null +++ b/server/internal/controller/admin/sys/dict_type.go @@ -0,0 +1,37 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/dict" + "hotgo/internal/service" +) + +var ( + DictType = cDictType{} +) + +type cDictType struct{} + +// Tree 树 +func (c *cDictType) Tree(ctx context.Context, _ *dict.TypeTreeReq) (res *dict.TypeTreeRes, err error) { + res = new(dict.TypeTreeRes) + res.List, err = service.SysDictType().Tree(ctx) + return +} + +// Delete 删除 +func (c *cDictType) Delete(ctx context.Context, req *dict.TypeDeleteReq) (res *dict.TypeDeleteRes, err error) { + err = service.SysDictType().Delete(ctx, &req.DictTypeDeleteInp) + return +} + +// Edit 更新 +func (c *cDictType) Edit(ctx context.Context, req *dict.TypeEditReq) (res *dict.TypeEditRes, err error) { + err = service.SysDictType().Edit(ctx, &req.DictTypeEditInp) + return +} diff --git a/server/internal/controller/admin/sys/ems_log.go b/server/internal/controller/admin/sys/ems_log.go new file mode 100644 index 0000000..0bea28e --- /dev/null +++ b/server/internal/controller/admin/sys/ems_log.go @@ -0,0 +1,61 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/emslog" + "hotgo/internal/service" +) + +var ( + EmsLog = cEmsLog{} +) + +type cEmsLog struct{} + +// Delete 删除 +func (c *cEmsLog) Delete(ctx context.Context, req *emslog.DeleteReq) (res *emslog.DeleteRes, err error) { + err = service.SysEmsLog().Delete(ctx, &req.EmsLogDeleteInp) + return +} + +// Edit 更新 +func (c *cEmsLog) Edit(ctx context.Context, req *emslog.EditReq) (res *emslog.EditRes, err error) { + err = service.SysEmsLog().Edit(ctx, &req.EmsLogEditInp) + return +} + +// View 获取指定信息 +func (c *cEmsLog) View(ctx context.Context, req *emslog.ViewReq) (res *emslog.ViewRes, err error) { + data, err := service.SysEmsLog().View(ctx, &req.EmsLogViewInp) + if err != nil { + return + } + + res = new(emslog.ViewRes) + res.EmsLogViewModel = data + return +} + +// List 查看列表 +func (c *cEmsLog) List(ctx context.Context, req *emslog.ListReq) (res *emslog.ListRes, err error) { + list, totalCount, err := service.SysEmsLog().List(ctx, &req.EmsLogListInp) + if err != nil { + return + } + + res = new(emslog.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Status 更新状态 +func (c *cEmsLog) Status(ctx context.Context, req *emslog.StatusReq) (res *emslog.StatusRes, err error) { + err = service.SysEmsLog().Status(ctx, &req.EmsLogStatusInp) + return +} diff --git a/server/internal/controller/admin/sys/gen_codes.go b/server/internal/controller/admin/sys/gen_codes.go new file mode 100644 index 0000000..44a4631 --- /dev/null +++ b/server/internal/controller/admin/sys/gen_codes.go @@ -0,0 +1,137 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/gencodes" + "hotgo/internal/service" +) + +var ( + GenCodes = cGenCodes{} +) + +type cGenCodes struct{} + +// Delete 删除 +func (c *cGenCodes) Delete(ctx context.Context, req *gencodes.DeleteReq) (res *gencodes.DeleteRes, err error) { + err = service.SysGenCodes().Delete(ctx, &req.GenCodesDeleteInp) + return +} + +// Edit 更新 +func (c *cGenCodes) Edit(ctx context.Context, req *gencodes.EditReq) (res *gencodes.EditRes, err error) { + data, err := service.SysGenCodes().Edit(ctx, &req.GenCodesEditInp) + if err != nil { + return + } + + res = new(gencodes.EditRes) + res.GenCodesEditModel = data + return +} + +// MaxSort 最大排序 +func (c *cGenCodes) MaxSort(ctx context.Context, req *gencodes.MaxSortReq) (res *gencodes.MaxSortRes, err error) { + res = new(gencodes.MaxSortRes) + res.GenCodesMaxSortModel, err = service.SysGenCodes().MaxSort(ctx, &req.GenCodesMaxSortInp) + return +} + +// View 获取指定信息 +func (c *cGenCodes) View(ctx context.Context, req *gencodes.ViewReq) (res *gencodes.ViewRes, err error) { + data, err := service.SysGenCodes().View(ctx, &req.GenCodesViewInp) + if err != nil { + return + } + + res = new(gencodes.ViewRes) + res.GenCodesViewModel = data + return +} + +// List 查看列表 +func (c *cGenCodes) List(ctx context.Context, req *gencodes.ListReq) (res *gencodes.ListRes, err error) { + list, totalCount, err := service.SysGenCodes().List(ctx, &req.GenCodesListInp) + if err != nil { + return + } + + res = new(gencodes.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Status 更新状态 +func (c *cGenCodes) Status(ctx context.Context, req *gencodes.StatusReq) (res *gencodes.StatusRes, err error) { + err = service.SysGenCodes().Status(ctx, &req.GenCodesStatusInp) + return +} + +// Selects 获取指定信息 +func (c *cGenCodes) Selects(ctx context.Context, req *gencodes.SelectsReq) (res *gencodes.SelectsRes, err error) { + data, err := service.SysGenCodes().Selects(ctx, &req.GenCodesSelectsInp) + if err != nil { + return + } + + res = new(gencodes.SelectsRes) + res.GenCodesSelectsModel = data + return +} + +// TableSelect 数据库表选项 +func (c *cGenCodes) TableSelect(ctx context.Context, req *gencodes.TableSelectReq) (res *gencodes.TableSelectRes, err error) { + data, err := service.SysGenCodes().TableSelect(ctx, &req.GenCodesTableSelectInp) + if err != nil { + return + } + + res = (*gencodes.TableSelectRes)(&data) + return +} + +// ColumnSelect 表字段选项 +func (c *cGenCodes) ColumnSelect(ctx context.Context, req *gencodes.ColumnSelectReq) (res *gencodes.ColumnSelectRes, err error) { + data, err := service.SysGenCodes().ColumnSelect(ctx, &req.GenCodesColumnSelectInp) + if err != nil { + return + } + + res = (*gencodes.ColumnSelectRes)(&data) + return +} + +// ColumnList 表字段列表 +func (c *cGenCodes) ColumnList(ctx context.Context, req *gencodes.ColumnListReq) (res *gencodes.ColumnListRes, err error) { + data, err := service.SysGenCodes().ColumnList(ctx, &req.GenCodesColumnListInp) + if err != nil { + return + } + + res = (*gencodes.ColumnListRes)(&data) + return +} + +// Preview 生成预览 +func (c *cGenCodes) Preview(ctx context.Context, req *gencodes.PreviewReq) (res *gencodes.PreviewRes, err error) { + data, err := service.SysGenCodes().Preview(ctx, &req.GenCodesPreviewInp) + if err != nil { + return + } + + res = new(gencodes.PreviewRes) + res.GenCodesPreviewModel = data + return +} + +// Build 生成预览 +func (c *cGenCodes) Build(ctx context.Context, req *gencodes.BuildReq) (res *gencodes.BuildRes, err error) { + err = service.SysGenCodes().Build(ctx, &req.GenCodesBuildInp) + return +} diff --git a/server/internal/controller/admin/sys/log.go b/server/internal/controller/admin/sys/log.go new file mode 100644 index 0000000..192a5a5 --- /dev/null +++ b/server/internal/controller/admin/sys/log.go @@ -0,0 +1,56 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "hotgo/api/admin/log" + "hotgo/internal/service" +) + +// Log 日志 +var Log = sLog{} + +type sLog struct{} + +// Clear 清空日志 +func (c *sLog) Clear(ctx context.Context, _ *log.ClearReq) (res *log.ClearRes, err error) { + err = gerror.New("暂时考虑到安全问题,请到数据库清空") + return +} + +// Export 导出 +func (c *sLog) Export(ctx context.Context, req *log.ExportReq) (res *log.ExportRes, err error) { + err = service.SysLog().Export(ctx, &req.LogListInp) + return +} + +// List 获取访问日志列表 +func (c *sLog) List(ctx context.Context, req *log.ListReq) (res *log.ListRes, err error) { + list, totalCount, err := service.SysLog().List(ctx, &req.LogListInp) + if err != nil { + return + } + + res = new(log.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// View 获取指定信息 +func (c *sLog) View(ctx context.Context, req *log.ViewReq) (res *log.ViewRes, err error) { + res = new(log.ViewRes) + res.LogViewModel, err = service.SysLog().View(ctx, &req.LogViewInp) + return +} + +// Delete 删除 +func (c *sLog) Delete(ctx context.Context, req *log.DeleteReq) (res *log.DeleteRes, err error) { + err = service.SysLog().Delete(ctx, &req.LogDeleteInp) + return +} diff --git a/server/internal/controller/admin/sys/login_log.go b/server/internal/controller/admin/sys/login_log.go new file mode 100644 index 0000000..6123c58 --- /dev/null +++ b/server/internal/controller/admin/sys/login_log.go @@ -0,0 +1,45 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.1.1 +// @AutoGenerate Date 2023-01-19 16:57:33 +package sys + +import ( + "context" + "hotgo/api/admin/loginlog" + "hotgo/internal/service" +) + +var ( + LoginLog = cLoginLog{} +) + +type cLoginLog struct{} + +// List 查看登录日志列表 +func (c *cLoginLog) List(ctx context.Context, req *loginlog.ListReq) (res *loginlog.ListRes, err error) { + list, totalCount, err := service.SysLoginLog().List(ctx, &req.LoginLogListInp) + if err != nil { + return + } + + res = new(loginlog.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出登录日志列表 +func (c *cLoginLog) Export(ctx context.Context, req *loginlog.ExportReq) (res *loginlog.ExportRes, err error) { + err = service.SysLoginLog().Export(ctx, &req.LoginLogListInp) + return +} + +// Delete 删除登录日志 +func (c *cLoginLog) Delete(ctx context.Context, req *loginlog.DeleteReq) (res *loginlog.DeleteRes, err error) { + err = service.SysLoginLog().Delete(ctx, &req.LoginLogDeleteInp) + return +} diff --git a/server/internal/controller/admin/sys/normal_tree_demo.go b/server/internal/controller/admin/sys/normal_tree_demo.go new file mode 100644 index 0000000..7348d87 --- /dev/null +++ b/server/internal/controller/admin/sys/normal_tree_demo.go @@ -0,0 +1,89 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.15.7 +package sys + +import ( + "context" + "hotgo/api/admin/normaltreedemo" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var ( + NormalTreeDemo = cNormalTreeDemo{} +) + +type cNormalTreeDemo struct{} + +// List 查看普通树表列表 +func (c *cNormalTreeDemo) List(ctx context.Context, req *normaltreedemo.ListReq) (res *normaltreedemo.ListRes, err error) { + list, totalCount, err := service.SysNormalTreeDemo().List(ctx, &req.NormalTreeDemoListInp) + if err != nil { + return + } + + if list == nil { + list = []*sysin.NormalTreeDemoListModel{} + } + + res = new(normaltreedemo.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Edit 更新普通树表 +func (c *cNormalTreeDemo) Edit(ctx context.Context, req *normaltreedemo.EditReq) (res *normaltreedemo.EditRes, err error) { + err = service.SysNormalTreeDemo().Edit(ctx, &req.NormalTreeDemoEditInp) + return +} + +// MaxSort 获取普通树表最大排序 +func (c *cNormalTreeDemo) MaxSort(ctx context.Context, req *normaltreedemo.MaxSortReq) (res *normaltreedemo.MaxSortRes, err error) { + data, err := service.SysNormalTreeDemo().MaxSort(ctx, &req.NormalTreeDemoMaxSortInp) + if err != nil { + return + } + + res = new(normaltreedemo.MaxSortRes) + res.NormalTreeDemoMaxSortModel = data + return +} + +// View 获取指定普通树表信息 +func (c *cNormalTreeDemo) View(ctx context.Context, req *normaltreedemo.ViewReq) (res *normaltreedemo.ViewRes, err error) { + data, err := service.SysNormalTreeDemo().View(ctx, &req.NormalTreeDemoViewInp) + if err != nil { + return + } + + res = new(normaltreedemo.ViewRes) + res.NormalTreeDemoViewModel = data + return +} + +// Delete 删除普通树表 +func (c *cNormalTreeDemo) Delete(ctx context.Context, req *normaltreedemo.DeleteReq) (res *normaltreedemo.DeleteRes, err error) { + err = service.SysNormalTreeDemo().Delete(ctx, &req.NormalTreeDemoDeleteInp) + return +} + +// TreeOption 获取普通树表关系树选项 +func (c *cNormalTreeDemo) TreeOption(ctx context.Context, req *normaltreedemo.TreeOptionReq) (res *normaltreedemo.TreeOptionRes, err error) { + data, err := service.SysNormalTreeDemo().TreeOption(ctx) + if err != nil { + return nil, err + } + + if len(data) > 0 { + res = (*normaltreedemo.TreeOptionRes)(&data) + } else { + temp := make(normaltreedemo.TreeOptionRes, 0) + res = &temp + } + return +} diff --git a/server/internal/controller/admin/sys/option_tree_demo.go b/server/internal/controller/admin/sys/option_tree_demo.go new file mode 100644 index 0000000..fa6cd22 --- /dev/null +++ b/server/internal/controller/admin/sys/option_tree_demo.go @@ -0,0 +1,89 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2025 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.17.8 +package sys + +import ( + "context" + "hotgo/api/admin/optiontreedemo" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var ( + OptionTreeDemo = cOptionTreeDemo{} +) + +type cOptionTreeDemo struct{} + +// List 查看选项树表列表 +func (c *cOptionTreeDemo) List(ctx context.Context, req *optiontreedemo.ListReq) (res *optiontreedemo.ListRes, err error) { + list, totalCount, err := service.SysOptionTreeDemo().List(ctx, &req.OptionTreeDemoListInp) + if err != nil { + return + } + + if list == nil { + list = []*sysin.OptionTreeDemoListModel{} + } + + res = new(optiontreedemo.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Edit 更新选项树表 +func (c *cOptionTreeDemo) Edit(ctx context.Context, req *optiontreedemo.EditReq) (res *optiontreedemo.EditRes, err error) { + err = service.SysOptionTreeDemo().Edit(ctx, &req.OptionTreeDemoEditInp) + return +} + +// MaxSort 获取选项树表最大排序 +func (c *cOptionTreeDemo) MaxSort(ctx context.Context, req *optiontreedemo.MaxSortReq) (res *optiontreedemo.MaxSortRes, err error) { + data, err := service.SysOptionTreeDemo().MaxSort(ctx, &req.OptionTreeDemoMaxSortInp) + if err != nil { + return + } + + res = new(optiontreedemo.MaxSortRes) + res.OptionTreeDemoMaxSortModel = data + return +} + +// View 获取指定选项树表信息 +func (c *cOptionTreeDemo) View(ctx context.Context, req *optiontreedemo.ViewReq) (res *optiontreedemo.ViewRes, err error) { + data, err := service.SysOptionTreeDemo().View(ctx, &req.OptionTreeDemoViewInp) + if err != nil { + return + } + + res = new(optiontreedemo.ViewRes) + res.OptionTreeDemoViewModel = data + return +} + +// Delete 删除选项树表 +func (c *cOptionTreeDemo) Delete(ctx context.Context, req *optiontreedemo.DeleteReq) (res *optiontreedemo.DeleteRes, err error) { + err = service.SysOptionTreeDemo().Delete(ctx, &req.OptionTreeDemoDeleteInp) + return +} + +// TreeOption 获取选项树表关系树选项 +func (c *cOptionTreeDemo) TreeOption(ctx context.Context, req *optiontreedemo.TreeOptionReq) (res *optiontreedemo.TreeOptionRes, err error) { + data, err := service.SysOptionTreeDemo().TreeOption(ctx) + if err != nil { + return nil, err + } + + if len(data) > 0 { + res = (*optiontreedemo.TreeOptionRes)(&data) + } else { + temp := make(optiontreedemo.TreeOptionRes, 0) + res = &temp + } + return +} diff --git a/server/internal/controller/admin/sys/provinces.go b/server/internal/controller/admin/sys/provinces.go new file mode 100644 index 0000000..318a423 --- /dev/null +++ b/server/internal/controller/admin/sys/provinces.go @@ -0,0 +1,129 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/provinces" + "hotgo/internal/library/location" + "hotgo/internal/service" +) + +var ( + Provinces = cProvinces{} +) + +type cProvinces struct{} + +// Tree 关系树选项列表 +func (c *cProvinces) Tree(ctx context.Context, _ *provinces.TreeReq) (res *provinces.TreeRes, err error) { + res = new(provinces.TreeRes) + res.List, err = service.SysProvinces().Tree(ctx) + return +} + +// Delete 删除 +func (c *cProvinces) Delete(ctx context.Context, req *provinces.DeleteReq) (res *provinces.DeleteRes, err error) { + err = service.SysProvinces().Delete(ctx, &req.ProvincesDeleteInp) + return +} + +// Edit 更新 +func (c *cProvinces) Edit(ctx context.Context, req *provinces.EditReq) (res *provinces.EditRes, err error) { + err = service.SysProvinces().Edit(ctx, &req.ProvincesEditInp) + return +} + +// MaxSort 最大排序 +func (c *cProvinces) MaxSort(ctx context.Context, req *provinces.MaxSortReq) (res *provinces.MaxSortRes, err error) { + data, err := service.SysProvinces().MaxSort(ctx, &req.ProvincesMaxSortInp) + if err != nil { + return + } + + res = new(provinces.MaxSortRes) + res.ProvincesMaxSortModel = data + return +} + +// View 获取指定信息 +func (c *cProvinces) View(ctx context.Context, req *provinces.ViewReq) (res *provinces.ViewRes, err error) { + data, err := service.SysProvinces().View(ctx, &req.ProvincesViewInp) + if err != nil { + return + } + + res = new(provinces.ViewRes) + res.ProvincesViewModel = data + return +} + +// List 查看列表 +func (c *cProvinces) List(ctx context.Context, req *provinces.ListReq) (res *provinces.ListRes, err error) { + list, totalCount, err := service.SysProvinces().List(ctx, &req.ProvincesListInp) + if err != nil { + return + } + + res = new(provinces.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Status 更新省市区状态 +func (c *cProvinces) Status(ctx context.Context, req *provinces.StatusReq) (res *provinces.StatusRes, err error) { + err = service.SysProvinces().Status(ctx, &req.ProvincesStatusInp) + return +} + +// ChildrenList 获取省市区下级列表 +func (c *cProvinces) ChildrenList(ctx context.Context, req *provinces.ChildrenListReq) (res *provinces.ChildrenListRes, err error) { + list, totalCount, err := service.SysProvinces().ChildrenList(ctx, &req.ProvincesChildrenListInp) + if err != nil { + return + } + + res = new(provinces.ChildrenListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// UniqueId 地区ID是否唯一 +func (c *cProvinces) UniqueId(ctx context.Context, req *provinces.UniqueIdReq) (res *provinces.UniqueIdRes, err error) { + data, err := service.SysProvinces().UniqueId(ctx, &req.ProvincesUniqueIdInp) + if err != nil { + return + } + + res = new(provinces.UniqueIdRes) + res.ProvincesUniqueIdModel = data + return +} + +// Select 省市区选项 +func (c *cProvinces) Select(ctx context.Context, req *provinces.SelectReq) (res *provinces.SelectRes, err error) { + data, err := service.SysProvinces().Select(ctx, &req.ProvincesSelectInp) + if err != nil { + return + } + + res = new(provinces.SelectRes) + res.ProvincesSelectModel = data + return +} + +// CityLabel 省市区选项 +func (c *cProvinces) CityLabel(ctx context.Context, req *provinces.CityLabelReq) (res *provinces.CityLabelRes, err error) { + cityLabel, err := location.ParseSimpleRegion(ctx, req.Id, req.Spilt) + if err != nil { + return + } + + res = (*provinces.CityLabelRes)(&cityLabel) + return +} diff --git a/server/internal/controller/admin/sys/serve_license.go b/server/internal/controller/admin/sys/serve_license.go new file mode 100644 index 0000000..5dd94d3 --- /dev/null +++ b/server/internal/controller/admin/sys/serve_license.go @@ -0,0 +1,74 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.7.6 +package sys + +import ( + "context" + "hotgo/api/admin/servelicense" + "hotgo/internal/service" +) + +var ( + ServeLicense = cServeLicense{} +) + +type cServeLicense struct{} + +// List 查看服务授权许可列表 +func (c *cServeLicense) List(ctx context.Context, req *servelicense.ListReq) (res *servelicense.ListRes, err error) { + list, totalCount, err := service.SysServeLicense().List(ctx, &req.ServeLicenseListInp) + if err != nil { + return + } + + res = new(servelicense.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出服务授权许可列表 +func (c *cServeLicense) Export(ctx context.Context, req *servelicense.ExportReq) (res *servelicense.ExportRes, err error) { + err = service.SysServeLicense().Export(ctx, &req.ServeLicenseListInp) + return +} + +// Edit 更新服务授权许可 +func (c *cServeLicense) Edit(ctx context.Context, req *servelicense.EditReq) (res *servelicense.EditRes, err error) { + err = service.SysServeLicense().Edit(ctx, &req.ServeLicenseEditInp) + return +} + +// View 获取指定服务授权许可信息 +func (c *cServeLicense) View(ctx context.Context, req *servelicense.ViewReq) (res *servelicense.ViewRes, err error) { + data, err := service.SysServeLicense().View(ctx, &req.ServeLicenseViewInp) + if err != nil { + return + } + + res = new(servelicense.ViewRes) + res.ServeLicenseViewModel = data + return +} + +// Delete 删除服务授权许可 +func (c *cServeLicense) Delete(ctx context.Context, req *servelicense.DeleteReq) (res *servelicense.DeleteRes, err error) { + err = service.SysServeLicense().Delete(ctx, &req.ServeLicenseDeleteInp) + return +} + +// Status 更新服务授权许可状态 +func (c *cServeLicense) Status(ctx context.Context, req *servelicense.StatusReq) (res *servelicense.StatusRes, err error) { + err = service.SysServeLicense().Status(ctx, &req.ServeLicenseStatusInp) + return +} + +// AssignRouter 分配服务授权许可路由 +func (c *cServeLicense) AssignRouter(ctx context.Context, req *servelicense.AssignRouterReq) (res *servelicense.AssignRouterRes, err error) { + err = service.SysServeLicense().AssignRouter(ctx, &req.ServeLicenseAssignRouterInp) + return +} diff --git a/server/internal/controller/admin/sys/serve_log.go b/server/internal/controller/admin/sys/serve_log.go new file mode 100644 index 0000000..b3ca4cf --- /dev/null +++ b/server/internal/controller/admin/sys/serve_log.go @@ -0,0 +1,55 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/servelog" + "hotgo/internal/service" +) + +var ( + ServeLog = cServeLog{} +) + +type cServeLog struct{} + +// List 查看服务日志列表 +func (c *cServeLog) List(ctx context.Context, req *servelog.ListReq) (res *servelog.ListRes, err error) { + list, totalCount, err := service.SysServeLog().List(ctx, &req.ServeLogListInp) + if err != nil { + return + } + + res = new(servelog.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Export 导出服务日志列表 +func (c *cServeLog) Export(ctx context.Context, req *servelog.ExportReq) (res *servelog.ExportRes, err error) { + err = service.SysServeLog().Export(ctx, &req.ServeLogListInp) + return +} + +// View 获取指定服务日志信息 +func (c *cServeLog) View(ctx context.Context, req *servelog.ViewReq) (res *servelog.ViewRes, err error) { + data, err := service.SysServeLog().View(ctx, &req.ServeLogViewInp) + if err != nil { + return + } + + res = new(servelog.ViewRes) + res.ServeLogViewModel = data + return +} + +// Delete 删除服务日志 +func (c *cServeLog) Delete(ctx context.Context, req *servelog.DeleteReq) (res *servelog.DeleteRes, err error) { + err = service.SysServeLog().Delete(ctx, &req.ServeLogDeleteInp) + return +} diff --git a/server/internal/controller/admin/sys/sms_log.go b/server/internal/controller/admin/sys/sms_log.go new file mode 100644 index 0000000..b718efb --- /dev/null +++ b/server/internal/controller/admin/sys/sms_log.go @@ -0,0 +1,49 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package sys + +import ( + "context" + "hotgo/api/admin/smslog" + "hotgo/internal/service" +) + +var ( + SmsLog = cSmsLog{} +) + +type cSmsLog struct{} + +// Delete 删除 +func (c *cSmsLog) Delete(ctx context.Context, req *smslog.DeleteReq) (res *smslog.DeleteRes, err error) { + err = service.SysSmsLog().Delete(ctx, &req.SmsLogDeleteInp) + return +} + +// View 获取指定信息 +func (c *cSmsLog) View(ctx context.Context, req *smslog.ViewReq) (res *smslog.ViewRes, err error) { + data, err := service.SysSmsLog().View(ctx, &req.SmsLogViewInp) + if err != nil { + return + } + + res = new(smslog.ViewRes) + res.SmsLogViewModel = data + return +} + +// List 查看列表 +func (c *cSmsLog) List(ctx context.Context, req *smslog.ListReq) (res *smslog.ListRes, err error) { + list, totalCount, err := service.SysSmsLog().List(ctx, &req.SmsLogListInp) + if err != nil { + return + } + + res = new(smslog.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} diff --git a/server/internal/controller/admin/sys/test_category.go b/server/internal/controller/admin/sys/test_category.go new file mode 100644 index 0000000..72213f3 --- /dev/null +++ b/server/internal/controller/admin/sys/test_category.go @@ -0,0 +1,79 @@ +// Package sys +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2024 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +// @AutoGenerate Version 2.15.7 +package sys + +import ( + "context" + "hotgo/api/admin/testcategory" + "hotgo/internal/model/input/sysin" + "hotgo/internal/service" +) + +var ( + TestCategory = cTestCategory{} +) + +type cTestCategory struct{} + +// List 查看测试分类列表 +func (c *cTestCategory) List(ctx context.Context, req *testcategory.ListReq) (res *testcategory.ListRes, err error) { + list, totalCount, err := service.SysTestCategory().List(ctx, &req.TestCategoryListInp) + if err != nil { + return + } + + if list == nil { + list = []*sysin.TestCategoryListModel{} + } + + res = new(testcategory.ListRes) + res.List = list + res.PageRes.Pack(req, totalCount) + return +} + +// Edit 更新测试分类 +func (c *cTestCategory) Edit(ctx context.Context, req *testcategory.EditReq) (res *testcategory.EditRes, err error) { + err = service.SysTestCategory().Edit(ctx, &req.TestCategoryEditInp) + return +} + +// MaxSort 获取测试分类最大排序 +func (c *cTestCategory) MaxSort(ctx context.Context, req *testcategory.MaxSortReq) (res *testcategory.MaxSortRes, err error) { + data, err := service.SysTestCategory().MaxSort(ctx, &req.TestCategoryMaxSortInp) + if err != nil { + return + } + + res = new(testcategory.MaxSortRes) + res.TestCategoryMaxSortModel = data + return +} + +// View 获取指定测试分类信息 +func (c *cTestCategory) View(ctx context.Context, req *testcategory.ViewReq) (res *testcategory.ViewRes, err error) { + data, err := service.SysTestCategory().View(ctx, &req.TestCategoryViewInp) + if err != nil { + return + } + + res = new(testcategory.ViewRes) + res.TestCategoryViewModel = data + return +} + +// Delete 删除测试分类 +func (c *cTestCategory) Delete(ctx context.Context, req *testcategory.DeleteReq) (res *testcategory.DeleteRes, err error) { + err = service.SysTestCategory().Delete(ctx, &req.TestCategoryDeleteInp) + return +} + +// Status 更新测试分类状态 +func (c *cTestCategory) Status(ctx context.Context, req *testcategory.StatusReq) (res *testcategory.StatusRes, err error) { + err = service.SysTestCategory().Status(ctx, &req.TestCategoryStatusInp) + return +} diff --git a/server/internal/controller/api/member/member.go b/server/internal/controller/api/member/member.go new file mode 100644 index 0000000..6fe3c71 --- /dev/null +++ b/server/internal/controller/api/member/member.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package member diff --git a/server/internal/controller/api/member/member_new.go b/server/internal/controller/api/member/member_new.go new file mode 100644 index 0000000..dfb4e71 --- /dev/null +++ b/server/internal/controller/api/member/member_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package member + +import ( + "hotgo/api/api/member" +) + +type ControllerV1 struct{} + +func NewV1() member.IMemberV1 { + return &ControllerV1{} +} diff --git a/server/internal/controller/api/member/member_v1_get_id_by_code.go b/server/internal/controller/api/member/member_v1_get_id_by_code.go new file mode 100644 index 0000000..42010d3 --- /dev/null +++ b/server/internal/controller/api/member/member_v1_get_id_by_code.go @@ -0,0 +1,14 @@ +package member + +import ( + "context" + + v1 "hotgo/api/api/member/v1" + + "github.com/gogf/gf/v2/frame/g" +) + +func (c *ControllerV1) GetIdByCode(ctx context.Context, req *v1.GetIdByCodeReq) (res *v1.GetIdByCodeRes, err error) { + g.RequestFromCtx(ctx).Response.Writeln("Hello World api member!") + return +} diff --git a/server/internal/controller/api/pay/pay.go b/server/internal/controller/api/pay/pay.go new file mode 100644 index 0000000..cc269a0 --- /dev/null +++ b/server/internal/controller/api/pay/pay.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package pay diff --git a/server/internal/controller/api/pay/pay_new.go b/server/internal/controller/api/pay/pay_new.go new file mode 100644 index 0000000..53eb435 --- /dev/null +++ b/server/internal/controller/api/pay/pay_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package pay + +import ( + "hotgo/api/api/pay" +) + +type ControllerV1 struct{} + +func NewV1() pay.IPayV1 { + return &ControllerV1{} +} diff --git a/server/internal/controller/api/pay/pay_v1_notify_ali_pay.go b/server/internal/controller/api/pay/pay_v1_notify_ali_pay.go new file mode 100644 index 0000000..5e22899 --- /dev/null +++ b/server/internal/controller/api/pay/pay_v1_notify_ali_pay.go @@ -0,0 +1,22 @@ +package pay + +import ( + "context" + + v1 "hotgo/api/api/pay/v1" + "hotgo/internal/consts" + "hotgo/internal/library/response" + "hotgo/internal/model/input/payin" + "hotgo/internal/service" + + "github.com/gogf/gf/v2/frame/g" +) + +func (c *ControllerV1) NotifyAliPay(ctx context.Context, req *v1.NotifyAliPayReq) (res *v1.NotifyAliPayRes, err error) { + if _, err = service.Pay().Notify(ctx, &payin.PayNotifyInp{PayType: consts.PayTypeAliPay}); err != nil { + return nil, err + } + + response.RText(g.RequestFromCtx(ctx), "success") + return +} diff --git a/server/internal/controller/api/pay/pay_v1_notify_qq_pay.go b/server/internal/controller/api/pay/pay_v1_notify_qq_pay.go new file mode 100644 index 0000000..6c93b03 --- /dev/null +++ b/server/internal/controller/api/pay/pay_v1_notify_qq_pay.go @@ -0,0 +1,26 @@ +package pay + +import ( + "context" + + v1 "hotgo/api/api/pay/v1" + "hotgo/internal/consts" + "hotgo/internal/model/input/payin" + "hotgo/internal/service" + + "github.com/gogf/gf/v2/frame/g" +) + +func (c *ControllerV1) NotifyQQPay(ctx context.Context, req *v1.NotifyQQPayReq) (res *v1.NotifyQQPayRes, err error) { + if _, err = service.Pay().Notify(ctx, &payin.PayNotifyInp{PayType: consts.PayTypeQQPay}); err != nil { + return + } + + r := g.RequestFromCtx(ctx) + r.Response.ClearBuffer() + r.Response.Write(``) + r.Response.WriteXml(g.Map{ + "return_code": "SUCCESS", + }) + return +} diff --git a/server/internal/controller/api/pay/pay_v1_notify_wx_pay.go b/server/internal/controller/api/pay/pay_v1_notify_wx_pay.go new file mode 100644 index 0000000..e871910 --- /dev/null +++ b/server/internal/controller/api/pay/pay_v1_notify_wx_pay.go @@ -0,0 +1,22 @@ +package pay + +import ( + "context" + + v1 "hotgo/api/api/pay/v1" + "hotgo/internal/consts" + "hotgo/internal/library/response" + "hotgo/internal/model/input/payin" + "hotgo/internal/service" + + "github.com/gogf/gf/v2/frame/g" +) + +func (c *ControllerV1) NotifyWxPay(ctx context.Context, req *v1.NotifyWxPayReq) (res *v1.NotifyWxPayRes, err error) { + if _, err = service.Pay().Notify(ctx, &payin.PayNotifyInp{PayType: consts.PayTypeWxPay}); err != nil { + return + } + + response.CustomJson(g.RequestFromCtx(ctx), `{"code": "SUCCESS","message": "收单成功"}`) + return +} diff --git a/server/internal/controller/home/base/site.go b/server/internal/controller/home/base/site.go new file mode 100644 index 0000000..b65ad40 --- /dev/null +++ b/server/internal/controller/home/base/site.go @@ -0,0 +1,38 @@ +// Package base +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package base + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "hotgo/api/home/base" + "hotgo/internal/consts" + "hotgo/internal/model" + "hotgo/internal/service" + "hotgo/utility/simple" +) + +// Site 基础 +var Site = cSite{} + +type cSite struct{} + +func (a *cSite) Index(ctx context.Context, _ *base.SiteIndexReq) (res *base.SiteIndexRes, err error) { + service.View().Render(ctx, model.View{Data: g.Map{ + "name": simple.AppName(ctx), + "version": consts.VersionApp, + }}) + + // err = gerror.New("这是一个测试错误") + // return + + // err = gerror.NewCode(gcode.New(10000, "这是一个测试自定义错误码错误", nil)) + // return + + // service.View().Error(ctx, gerror.New("这是一个允许被自定义格式的错误,默认和通用错误格式一致,你可以修改它")) + // return + return +} diff --git a/server/internal/controller/websocket/handler/admin/monitor.go b/server/internal/controller/websocket/handler/admin/monitor.go new file mode 100644 index 0000000..f10ed93 --- /dev/null +++ b/server/internal/controller/websocket/handler/admin/monitor.go @@ -0,0 +1,198 @@ +// Package admin +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package admin + +import ( + "fmt" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" + "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/disk" + "github.com/shirou/gopsutil/v3/host" + "github.com/shirou/gopsutil/v3/mem" + "github.com/shirou/gopsutil/v3/process" + "hotgo/internal/consts" + "hotgo/internal/model" + "hotgo/internal/service" + "hotgo/internal/websocket" + "hotgo/utility/file" + "hotgo/utility/format" + "hotgo/utility/simple" + "os" + "runtime" + "time" +) + +var ( + Monitor = cMonitor{} +) + +type cMonitor struct{} + +type MonitorHeadExtra struct { + Data interface{} `json:"data"` + Data1 string `json:"data1,omitempty"` +} +type MonitorHead struct { + Title string `json:"title"` + Data string `json:"data"` + BottomTitle string `json:"bottomTitle"` + TotalSum string `json:"totalSum"` + IconClass string `json:"iconClass"` + Extra MonitorHeadExtra `json:"extra"` +} + +// RunInfo 运行信息 +func (c *cMonitor) RunInfo(client *websocket.Client, req *websocket.WRequest) { + var ( + meta = service.AdminMonitor().GetMeta(client.Context()) + mHost, _ = host.Info() + pwd, _ = os.Getwd() + gm runtime.MemStats + ) + + runtime.ReadMemStats(&gm) + + data := g.Map{ + // 服务器信息 + "hostname": mHost.Hostname, + "os": mHost.OS, + "arch": mHost.KernelArch, + "intranet_ip": meta.IntranetIP, + "public_ip": meta.PublicIP, + + // 运行信息 + "version": runtime.Version(), // GO 版本 + "hgVersion": consts.VersionApp, // HG 版本 + "startTime": gtime.New(meta.STartTime), + "runTime": gtime.Now().Timestamp() - meta.STartTime, + "rootPath": runtime.GOROOT(), + "pwd": pwd, + "goroutine": runtime.NumGoroutine(), + "goMem": format.FileSize(int64(gm.Sys)), + "goSize": file.DirSize(pwd), + } + + if simple.IsDemo(client.Context()) { + data["rootPath"] = consts.DemoTips + data["pwd"] = consts.DemoTips + data["intranet_ip"] = consts.DemoTips + data["public_ip"] = consts.DemoTips + } + + websocket.SendSuccess(client, req.Event, data) +} + +// Trends 实时数据 +func (c *cMonitor) Trends(client *websocket.Client, req *websocket.WRequest) { + type NetC struct { + Time *gtime.Time `json:"time"` + BytesSent string `json:"bytesSent"` // number of bytes sent + BytesRecv string `json:"bytesRecv"` // number of bytes received + Down float64 `json:"down"` + UP float64 `json:"up"` + } + + var ( + mCpu, cpuErr = cpu.Info() + mCpuUsed float64 + mMem, memErr = mem.VirtualMemory() + mMemUsed float64 + mDisk, diskErr = disk.Usage("/") + mProcess, processErr = process.Pids() + mLoadAvg = new(model.LoadAvgStats) + monitorHeads []MonitorHead + nets []NetC + meta = service.AdminMonitor().GetMeta(client.Context()) + ) + + if cpuErr != nil { + g.Log().Infof(client.Context(), "read CPU info fail:%+v", cpuErr) + mCpu = []cpu.InfoStat{{VendorID: "", ModelName: ""}} + } + + if memErr != nil { + g.Log().Infof(client.Context(), "read mem info fail:%+v", memErr) + mMem = new(mem.VirtualMemoryStat) + } + + if diskErr != nil { + g.Log().Infof(client.Context(), "read disk info fail:%+v", diskErr) + mDisk = new(disk.UsageStat) + } + + if processErr != nil { + g.Log().Infof(client.Context(), "read process.Pids fail:%+v", processErr) + } + + // cpu使用率 + cu, err := cpu.Percent(time.Second, false) + if err == nil { + mCpuUsed = gconv.Float64(fmt.Sprintf("%.2f", cu[0])) + } + + // 内存使用率 + mMemUsed = gconv.Float64(fmt.Sprintf("%.2f", mMem.UsedPercent)) + + // 负载 + if len(meta.LoadAvg) > 0 { + mLoadAvg = meta.LoadAvg[len(meta.LoadAvg)-1] + } + + monitorHeads = append(monitorHeads, MonitorHead{ + Title: "CPU", + Data: "使用率 " + format.Round2String(mCpuUsed) + "%", + BottomTitle: "CPU数量", + TotalSum: gconv.String(runtime.NumCPU()) + "核心", + IconClass: "HardwareChip", + Extra: MonitorHeadExtra{ + Data: mCpu[0].VendorID, + Data1: mCpu[0].ModelName, + }}, + MonitorHead{ + Title: "内存", + Data: "使用率 " + format.Round2String(mMemUsed) + "%", + BottomTitle: "总内存", + TotalSum: format.FileSize(int64(mMem.Total)), + IconClass: "AppsSharp", + Extra: MonitorHeadExtra{ + Data: format.FileSize(int64(mMem.Used)), + Data1: format.FileSize(int64(mMem.Total - mMem.Used)), + }}, + MonitorHead{ + Title: "磁盘", + Data: "已用 " + format.FileSize(int64(mDisk.Used)), + BottomTitle: "总容量", + TotalSum: format.FileSize(int64(mDisk.Total)), + IconClass: "PieChart", + Extra: MonitorHeadExtra{ + Data: format.Round2String(mDisk.UsedPercent), + }}, + MonitorHead{ + Title: "负载", + Data: format.Round2String(mLoadAvg.Ratio) + "%", + BottomTitle: "总进程数", + TotalSum: gconv.String(len(mProcess)) + "个", + IconClass: "Analytics", + }) + + for _, v := range meta.NetIO { + nets = append(nets, NetC{ + Time: v.Time, + BytesSent: format.FileSize(int64(v.BytesSent)), // 转换为最大整数单位 + BytesRecv: format.FileSize(int64(v.BytesRecv)), + Down: format.Round2Float64(v.Down / 1024), // 转换为kb + UP: format.Round2Float64(v.UP / 1024), + }) + } + + websocket.SendSuccess(client, req.Event, g.Map{ + "head": monitorHeads, + "load": meta.LoadAvg, + "net": nets, + }) +} diff --git a/server/internal/controller/websocket/handler/common/site.go b/server/internal/controller/websocket/handler/common/site.go new file mode 100644 index 0000000..400165e --- /dev/null +++ b/server/internal/controller/websocket/handler/common/site.go @@ -0,0 +1,39 @@ +// Package common +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package common + +import ( + "github.com/gogf/gf/v2/util/gconv" + "hotgo/internal/websocket" +) + +var ( + Site = cSite{} +) + +type cSite struct{} + +func (c *cSite) Join(client *websocket.Client, req *websocket.WRequest) { + name := gconv.String(req.Data["id"]) + + if !client.Tags.Contains(name) { + client.Tags.Append(name) + } + + websocket.SendSuccess(client, req.Event, client.Tags.Slice()) +} + +func (c *cSite) Quit(client *websocket.Client, req *websocket.WRequest) { + name := gconv.String(req.Data["id"]) + if client.Tags.Contains(name) { + client.Tags.RemoveValue(name) + } + websocket.SendSuccess(client, req.Event, client.Tags.Slice()) +} + +func (c *cSite) Ping(client *websocket.Client, req *websocket.WRequest) { + websocket.SendSuccess(client, req.Event) +} diff --git a/server/internal/controller/websocket/send.go b/server/internal/controller/websocket/send.go new file mode 100644 index 0000000..03cec08 --- /dev/null +++ b/server/internal/controller/websocket/send.go @@ -0,0 +1,29 @@ +// Package websocket +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package websocket + +import ( + "context" + "hotgo/api/websocket/base" + "hotgo/internal/websocket" + "hotgo/utility/simple" +) + +// Send 通过http发送ws消息 +var Send = send{} + +type send struct{} + +// SendToTag 发送标签消息 +func (c *send) SendToTag(ctx context.Context, req *base.SendToTagReq) (res *base.SendToTagRes, err error) { + simple.SafeGo(ctx, func(ctx context.Context) { + websocket.SendToTag(req.Tag, &websocket.WResponse{ + Event: req.Response.Event, + Data: req.Response, + }) + }) + return +} diff --git a/server/internal/crons/close_order.go b/server/internal/crons/close_order.go new file mode 100644 index 0000000..8dfebe6 --- /dev/null +++ b/server/internal/crons/close_order.go @@ -0,0 +1,45 @@ +// Package crons +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package crons + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "hotgo/internal/consts" + "hotgo/internal/dao" + "hotgo/internal/library/cron" + "hotgo/internal/service" +) + +func init() { + cron.Register(CloseOrder) +} + +// CloseOrder 取消过期订单 +var CloseOrder = &cCloseOrder{name: "close_order"} + +type cCloseOrder struct { + name string +} + +func (c *cCloseOrder) GetName() string { + return c.name +} + +// Execute 执行任务 +func (c *cCloseOrder) Execute(ctx context.Context, parser *cron.Parser) (err error) { + _, err = service.AdminOrder().Model(ctx). + Where(dao.AdminOrder.Columns().Status, consts.OrderStatusNotPay). + WhereLTE(dao.AdminOrder.Columns().CreatedAt, gtime.Now().AddDate(0, 0, -1)). + Data(g.Map{ + dao.AdminOrder.Columns().Status: consts.OrderStatusClose, + }).Update() + if err != nil { + parser.Logger.Warning(ctx, "cron CloseOrder Execute err:%+v", err) + } + return +} diff --git a/server/internal/crons/test.go b/server/internal/crons/test.go new file mode 100644 index 0000000..c207c23 --- /dev/null +++ b/server/internal/crons/test.go @@ -0,0 +1,33 @@ +// Package crons +// @Link https://github.com/bufanyun/hotgo +// @Copyright Copyright (c) 2023 HotGo CLI +// @Author Ms <133814250@qq.com> +// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE +package crons + +import ( + "context" + "hotgo/internal/library/cron" + "time" +) + +func init() { + cron.Register(Test) +} + +// Test 测试任务(无参数) +var Test = &cTest{name: "test"} + +type cTest struct { + name string +} + +func (c *cTest) GetName() string { + return c.name +} + +// Execute 执行任务 +func (c *cTest) Execute(ctx context.Context, parser *cron.Parser) (err error) { + parser.Logger.Infof(ctx, "cron test Execute:%v", time.Now()) + return +}