Compare commits

..
Author SHA1 Message Date
copilot-swe-agent[bot]andpixelmaxQm 7e272a9f8c feat: replace process.env manual loading with Vite's native loadEnv
Co-authored-by: pixelmaxQm <165128580+pixelmaxQm@users.noreply.github.com>
2026-03-03 05:59:02 +00:00
copilot-swe-agent[bot] 7602673ed3 Initial plan 2026-03-03 05:56:11 +00:00
piexlMax(奇淼 556b4431a2 fix: 修复获取x-token的方式,确保正确获取用户token 2026-02-10 16:15:40 +08:00
piexlMax(奇淼 9fea067931 feat: 更新富文本编辑器样式和结构,增强可读性 2026-02-10 11:44:10 +08:00
piexlMax(奇淼 fa9957c43c feat: 调整自动化插件的注册逻辑 2026-02-05 14:08:13 +08:00
piexlMax(奇淼 00224efd24 fix: 字典搜索bug 2026-02-05 13:50:33 +08:00
piexlMax(奇淼 506c9ea7a6 feat: 自动生成插件不再添加到注册功能 2026-02-05 13:44:26 +08:00
piexlMax(奇淼 05872354b8 feat: 补充丢失的自动迁移结构 2026-02-04 13:49:24 +08:00
piexlMax(奇淼 b71cc443c0 refactor: 调整ai工具rules 2026-02-03 10:18:34 +08:00
piexlMax(奇淼 1317e9504e feat: 增加技能配置界面的填写指引和模板功能 2026-02-02 18:06:19 +08:00
piexlMax(奇淼 670aff79cc feat: 增加技能参考和模板的创建、获取及保存功能 2026-02-02 18:06:11 +08:00
pixelmaxQM 52cd5e72ab feat: 更新版本号至v2.8.9 2026-02-01 23:42:20 +08:00
pixelmaxQM 68d6d3660b feat: 更新版本号至2.8.9 2026-02-01 22:26:03 +08:00
876017115c feat:发布2.8.9版本 (#2175)
* feat: ai相关调用调整

* feat: ai请求模式变更

* feat: ai自动化完善

* feat: 添加环境变量支持,条件渲染开发环境特定元素

* feat: 2.5版本插件,不再冗余进主项目,可以做到完全自动安装。

* feat: 添加插件管理功能,包括获取插件列表和删除插件的API接口

* feat: 同步测试插件的id调整

* feat: 增加插件相关初始化api

* feat: 增加登录日志

* feat: 增加签发token功能

* feat: 更安全的目录清理功能,确保仅在无Go文件时删除目录

* feat: 增加skills定义能力

* feat: 优化技能管理界面,增强用户体验和视觉效果

* feat: 更新授权链接,确保用户获取最新的授权信息

* feat: 修改技能定义器名称为“Skills管理”,并重命名文件为sys_skills.go

* feat: 增加全局约束的获取和保存功能,更新相关API和前端实现

* feat: 增加skills全局约束管理

* feat: 添加 vite-check-multiple-dom 插件,支持路由多根检测 (#2173)

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: Azir-11 <2075125282@qq.com>
Co-authored-by: 青菜白玉汤 <79054161+Azir-11@users.noreply.github.com>
2026-01-30 14:33:57 +08:00
piexlMax(奇淼 755373468c feat: 为mcp增加字段示例 2026-01-16 16:19:22 +08:00
piexlMax(奇淼 d2e64e618e fix: 重新实现组件缓存处理逻辑 2026-01-12 15:27:41 +08:00
piexlMax(奇淼 fd2a6f45fd fixed: 增加错误设置首页的补救措施 2026-01-12 15:11:59 +08:00
2242f5d6e1 public: 发布v2.8.8 (#2167)
* refactor: 移除冗余的工具名称和描述,简化代码生成器的文档

* Add Content-Type to S3 upload input

Add Content-Type to S3 upload input

* style: 优化仪表盘组件样式,调整各个子组件的布局和样式,提升视觉效果

* fix: 更新插件链接

* 优化角色配置-首页配置相关内容

* feat: 默认首页只允许选择已选中的菜单

* feat: 更新样式和优化组件,调整背景色及文本颜色

* feat: 清理无用的右侧边线

* feat: 增加了导入导出模板的自定义sql能力,方便灵活化扩展导入导出

* feat: 优化日志输出,增加插件字典定义

* feat: 增加插件字典定义前端相关

* feat: 增加插件自定义字典方法

* feat: 增加文件名和路径合法性检查

* feat: 修复暗黑模式和亮色模式logo路径定义

* feat: 移除未使用的defineEmits导入

* feat: 更新授权链接至新地址

* feat: 移除菜单组件背景色

* feat: 更新导出和导入SQL语句的示例占位符

* feat: 错误日志必须有数据库链接才会存储

* feat: 移除仪表板中公告卡片的高度限制

* feat: 添加插件列表接口,更新插件表格组件,移除不必要的注释

* feat: 更新版本号至v2.8.8,调整插件表格组件的请求参数

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: Yexk_M <yexk@yexk.cn>
Co-authored-by: Azir-11 <2075125282@qq.com>
2026-01-11 14:41:19 +08:00
PiexlMax(奇淼 567a8eb9bb fixed: 文件句柄泄露问题
文件句柄泄露问题
2026-01-11 14:34:21 +08:00
PiexlMax(奇淼 2ebeec8765 fixed: MD5 碰撞可能导致不同内容被误判为同一文件
MD5 碰撞可能导致不同内容被误判为同一文件
2026-01-11 14:33:47 +08:00
wike2019 70ee13e10c 文件句柄泄露问题 2026-01-11 13:13:59 +08:00
wike2019 ed65e31cd8 MD5 碰撞可能导致不同内容被误判为同一文件 2026-01-11 13:11:38 +08:00
PiexlMax(奇淼 f693f29326 feat: 优化unzip逻辑
io.Copy 后立即调用 Unzip,但 out 由 defer 关闭,可能在解压时尚未关闭
2026-01-11 12:40:34 +08:00
wike2019 2fda961643 io.Copy 后立即调用 Unzip,但 out 由 defer 关闭,可能在解压时尚未关闭 2026-01-10 16:00:10 +08:00
PiexlMax(奇淼 fd9883e035 Merge pull request #2158 from wike2019/pr/fix-cutter
fix bug 当日志文件删除失败时不阻塞日志写入
2026-01-06 11:18:58 +08:00
wike2019 f41f068b8b fix bug 当日志文件删除失败时不阻塞日志写入 2026-01-05 22:18:41 +08:00
PiexlMax(奇淼 799f411c73 Merge pull request #2150 from zayn-code/user-dialog
用户管理的侧边栏优化体验
2026-01-04 11:45:10 +08:00
PiexlMax(奇淼 97e7be9d3c Merge pull request #2157 from morya/main
FIX: code too complicated
2026-01-04 11:43:37 +08:00
morya 5cfe04e5f5 FIX: code too complicated 2026-01-03 23:56:05 +08:00
zayn 5f0d59a02b 其他页面都可以通过点击外层关闭侧边栏,用户界面不可以,养成习惯后体验不太好,故允许点击外层关闭侧边栏 2025-12-09 15:27:22 +08:00
pixelmaxQM 805f319578 fix: 优化文件上传时的数据库查询条件 2025-12-06 15:46:15 +08:00
piexlMax(奇淼 f23df92c18 feat: 调整获取logo的方式 2025-12-05 17:51:18 +08:00
piexlMax(奇淼 41d9453110 fix: 修复初始化没有创建SysError表的问题 2025-12-01 17:29:30 +08:00
piexlMax(奇淼 48d0cae58b Merge remote-tracking branch 'origin/main' 2025-12-01 17:26:55 +08:00
PiexlMax(奇淼 49af9439dc update: 2.8.7-beta发布
update: 2.8.7-beta发布
2025-12-01 17:21:02 +08:00
piexlMax(奇淼 1994497ad4 fix: 调整 gva-search-box 的内边距 2025-12-01 17:07:31 +08:00
piexlMax(奇淼 4ce191cdfa fix: 修复分片上传任意文件删除问题 2025-12-01 16:56:31 +08:00
piexlMax(奇淼 ee8d8d7e04 fix: 添加路径穿越拦截,禁止非法路径删除切片 2025-12-01 16:44:32 +08:00
PiexlMax(奇淼 cf022f492c Merge pull request #2146 from Azir-11/dev-287
添加全局组件大小配置和相关主题配置项,优化主题配置栏
2025-12-01 16:17:51 +08:00
piexlMax(奇淼 96019e8a9b feat: 版本号调整 2025-11-28 17:34:37 +08:00
piexlMax(奇淼 9ff1d4ca77 fix: 修复 vueDevTools 插件的缩进问题 2025-11-28 16:45:00 +08:00
Azir-11 8bc631ece9 feat: 重构优化系统配置相关 css 代码,优化了部分 UI 样式 2025-11-27 19:12:41 +08:00
Azir-11 0edb567ded feat: 添加全局组件大小配置和相关主题配置项 2025-11-27 18:40:22 +08:00
piexlMax(奇淼 d404fcf746 feat: 优化字典管理界面,增加按钮提示和调整按钮样式 2025-11-27 15:15:24 +08:00
piexlMax(奇淼 8af78e3af7 feat: 增加图片上传和粘贴识别功能,支持通过图片生成字典描述 2025-11-27 15:11:14 +08:00
piexlMax(奇淼 3722a8e7f3 feat: 增加AI生成字典功能,支持用户输入描述生成字典 2025-11-27 14:43:50 +08:00
piexlMax(奇淼 b86f7412d1 feat: 添加项目规则文档,详细描述功能、架构及开发规范 2025-11-27 14:04:13 +08:00
piexlMax(奇淼 ad52418f99 feat: 优化前端页面展示 2025-11-26 17:24:41 +08:00
piexlMax(奇淼 08ae44158f feat: 增加字典的json导出和导入 2025-11-26 16:40:48 +08:00
piexlMax(奇淼 a1f18e1386 feat: 增加字典的json导出和导入 2025-11-26 15:54:18 +08:00
PiexlMax(奇淼 c028ea3d15 Merge pull request #2145 from bypanghu/main
fix: 更新优化插件注册 api 和注册 menus 逻辑。
2025-11-24 18:34:54 +08:00
bypanghu f357c676bb fix: 更新优化插件注册 api 和注册 menus 逻辑。 2025-11-24 09:13:57 +08:00
piexlMax(奇淼 8022c662e0 fix(layout): 将Iframe路由名称更新为gvaLayoutIframe 2025-11-18 14:06:05 +08:00
piexlMax(奇淼 aa84605c4d fix(deps): 修复自动划代码字典查询条件失效问题 2025-11-17 17:49:50 +08:00
piexlMax(奇淼 287cb6ec9c feat: 优化error样式 2025-11-14 14:41:11 +08:00
piexlMax(奇淼 b9788e9b2a feat(错误日志): 添加异步处理错误日志功能 2025-11-12 18:02:50 +08:00
piexlMax(奇淼 a469ea23f4 refactor(zap): 重构日志信息格式以提高可读性 2025-11-11 18:21:14 +08:00
piexlMax(奇淼 c5f81d64c8 fix(错误处理): 统一前端错误类型显示为中文并优化错误详情布局 2025-11-11 18:18:23 +08:00
piexlMax(奇淼 78d135c6bf feat(日志): 增强日志功能以显示调用方源码 2025-11-11 18:11:32 +08:00
PiexlMax(奇淼 ff06aca146 Merge pull request #2138 from feitianbubu/pr/fix-cookie-duration
fix: correct cookie maxAge using seconds instead of minutes
2025-11-11 17:12:44 +08:00
PiexlMax(奇淼 849d5760da Merge pull request #2139 from feitianbubu/pr/fix-repeat-migrate-alter
fix: repeat alter gorm autoMigrate due to incorrect comments
2025-11-11 17:12:18 +08:00
piexlMax(奇淼 8cce9edbde feat(错误日志): 实现错误日志记录功能并修复拼写错误
添加错误日志记录功能,包括API、路由、服务和前端接口
修复sysError相关变量名的拼写错误
更新依赖版本至go 1.24
使用自定义Recovery中间件记录panic信息
添加zap日志钩子将错误日志写入数据库
2025-11-11 16:33:26 +08:00
piexlMax(奇淼 6bea7bc524 feat(导出模板): 添加SQL预览功能并优化模板展示界面 2025-11-10 11:05:03 +08:00
PiexlMax(奇淼 b6c0138dd2 feat: 统一配置命名 2025-11-09 16:15:22 +08:00
PiexlMax(奇淼 7658ff46c3 Update config.js 2025-11-09 16:10:40 +08:00
PiexlMax(奇淼 bd1aa1f559 Merge pull request #2140 from xue-ding-e/patch-7
bugfix:用户管理界面无法分配 / 查看角色
2025-11-09 16:09:29 +08:00
Qing Liang 27fb85f630 bugfix:用户管理界面无法分配 / 查看角色 2025-11-07 22:50:01 +08:00
feitianbubu 0be88bb442 fix: repeat alter gorm autoMigrate due to incorrect comments 2025-11-07 14:44:06 +08:00
feitianbubuandClaude a8642f4582 fix: correct cookie maxAge calculation by using seconds instead of minutes
The SetToken function expects maxAge in seconds (standard for HTTP cookies), but the code was incorrectly dividing by 60, causing cookies to expire 60 times faster than intended.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 10:54:11 +08:00
piexlMax(奇淼 5d67fc95d2 Merge branch 'main' into dev-287 2025-11-06 17:59:24 +08:00
piexlMax(奇淼 057ad2eeeb fix: 添加占位符字段防止json schema校验失败 2025-11-06 17:50:23 +08:00
piexlMax(奇淼 ca0a1250cd refactor(mcp): 修改execute定义 2025-11-06 17:50:23 +08:00
piexlMax(奇淼 6c82b34e8b fix: 添加占位符字段防止json schema校验失败 2025-11-06 17:43:09 +08:00
piexlMax(奇淼 fdc5e3cbf6 Merge branch 'dev-287' of github.com:flipped-aurora/gin-vue-admin into dev-287 2025-11-06 17:28:30 +08:00
piexlMax(奇淼 a0643d8ded refactor(mcp): 修改execute定义 2025-11-06 17:25:36 +08:00
PiexlMax(奇淼 83fb5d5921 Merge pull request #2107 from feitianbubu/pr/fix--dup-key-upload
feat: add check for existing file key before upload
2025-11-05 11:49:57 +08:00
PiexlMax(奇淼 a1070a64e7 Merge pull request #2132 from andrewbytecoder/main
fix(jwt):修正令牌过期时间计算错误
2025-11-03 13:28:47 +08:00
PiexlMax(奇淼 709cdef050 Merge pull request #2134 from frank-515/main
doc: 翻译了README-en.md 中的中文
2025-11-03 13:27:24 +08:00
PiexlMax(奇淼 c95ece3fe2 Merge pull request #2136 from Azir-11/dev-287
style(版本管理): 优化导出和导入版本抽屉的样式,支持暗色模式
2025-11-03 13:05:15 +08:00
Azir-11 d5befa1900 style(版本管理): 优化导出和导入版本抽屉的样式,支持暗色模式 2025-11-03 02:13:58 +08:00
frank515 89ea284cc6 doc: 翻译了README-en.md 中的中文 2025-10-30 21:46:10 +08:00
piexlMax(奇淼 ffe1844ba6 fix(mcp): 递归检查包文件夹中是否存在.go文件 2025-10-28 17:47:29 +08:00
piexlMax(奇淼 d36eeb5134 feat(错误日志): 实现前后端错误日志收集与管理功能 2025-10-28 16:19:25 +08:00
wangyazhou b9009bbd48 fix(jwt):修正令牌过期时间计算错误
- 调整了SetToken函数中的过期时间单位,从秒转换为分钟
- 确保新令牌的过期时间与配置保持一致- 修复了因时间单位不匹配导致的令牌提前失效问题
2025-10-28 15:14:26 +08:00
pixelmaxQM 5be32930f8 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2025-10-25 12:05:34 +08:00
pixelmaxQM 296c71290c fix(autocode): 修复插件包检测逻辑并清理无效数据库记录
改进插件包目录结构检测逻辑,当缺少必要目录时生成警告描述
添加清理数据库中不存在对应实体文件的包记录功能
2025-10-25 12:05:25 +08:00
PiexlMax(奇淼 2378971c8c Merge pull request #2129 from Azir-11/main
typo: 优化注释说明
2025-10-25 11:43:21 +08:00
piexlMax(奇淼 5a30df558c fix(登录): 修正验证码长度计算逻辑 2025-10-24 15:50:53 +08:00
青菜白玉汤 2c21f3cd75 typo: 优化注释说明 2025-10-24 10:52:16 +08:00
7d3e7b5b7a public:发布2.8.6版本 (#2126)
* feat(mcp): 新增gva_review工具并优化字典和代码生成逻辑

* fix: 调整mcp整体逻辑

* chore: 更新.gitignore,添加对本地配置文件的忽略

* feat(logo): 新增Logo组件并在多个页面中替换原有logo实现

* fix: 修复菜单 Logo 部分删除文本后显示异常的问题

* fix:添加字典列表搜索,支持中英文搜索.添加字典详情搜索

* style: 优化部分视觉样式

* feat: 增强错误预览组件的暗黑模式支持

* feat: 优化请求错误消息获取逻辑,增加状态文本优先级

* feat: 添加前端登录验证码静态验证逻辑

* feat: 添加开发环境启动脚本

* feat: 更新 SvgIcon 组件,支持本地图标和 Iconify 图标、移除未使用的 unocss 依赖

* fix:字典支持 tree 结构

* feat: 优化动态路由注册方式

* feat: 添加配置控制标签页keep-alive功能

* feat: 添加全局错误处理机制,捕获 Vue 和 JS 错误

* refactor: 移除API和菜单创建结果中的权限分配提醒,优化输出信息

* feat: 更新 reset.scss,优化全局样式重置,增强兼容性和可读性

* refactor(字典详情): 优化字典详情查询逻辑,移除预加载改为按需加载

* refactor(路由管理): 优化路由添加逻辑,增强路径处理和顶级路由注册

* refactor(系统配置): 将auto-migrate修改为disable-auto-migrate,保证用户升级的兼容性

* feat(utils): 优化字典数据递归查找功能并替换select为tree-select

* fix(deps): 修复在字段类型为file生成搜索条件无法运行的bug

* fix: 修复header的tools中icon不展示的问题

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: Azir-11 <2075125282@qq.com>
Co-authored-by: bypanghu <bypanghu@163.com>
Co-authored-by: feitianbubu <feitianbubu@qq.com>
Co-authored-by: 青菜白玉汤 <79054161+Azir-11@users.noreply.github.com>
Co-authored-by: krank <emosick@qq.com>
2025-10-19 13:27:48 +08:00
PiexlMax(奇淼 b01b27f1eb Merge pull request #2111 from zayn-code/dict
修复字典值分页bug
2025-10-09 13:59:00 +08:00
zayn d40b1ba823 修复字典值分页bug
当字典值有多页,且sort值一样时,分页返回的数据有问题,导致有些数据一直加载不出来
2025-09-30 16:38:55 +08:00
piexlMax(奇淼 a1dfc360fc feat(路由): 添加配置控制标签页keep-alive功能 2025-09-30 13:46:33 +08:00
青菜白玉汤 6da17433f2 优化动态路由注册方式
feat: 优化动态路由注册方式
2025-09-30 13:29:12 +08:00
feitianbubu 32f21d8555 feat: add check for existing file key before upload 2025-09-30 12:59:26 +08:00
PiexlMax(奇淼 c59a0504ad Merge pull request #2095 from xue-ding-e/patch-6
Update response.go
2025-09-21 17:32:07 +08:00
Qing Liang 182af9a1b6 Update response.go
删除多余注释
2025-09-11 11:20:52 +08:00
piexlMax(奇淼 424c5b23b4 style(layout): 修复绝对定位类名缺少重要修饰符的问题 2025-09-09 11:18:11 +08:00
piexlMax(奇淼 86b420ce67 docs: 更新项目规则文档和调整代码格式 2025-09-08 10:54:44 +08:00
piexlMax(奇淼 ea5709e5b6 style(菜单组件): 调整级联选择器宽度样式为全宽 2025-09-08 10:51:13 +08:00
PiexlMax(奇淼 4e9e3570ed fix: VersionData数据类型改为text 2025-09-07 23:58:05 +08:00
pixelmaxQM 78cdc287c5 docs: 更新项目规则文档中的角色描述为全栈专家 2025-09-07 12:46:59 +08:00
piexlMax(奇淼 58b123d316 fix: VersionData 默认使用text 考虑兼容性 2025-09-05 17:38:46 +08:00
piexlMax(奇淼 fb199aeedc fix: 修复多出来的一个/ 2025-09-04 15:16:31 +08:00
piexlMax(奇淼 364dddb70a Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2025-09-03 16:32:46 +08:00
piexlMax(奇淼 6bf848d53f style: 统一使用!前缀替代方括号的宽度类名
修改模板文件中的宽度类名,从w-[380px]和w-40统一改为!w-380px和!w-40
修复模板中条件判断的语法格式问题
2025-09-03 16:29:52 +08:00
青菜白玉汤 3e429f4091 feat: 增加依赖,提高 unocss 相关兼容性 (#2088)
* fix: 补充部分运行时依赖

* optimize: 优化class mark.
2025-09-02 15:03:48 +08:00
piexlMax(奇淼 daabca4768 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2025-09-01 15:19:22 +08:00
piexlMax(奇淼 9e688c65d3 fix(richtext): 为富文本编辑器上传图片添加token认证头
添加用户token到图片上传请求头中,确保有权限的用户才能上传文件
2025-09-01 15:17:58 +08:00
pixelmaxQM 2e8f5870d8 refactor(model): 调整版本数据字段的数据库类型注释
为VersionData字段添加postgres和sqlite数据库特定的类型注释,提高跨数据库兼容性
2025-08-31 00:16:32 +08:00
Qing Liang 8b0a00b98a Update project_rules.md (#2083) 2025-08-29 11:44:59 +08:00
piexlMax(奇淼 1ce3e11d52 fix(selectFile): 修复未初始化时fileList为undefined的问题 2025-08-28 15:34:35 +08:00
piexlMax(奇淼 11aa8c5cc2 feat(version): 添加字典数据支持到版本管理功能 2025-08-28 15:11:52 +08:00
piexlMax(奇淼 d8e6f2f5f4 fix: 同步 go.mod 2025-08-28 13:58:29 +08:00
piexlMax(奇淼 9d5c93b4c3 refactor(version): 统一版本号管理并更新至v2.8.5
将版本号从硬编码改为统一管理,使用package.json和全局变量维护版本信息
2025-08-28 13:51:54 +08:00
Qing Liang 2f7f3e5ac6 other:注释 重置用户密码 (#2081) 2025-08-28 13:37:04 +08:00
PiexlMax(奇淼 cb97d3832d Merge pull request #2080 from flipped-aurora/v2.8.5
发布v2.8.5 beta 版本
2025-08-28 11:45:01 +08:00
piexlMax(奇淼 dd34d6e3be fix: mcp字段统一样式限制 2025-08-26 18:43:55 +08:00
PiexlMax(奇淼 1d700ad5b6 Update README.md 2025-08-19 18:26:17 +08:00
PiexlMax(奇淼 3648df9522 Merge pull request #2070 from dzwvip/main
修改gorm-oracle的驱动包为go-ora,不再依赖cgo和oracle instant  client
2025-08-14 15:33:51 +08:00
dzwvip eb2925829f 修改gorm-oracle的驱动包为go-ora,不再依赖cgo和oracle client 2025-08-12 15:05:38 +08:00
piexlMax(奇淼 1e3c968277 refactor(mcp): 更新默认值描述并移除无用工具 2025-08-11 10:52:15 +08:00
piexlMax(奇淼 339db778c3 chore: 优化引入svg方式 2025-08-08 11:46:08 +08:00
piexlMax(奇淼 8b8ae7b692 refactor(auth): 简化权限指令中的类型检查逻辑 2025-08-07 16:18:04 +08:00
piexlMax(奇淼 52be26eb43 fix: 修正未配置默认路由时的错误提示信息 2025-08-06 15:55:38 +08:00
piexlMax(奇淼 9f958addc8 fix(verify): 移除登录验证中的Captcha字段校验
refactor(validation): 强制字段名首字母大写并更新文档
2025-08-06 15:18:03 +08:00
piexlMax(奇淼 7a69b88885 refactor(config): 更新配置文件格式并添加新配置项 2025-08-06 13:47:09 +08:00
pixelmaxQM 76fe71a8dd docs(mcp): 完善工具描述并添加重要限制说明 2025-08-05 20:35:12 +08:00
piexlMax(奇淼 3f21d7f8dd docs(mcp): 更新字段类型的支持说明文档 2025-08-05 18:56:57 +08:00
PiexlMax(奇淼 1fce169616 Merge pull request #2065 from flipped-aurora/2.8.5
支持多模块mcp,精细化api和menu的创建规则。
2025-08-05 18:43:21 +08:00
piexlMax(奇淼 0d900293eb docs: 更新文档中字段类型描述并优化工具说明
更新多个文档和工具描述文件,统一字段类型的详细说明格式
优化菜单创建工具和API创建工具的描述,明确使用场景
补充执行计划schema中字段类型的详细说明

(cherry picked from commit d9448aa25cca717e01a00aec2c38a24da7b28f6f)
2025-08-05 18:39:13 +08:00
piexlMax(奇淼 b71ad7b6f4 docs(mcp): 完善模块关联配置的文档和示例
(cherry picked from commit e042d0464c47ab8441f363df1a1242e26a9c13f7)
2025-08-05 18:39:13 +08:00
PiexlMax(奇淼 2139e38147 refactor: optimize and simplify login captcha validation flow (#2063)
* Optimize captcha related fields verification

- Add `Captcha` field validation to `LoginVerify` rules, ensuring that the captcha isn't empty while prechecking the data.
- Remove redundant checks for empty values for `Captcha` and `CaptchaId`, as they are already validated in the `LoginVerify` struct.
- Move client IP key retrieval after input validation for better flow.

* refactor: simplify login captcha validation flow for cleaner code
2025-08-04 18:35:28 +08:00
Feng.YJ a033ab9abe refactor: simplify login captcha validation flow for cleaner code 2025-08-04 13:43:03 +08:00
Feng.YJ 311e1ddb9f Optimize captcha related fields verification
- Add `Captcha` field validation to `LoginVerify` rules, ensuring that the captcha isn't empty while prechecking the data.
- Remove redundant checks for empty values for `Captcha` and `CaptchaId`, as they are already validated in the `LoginVerify` struct.
- Move client IP key retrieval after input validation for better flow.
2025-08-04 13:39:51 +08:00
pixelmaxQM 31e6316916 feat(mcp): 实现需求分析工具并支持批量创建模块
1. 新增requirement_analyzer工具,用于将用户需求转换为结构化提示词
2. 修改gva_auto_generate工具支持批量创建多个模块
3. 更新文档示例和schema以反映批量创建功能
4. 优化执行计划验证逻辑,支持模块数组校验
5. 改进字典创建流程,避免重复创建相同字典类型
2025-08-03 23:58:47 +08:00
PiexlMax(奇淼 9260111312 Update README.md 2025-08-01 13:31:50 +08:00
PiexlMax(奇淼andpiexlMax(奇淼 877f8f4fcf feat(autoCode): 添加空包检测与自动清理功能 (#2061)
refactor(analyzer): 重构模块分析逻辑,增加空包检测

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
2025-08-01 13:22:40 +08:00
273d7bd50e V2.8.4Beta 极致融合AI编辑器 让开发速度更进一步 (#2060)
* fix(style): 修复 border 额外的 reset 导致 tailwind border 属性生效异常的问题

* feat: 添加错误预览组件并优化请求错误处理逻辑

* optimize: select and update necessary fields in `ChangePassword` method

- Simplify `ChangePassword` method signature by removing unnecessary return type.
- Use `Select()` to fetch only the necessary fields (`id` and `password`) from the database.
- Replace `Save()` with `Update()` for more efficient password update operation.

Note: use `Save(&user)` to update the whole user record, which will cover other unchanged fields as well, causing data inconsistency when data race conditions.

* feat(menu): 版本更新为2.8.4,给菜单增加按钮和参数的预制打包

* feat(menu): 恢复空白的配置文件

* Remove unused `SideMode` field from `ChangeUserInfo` struct

Remove unused and deprecated `SideMode` field from user request model.

* feat(automation): 增加可以自动生成CURD和续写方法的MCP

* fix(mcp): 确保始终返回目录结构信息

* fix(mcp): 当不需要创建模块时提前返回目录结构信息

* feat(automation): 增加可以自动生成CURD和续写方法的MCP

* feat(mcp): 添加GAG工具用户确认流程和自动字典创建功能

实现三步工作流程:分析、确认、执行
新增自动字典创建功能,当字段使用字典类型时自动检查并创建字典
添加用户确认机制,确保创建操作前获得用户明确确认

* feat(version): 新增版本管理功能,支持创建、导入、导出和下载版本数据

新增版本管理模块,包含以下功能:
1. 版本数据的增删改查
2. 版本创建功能,可选择关联菜单和API
3. 版本导入导出功能
4. 版本JSON数据下载
5. 相关前端页面和接口实现

* refactor(version): 简化版本管理删除逻辑并移除无用字段

移除版本管理中的状态、创建者、更新者和删除者字段
简化删除和批量删除方法的实现,去除事务和用户ID参数
更新自动生成配置的默认值说明

* feat(版本管理): 新增版本管理功能模块

* fix(menu): 修复递归创建菜单时关联数据未正确处理的问题

* feat(mcp): 添加预设计模块扫描功能以支持代码自动生成

在自动化模块分析器中添加对预设计模块的扫描功能,包括:
- 新增PredesignedModuleInfo结构体存储模块信息
- 实现scanPredesignedModules方法扫描plugin和model目录
- 在分析响应中添加predesignedModules字段
- 更新帮助文档说明预设计模块的使用方式

这些修改使系统能够识别并利用现有的预设计模块,提高代码生成效率并减少重复工作。

* feat(mcp): 新增API、菜单和字典生成工具并优化自动生成模块

* docs(mcp): 更新菜单和API创建工具的描述信息

* feat(mcp): 添加字典查询工具用于AI生成逻辑时了解可用字典选项

* feat: 在创建菜单/API/模块结果中添加权限分配提醒

为菜单创建、API创建和模块创建的结果消息添加权限分配提醒,帮助用户了解后续需要进行的权限配置步骤

* refactor(mcp): 统一使用WithBoolean替换WithBool并优化错误处理

* docs(mcp): 更新API创建工具的说明和错误处理日志

* feat(mcp): 添加插件意图检测功能并增强验证逻辑

---------

Co-authored-by: Azir <2075125282@qq.com>
Co-authored-by: Feng.YJ <jxfengyijie@gmail.com>
Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
2025-07-31 21:21:04 +08:00
PiexlMax(奇淼 39abc7b632 Update README.md 2025-07-16 14:46:50 +08:00
piexlMax(奇淼 e19ddf6600 public: 发布2.8.3版本 2025-07-15 18:22:04 +08:00
piexlMax(奇淼 9db3bcfac5 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2025-07-15 10:48:53 +08:00
piexlMax(奇淼 a6b6b5d4aa fix: 修正变量名拼写错误,将detailFrom统一改为detailForm 2025-07-15 10:45:58 +08:00
pixelmaxQM 23f9227da1 fix(table): 修复日期列的模板语法错误,确保正确渲染创建日期 2025-07-11 00:20:29 +08:00
pixelmaxQM 857ba194e5 fix(menu): 更新成功消息提示,添加角色管理页面权限分配说明;优化菜单添加逻辑,增加父菜单存在性和权限检查 2025-07-11 00:14:14 +08:00
pixelmaxQM 6e27e3a114 fix(menus): 在设置首页菜单以后保存当前菜单结构,防止把无权限菜单设置为首页导致系统死锁 2025-07-10 23:36:27 +08:00
piexlMax(奇淼 d5b4bbfa84 fix(autoCode): 删除不必要的路由参数监听 2025-07-10 16:11:51 +08:00
piexlMax(奇淼 72ee8fb6fc fix(router): 修复路由keep-alive逻辑并添加组件名称 2025-07-10 14:52:59 +08:00
gorsandPiexlMax(奇淼 2ec2e9a66e Update service.go.tpl (#2053)
fix 排序时错误获取失败:错误: 字段 "createdat" 不存在 (SQLSTATE 42703)

---------

Co-authored-by: PiexlMax(奇淼 <165128580+pixelmaxQm@users.noreply.github.com>
2025-07-03 13:19:44 +08:00
piexlMax(奇淼 bf095c38e9 fix(service): 表格排序ID变为小写 2025-07-03 11:50:14 +08:00
piexlMax(奇淼 cee3b54b4c fix(loading): 修复loading状态管理问题并添加超时处理 2025-07-03 11:42:39 +08:00
piexlMax(奇淼 ff7e002049 fix: 修复richtext的情况下gorm标签多一个"的bug 2025-07-02 10:36:50 +08:00
zayn a1c8f6bc55 逻辑错误调整 (#2052) 2025-06-30 16:04:18 +08:00
青菜白玉汤andPiexlMax(奇淼 ca24945af6 feat: 重构设置界面,添加主题模式、颜色选择和布局配置模块,移除冗余组件 (#2050)
* feat: 重构设置界面,添加主题模式、颜色选择和布局配置模块,移除冗余组件

---------

Co-authored-by: PiexlMax(奇淼 <165128580+pixelmaxQm@users.noreply.github.com>
2025-06-29 13:27:12 +08:00
我看谁不卷 ea7455e092 fix:修复查询条件无法添加问题 (#2047) 2025-06-28 22:30:45 +08:00
Joy a5e1170af0 web/src/utils/request.js: Fix Server 返回非 JSON 响应数据时导致错误弹窗 (#2049) 2025-06-28 22:29:02 +08:00
pixelmaxQM 44751357b4 feat: 添加超时中间件以处理请求超时 2025-06-28 17:45:53 +08:00
zayn e58d40ab83 头部导航栏里的菜单无法正常渲染出来的bug (#2046)
菜单循环中没有子菜单就直接返回,没有添加到arr列表中导致arr始终是空的
2025-06-20 13:36:43 +08:00
piexlMax(奇淼 f7c3d76d37 feat(菜单管理): 重构菜单表单界面并更新element-plus依赖 2025-06-19 15:33:05 +08:00
hzbnb~ 55bf69c810 fix: 修复不小心选择业务库后想删掉的问题 (#2042) 2025-06-12 13:13:02 +08:00
Shan Chenyu b4232a8f27 更新 captcha.go 注释拼写错误 (#2043) 2025-06-12 13:12:28 +08:00
Hu Haolong 8d6dcc6b07 sys_authority.go: Fix a potential nil pointer dereference in GetParentAuthorityID (#2044) 2025-06-12 13:12:08 +08:00
piexlMax(奇淼 e3a57bdc69 update: 同步go.sum 2025-06-11 15:42:16 +08:00
piexlMax(奇淼 0eee6a3cc2 update: 升级mcp-go依赖至v0.31.0 2025-06-10 10:54:06 +08:00
计乐心 174721bc55 新增支持LoginAuth认证方式适用于IBM、微软等部分邮箱服务 (#2041) 2025-06-05 11:31:25 +08:00
OPSTime ba63bf2371 修正导出execl中数字为文本类型问题 (#2039) 2025-06-05 11:29:35 +08:00
hzbnb~ 2f07e9271f fix: 修复在多库模式下生成代码时候用默认库用错的情况 (#2038) 2025-06-05 11:19:30 +08:00
shabby2333 3e9602ff7e fix: #2030 富文本编辑器全屏时部分内容会被其他表单项遮挡 (#2040) 2025-06-05 11:08:28 +08:00
K8sCat 30763b48de db_list.go: 移除不必要的case判断 (#2036) 2025-06-05 11:06:17 +08:00
bossa c3b75933b8 系统生成文件,当需要手动实现增加TODO标识 (#2037) 2025-06-05 11:05:29 +08:00
PiexlMax(奇淼 ff08d45f25 Revert "修正导出数字为文本格式问题 (#2033)" (#2034)
This reverts commit b916c7951b.
2025-05-28 17:15:39 +08:00
hzbnb~ be0e4e97f7 feat: 添加暂存成功提醒 (#2031) 2025-05-28 15:49:45 +08:00
OPSTimeandCai Meng 蔡猛 b916c7951b 修正导出数字为文本格式问题 (#2033)
Co-authored-by: Cai Meng 蔡猛 <caimeng@wisers.com>
2025-05-28 15:49:28 +08:00
piexlMax(奇淼 0ebb3d4195 update: 更新MCP为0.29.0,并且调节对应的方法。 2025-05-22 16:10:47 +08:00
piexlMax(奇淼 e7680c43ac fix: 处理SQL条件中IN和NOT IN操作符的格式化问题
在生成SQL查询条件时,当操作符为IN或NOT IN时,未正确格式化SQL语句。现已修复此问题,确保生成的SQL语句符合预期格式。
2025-05-21 17:41:54 +08:00
piexlMax(奇淼 2f80eaaf9c fix(exportTemplate): 添加IN和NOT IN操作符并修复参数解析问题
在导出模板功能中添加IN和NOT IN操作符,以支持更复杂的查询条件。同时修复了参数解析逻辑,确保从params参数中正确提取过滤条件、分页和排序等参数,避免直接使用values导致的解析错误。
2025-05-21 17:11:23 +08:00
hang666 2dfe9d7f4b fix: 修复代码生成中时间和富文本的搜索错误 (#2028)
* fix: 修复代码生成中时间和富文本的搜索错误
2025-05-19 15:30:27 +08:00
piexlMax(奇淼 cbc504cc0b fix(用户模块): 修正清理存储逻辑以正确删除cookie和localStorage项 2025-05-19 14:43:05 +08:00
piexlMax(奇淼 99550cbc37 feat: 图片选择功能增加拖拽 2025-05-19 13:58:20 +08:00
pixelmaxQM 4a53864738 fix:调整自动化MCP Tools模板 2025-05-18 11:45:36 +08:00
PiexlMax(奇淼andhang666 b731b9df78 fix: 修正搜索时间范围传入ISO8601字符串导致MySQL查询出错,并优化nil切片len检查(S1009) (#2027)
* fix: 修正搜索时间范围传入ISO8601字符串导致MySQL查询出错,并优化nil切片len检查(S1009) (#2026)

* fix:时间范围修改接受参数

---------

Co-authored-by: hang666 <44329474+hang666@users.noreply.github.com>
2025-05-17 15:41:37 +08:00
piexlMax(奇淼 1f3a8ea2eb feat: 不再对查询条件时间范围进行检测 2025-05-15 18:42:58 +08:00
piexlMax(奇淼 2bd82ead97 refactor(搜索功能): 优化时间范围搜索逻辑,使用createdAtRange替代startCreatedAt和endCreatedAt
将时间范围搜索逻辑从`startCreatedAt`和`endCreatedAt`改为`createdAtRange`,简化代码并提高可维护性。同时更新了相关模板文件和验证规则,确保前后端一致性和用户体验的连贯性。
2025-05-15 18:40:57 +08:00
piexlMax(奇淼 9f1f72fce5 update: 修正前端版本号 2025-05-14 16:25:57 +08:00
piexlMax(奇淼 38ed8bb399 feat: 删除多余的服务初始化 2025-05-14 14:36:43 +08:00
piexlMax(奇淼 2d98fdf321 feat: tool卡片页面优化 2025-05-14 12:47:59 +08:00
piexlMax(奇淼 214e108591 feat(mcpTest): 添加复制MCP配置功能 2025-05-14 12:41:52 +08:00
piexlMax(奇淼 b197a84ef7 feat:提交并优化mcp配置 2025-05-14 12:39:20 +08:00
piexlMax(奇淼 09603c436e feat: 增加 mcp Tools 自动测试工具 2025-05-14 10:51:52 +08:00
pixelmaxQM d4c883535b fix:mcp tools 编译不通过的bug 2025-05-13 21:58:21 +08:00
6323688fca 发布dev2.8.2版本 (#2025)
* refactor(server): 重构服务器启动和重载逻辑

将服务器启动和重载逻辑进行重构,提取初始化系统为单独函数,优化代码结构。删除冗余的服务器初始化文件,统一使用新的 `server_run.go` 实现优雅关闭和重载功能。同时,将“重启服务”改为“重载服务”以更准确地描述功能。

* refactor: 重构系统事件处理、JWT和Casbin相关逻辑

- 将系统重载逻辑提取到独立的`system_events.go`文件中,并引入全局事件管理器
- 将JWT相关操作从`service`层移动到`utils`层,减少服务层依赖
- 将Casbin实例管理逻辑提取到`utils`层,统一管理Casbin实例的初始化和获取
- 删除冗余的`CreateSysOperationRecord`方法,优化操作记录中间件逻辑

* refactor(server): 重构服务初始化和关闭逻辑

将 `RunServer` 函数重命名为 `initServer`,并调整其调用方式以简化代码。同时,在系统初始化时添加 `SetupHandlers` 函数以注册全局处理函数,提升代码可维护性。

* fix: 修复自动化代码enum查询条件的bug

* fix: 修复组合模式下,顶部菜单重复bug

* refactor: 修改名称 RunWindowsServer ==> RunServer

* 新增mcp

* feat: 支持mcp服务

* feat:调整mcp结构,增加客户端和测试用例

* feat:更换mcp基础包和结构

* feat:提交客户端工具测试用例

* feat: 增加自动创建 mcp Tool模板 功能

* fix: 增加默认值属性

* feat: 调整初始化menu的逻辑

* feat: 调整初始config.yaml

* feat: 增加全局GVA_MCP_SERVER属性,方便灵活化开发。

* feat: 优化自动化mcp逻辑和成功展示

* feat: 优化mcp tool nickname工具

* feat: 发布2.8.2 Beta版本

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: Gor-c <creup@outlook.com>
Co-authored-by: QIN xiansheng <sjjlnaps@163.com>
2025-05-13 19:24:54 +08:00
PiexlMax(奇淼 7a7c811311 Update README.md 2025-05-13 19:22:50 +08:00
Shinji-Li 81e178b267 docs: update a new contributions charts (#2024) 2025-05-13 19:21:58 +08:00
PiexlMax(奇淼 70c9a715d4 Update README.md 2025-05-07 16:03:32 +08:00
qSeisCloud 28bd6fef7e auto_code_plugin.go: update deprecated lib mholt/archiver/v4 to mholt/archives (#2023)
* update deprecated lib mholt/archiver/v4 to mholt/archives
2025-05-07 09:59:37 +08:00
pixelmaxQM 35e3f820c0 fix: 搜索条件增加array的特殊处理 2025-05-05 14:21:23 +08:00
piexlMax(奇淼 e847aa9e75 fix: 修复顶栏菜单重复出现的bug 2025-04-30 09:56:36 +08:00
pixelmaxQM fcfa55b39a feat: 修复自动化代码插件form引用模板错误的问题 2025-04-29 22:33:09 +08:00
qSeisCloud 8be390b2cf 修复表格标题行首尾空不匹配或多余的标题导致的SQL语句错误问题
修复表格标题行首尾空不匹配或多余的标题导致的SQL语句错误问题
2025-04-29 13:21:22 +08:00
Gor-c 3ad83cbcd6 fix: 修复组合模式下,顶部菜单重复bug 2025-04-29 11:16:17 +08:00
piexlMax(奇淼 41826f5e5c fix: 优化Windows服务器启动时Redis初始化逻辑 2025-04-28 15:38:36 +08:00
pixelmaxQM 0ccd6dc750 fix: 修复顶栏多出一个...的问题 2025-04-24 21:47:47 +08:00
pixelmaxQM 8c2ce8587d feat: 修复自动化代码的bug 2025-04-24 21:18:31 +08:00
pixelmaxQM 5e35fcea58 fix: 修复菜单无ICON的展示问题 2025-04-21 23:49:38 +08:00
pixelmaxQM 54595d46e5 fix: 修复顶栏模式bug和侧栏无图标的bug 2025-04-21 23:15:08 +08:00
piexlMax(奇淼 09cb29da17 feat: VITE_EDITOR 默认值 调整为 code 2025-04-21 18:19:03 +08:00
piexlMax(奇淼 ecf1b5bc56 fix: 修复自动化代码enum查询条件的bug 2025-04-21 15:08:05 +08:00
piexlMax(奇淼 da71231be9 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2025-04-18 11:43:19 +08:00
piexlMax(奇淼 63feecf4aa update: 发布2.8.1版本 2025-04-18 11:41:57 +08:00
a6255557ee 发布2.8.1 beta版本 (#2014)
AI: 增加了AI前端绘制功能,可以根据描述生成客户端页面【授权用户专属】

自动化: 自动化模板采用了function模式,更加方便用户二次开发和自定义改动

自动化: 默认携带ID和CreatedAt排序

自动化: 所有自动化Select模板默认支持select搜索

优化:http交互报错信息增加防止多次弹出错误遮罩机制

ICON: 优化ICON逻辑,防止多次加载svg

布局:增加侧边分栏模式
布局: 顶栏模式样式优化和高亮逻辑调整
优化: 个人配置不再需要手动点击保存,会根据变化自动保存

BUG: 修复了菜单点击设为主页勾选被取消的bug
安全: 更新了jwt版本,修复CVE-2025-30204
导出: 默认支持软删除过滤
代码: 优化了部分代码逻辑
本次更新需要重新执行 npm i

---------

Signed-off-by: joohwan <zhouhuan.chen@yunqutech.com >
Co-authored-by: huiyifyj <jxfengyijie@gmail.com>
Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: okppop <okppop@protonmail.com>
Co-authored-by: joohwan <zhouhuan.chen@yunqutech.com >
Co-authored-by: xuedinge <781408517@qq.com>
2025-04-18 11:40:03 +08:00
piexlMax(奇淼 84a3c3ba7c fix: 修复redirect跳转的bug 2025-04-15 18:01:01 +08:00
piexlMax(奇淼 90c8a240a1 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2025-04-15 16:46:09 +08:00
piexlMax(奇淼 07c694e24d fix: 修复点击分配按钮,勾选的菜单消失的bug 2025-04-15 16:43:22 +08:00
pixelmaxQM 7c1c392710 feat: 固定svg导入版本为1.1.0 2025-04-12 19:12:30 +08:00
piexlMax(奇淼 379f5fe841 Merge remote-tracking branch 'refs/remotes/origin/dev-281' 2025-04-09 09:51:04 +08:00
piexlMax(奇淼 0ab15cc5e2 feat: 模板方法抽离 不在模板中做逻辑 2025-04-08 18:48:39 +08:00
PiexlMax(奇淼 8f7a8a9e6d Update bug_report.yaml 2025-04-08 17:53:27 +08:00
PiexlMax(奇淼 d5dc42c71e Update feature_request.yaml 2025-04-08 17:53:09 +08:00
pixelmaxQM 6ae5b2384e feat: 增加默认AI绘制功能页面 2025-04-07 17:34:59 +08:00
pixelmaxQM 07c9e97bf5 feat: 增加复制功能 2025-04-07 17:31:31 +08:00
pixelmaxQM 5a53da62e3 feat: 调整AI基础路径 2025-04-07 17:25:09 +08:00
pixelmaxQM 11748da7a9 feat: 调整提示语 2025-04-07 17:20:53 +08:00
pixelmaxQM b0e15b86f5 Merge remote-tracking branch 'origin/main' into dev-281 2025-04-07 17:11:32 +08:00
pixelmaxQM 1d1ad23bc0 feat: 页面可以拖动选择 2025-04-07 17:08:20 +08:00
pixelmaxQM ac54446769 feat: 增加AI生成页面功能。 2025-04-07 17:03:24 +08:00
pixelmaxQM 5fe5caaf2b feat: 增加AI生成页面功能。 2025-04-07 17:03:18 +08:00
pixelmaxQM e111b01f16 feat: 调整重置配置属性,增加自动出页面功能 2025-04-07 13:15:53 +08:00
pixelmaxQM fd2ac3f7f1 Merge remote-tracking branch 'refs/remotes/origin/autoCode-picture' into dev-281 2025-04-07 13:12:50 +08:00
pixelmaxQM 4e57b75640 Merge remote-tracking branch 'origin/dev-281' 2025-04-07 13:03:50 +08:00
pixelmaxQM e439bff2bc feat: 调整个人配置功能,每次改变自动保存,右上角保存修改为重置。 2025-04-07 13:00:14 +08:00
PiexlMax(奇淼 e210002bff Merge pull request #2003 from huiyifyj/ctx-nil-and-others
fix: check for nil and return explicit type for `UseWithCtx` method
2025-04-07 12:46:03 +08:00
pixelmaxQM 4e735beb2f fix: 组合模式下 获取左侧菜单栏 2025-04-07 12:38:26 +08:00
pixelmaxQM d747edc1f3 fix: 禁止浏览器的默认游标行为 2025-04-07 12:17:38 +08:00
huiyifyj 8bec94336b test: fix missing isPackage argument called method 2025-04-01 16:46:36 +08:00
huiyifyj 83eb193f1b fix UseWithCtx method to check for nil context
- Add nil check for context parameter.
- UseWithCtx method return explicit type rather than interface.

Replace base64Captcha.Store return type with *RedisStore for better type safety.
2025-04-01 16:26:31 +08:00
piexlMax(奇淼 9806f72ca6 fix: 设为首页按钮防止事件穿透 2025-04-01 14:23:46 +08:00
pixelmaxQM 7e7ec52290 feat: 防止npm i 报错 2025-03-27 22:24:20 +08:00
pixelmaxQM 98746fbca5 feat: 更新前端依赖 2025-03-26 20:35:10 +08:00
PiexlMax(奇淼 c0f65386bd Merge pull request #2000 from ByteZhou-2018/m_20250318_gorm_logic
GORM初始化数据库优化,通过抽取重复的逻辑避免代码冗余。
2025-03-26 13:31:23 +08:00
pixelmaxQM cef6fce2c9 feat: 菜单增加单独的动画选择机制 2025-03-20 22:32:20 +08:00
ByteZhou-2018 4964518486 fix pgsql return error to panic 2025-03-18 21:57:51 +08:00
ByteZhou-2018 06ec433b4e Optimize GORM database initialization by extracting duplicate logic 2025-03-18 21:35:10 +08:00
pixelmaxQM 85681af8b8 feat: 默认注册表增加 info表和图库分类表 2025-03-16 12:09:14 +08:00
Qing Liang 4b12ecdf4b bugfix:mongodb没有密码无法连接 (#1999) 2025-03-16 12:00:22 +08:00
pixelmaxQM e8eacb02d6 feat: 未登录情况下防止进入路由死循环 2025-03-16 11:53:44 +08:00
pixelmaxQM e9dd55f4f9 feat: 修复未登录情况下死循环的bug 2025-03-15 16:42:36 +08:00
pixelmaxQM a79df727c9 feat: 给扫码上传添加客户端标记 2025-03-15 14:06:17 +08:00
pixelmaxQM ca47b1c4f5 feat: 在登录状态下进入白名单页面强制拉取到当前角色的默认页面 2025-03-15 14:05:58 +08:00
ab75bc7f59 public: 发布2.8.0版本 (#1998)
* feat:修改token获取优先级,优先从header获取

* feat: 增加业务ctx的传递

* fix文件选择问题,
有公共函数onDownloadFile,去掉downloadFile

* 没问题

* feat: 增加context引入

* fix: 修复图片多选的情况下点击确定抽屉无法收起的bug

* feat: 提高header的token优先级,优化导出表格逻辑,不再依赖于cookie鉴权

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: task <121913992@qq.com>
2025-03-15 13:31:33 +08:00
PiexlMax(奇淼 f776a061ce Update README.md 2025-03-13 11:05:33 +08:00
krank 1456f95b2c Update README.md 2025-03-08 13:34:23 +08:00
krank c5767f6ad5 Update README.md 2025-03-08 13:32:41 +08:00
haimait 3f8dedba80 fix: 修改导入excel模板数据注释 (#1995) 2025-03-05 10:15:49 +08:00
pixelmaxQM 121d62f20f fix: 修复图片多选的情况下点击确定抽屉无法收起的bug 2025-03-03 20:05:48 +08:00
pixelmaxQM 2c08265210 fix: 修复个人样式配置情况下false无法生效的问题 2025-02-25 20:43:58 +08:00
PiexlMax(奇淼 82e397f136 fix:修复mssql中getDB失败的bug 2025-02-20 15:29:46 +08:00
taskandtask 730ee0205e 媒体库增加裁剪上传,扫码上传 (#1994)
Co-authored-by: task <121913992@qq.com>
2025-02-19 18:08:31 +08:00
pixelmaxQM a4716d5db0 fix: 修复iframe url传入不识别的bug 2025-02-16 12:28:34 +08:00
pixelmaxQM 06f166b70a feat: 发布2.7.9版本 2025-02-16 11:52:41 +08:00
pixelmaxQM f2ea36ac0d feat: 调整初始化数据 2025-02-15 16:58:33 +08:00
piexlMax(奇淼 a8e706a395 feat: 调整自动化代码富文本模式下的可选查询条件 2025-02-13 16:20:52 +08:00
bypanghu f608bfa191 fix:设置添加页面切换动画 2025-02-13 15:39:09 +08:00
piexlMax(奇淼 e494e22c07 feat: 调整版本为v2.7.9-beta 2025-02-13 15:33:01 +08:00
d40c815760 2.7.9beta (#1993)
* 媒体库增加分类,图库多选择时优化。

* 重构 JWT token 生成,使用 `New()` 函数代替直接创建实例

* 上传组件支持查看大图 (#1982)

* 将参数缓存,媒体库增加分类,图库多选择时优化。 (#1978)

* 媒体库增加分类,图库多选择时优化。

*修复文件上传进度显示bug&按钮样式优化 (#1986)

* fix:添加内部 iframe 展示网页,优化 permission 代码

* 俩个uuid库合并一个,更新库到当前版本。

* 优化关于我们界面

* feat: 个人中心头像调整,媒体库兼容性调整。

* feat: 自动化代码前端页面美化,多余按钮收入专家模式

* feat: 增加单独生成server功能

* feat: 限制单独生成前后端的情况下的细节配置

* feat: 修复全选失败报错的问题

---------

Co-authored-by: task <121913992@qq.com>
Co-authored-by: Feng.YJ <32027253+huiyifyj@users.noreply.github.com>
Co-authored-by: will0523 <dygsunshine@163.com>
Co-authored-by: task <ms.yangdan@gmail.com>
Co-authored-by: sslee <57312216+GIS142857@users.noreply.github.com>
Co-authored-by: bypanghu <bypanghu@163.com>
Co-authored-by: Azir <2075125282@qq.com>
Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: krank <emosick@qq.com>
2025-02-13 15:25:10 +08:00
PiexlMax(奇淼 ea39d83907 Update README.md 2025-02-10 16:44:35 +08:00
pixelmaxQM dae38d9b18 fix:菜单复合模式下,点击一级菜单会自动选择首位子菜单,不含子菜单则定位为顶栏本体。 2025-02-09 19:56:51 +08:00
krank 1e7cf9e65d feat: AI识图前端页面 2025-01-10 16:33:59 +08:00
药要吃 831bd61e02 更新个人信息页样式 这个头 得开 (#1977)
* 更新个人信息页样式
2025-01-09 17:14:39 +08:00
pixelmaxQM fe2b846dbc feat: 提交发布2.7.8版本 2025-01-01 14:49:27 +08:00
pixelmaxQM 8c47d2b179 feat: 提交发布2.7.8版本 2025-01-01 14:49:27 +08:00
Leslie afe6b234cf fixed: 修复递归获取角色列表数据缺失问题 (#1974) 2024-12-31 11:38:04 +08:00
piexlMax(奇淼 1743c763d2 feat: gorm的debug日志无论是否开启了zap都需要输出到控制台 2024-12-31 10:51:33 +08:00
Feng.YJ 21237f8be1 模板文件文档注释修改 (#1973)
* 模板文件文档注释修改

* 补充模板相关修改
2024-12-30 17:08:17 +08:00
piexlMax(奇淼 d19e446416 fixed: 修复无法创建新内容的bug 2024-12-26 15:16:58 +08:00
piexlMax(奇淼 8b93ede959 fixed: 修复sql日志无法加入统一zap输出的bug 2024-12-25 13:51:02 +08:00
PiexlMax(奇淼 cb23254152 给自动化代码增加视觉功能 (#1970)
* update:增加视觉能力。

* feat: 自动化代码增加视觉识别功能
2024-12-22 00:14:03 +08:00
Feng.YJ 601aa6e245 代码优化及错误返回改进 (#1969)
* Makefile: 使用 '?=' 替代 if-else 的判断

* 移除多余的类型转换

* 移除多余的nil判断

* map 使用简化以及错误处理优化
2024-12-22 00:13:22 +08:00
Feng.YJ 532d282509 修复生成的结构体 tag 字段错误以及其它注释和尾部空格问题 (#1968)
* 修复生成的结构体 tag 字段错误

* 移除字段注释多余尾部空格

* 文件模板注释 `@accept` 保持规范
2024-12-20 16:50:45 +08:00
Feng.YJ 93c0525ea5 生成模板中注释文档 query 修改 (#1967)
* 生成模板中注释文档 query 修改
2024-12-19 17:21:22 +08:00
Feng.YJ 2bf423b42f 修复可能的 context 泄露以及遗漏的错误处理 (#1965)
* 修复结构体 tag 字段的错误使用
2024-12-17 16:59:06 +08:00
Brandon-lz f6c2ce45c1 修复限流不返回报错信息的bug (#1966) 2024-12-17 16:57:28 +08:00
Feng.YJ d24eeefc86 添加 swagger 文档接口排序的 @Tag 设置说明 (#1964)
* fix: 修复欢迎信息中的 tab 缩进格式

* 添加 swagger 文档生成

* 添加 swagger 文档接口排序的 `@Tag` 设置说明
2024-12-16 14:25:38 +08:00
pixelmaxQM 876d4187d9 fixed: 过滤条件添加富文本 2024-12-15 13:34:14 +08:00
pixelmaxQM 2412e7151f fixed: 修复富文本组件 查看详情没有正确展示的bug 2024-12-15 13:31:33 +08:00
Isaacedvr1003andzsc 07c21caf8d fixed:修复表名是大写字母开头时,自动化代码异常问题。 (#1961)
Co-authored-by: zsc <zhangshuncheng@dhcc.com.cn>
2024-12-13 17:51:00 +08:00
青菜白玉汤 69ddb2ddff fix: 修复自动化代码管理侧边栏自动展开的问题 (#1959) 2024-12-11 17:51:10 +08:00
283143e1bf 发布v2.7.8Beta1 (#1957)
* beta:2.7.8-a 增加自动化创建树形结构 (#1941)

* feat: 支持创建树形结构

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>

* 优化user store部分写法

* Update user.js

* feat: 升级版本号

* Dev 278 beta2 (#1954)

* 在关闭详情弹窗后 detailFrom为空对象,arr为undefined 使用slice控制台会报错

* 查询不重置pageSize

* 优化主题模式相关内容

* 优化弹窗手机端显示

* bugfix:PostgreSQL initdb (#1953)

* bugfix:postgresql增加显示指定template

---------

Co-authored-by: PiexlMax(奇淼 <165128580+pixelmaxQm@users.noreply.github.com>

---------

Co-authored-by: zayn <972858472@qq.com>
Co-authored-by: Azir <2075125282@qq.com>
Co-authored-by: Qing Liang <106448173+xue-ding-e@users.noreply.github.com>

* docs:调整部分代码注释以及代码格式

* feat: 自动化代码字典支持多选

* fix:调整值接收器和指针接收器

* feat: 支持导出表格复制,优化增加方法页面。

* chore:初始化代码规范化。

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: Azir <2075125282@qq.com>
Co-authored-by: zayn <972858472@qq.com>
Co-authored-by: Qing Liang <106448173+xue-ding-e@users.noreply.github.com>
Co-authored-by: cjb <75364055@qq.com>
2024-12-08 21:17:21 +08:00
PiexlMax(奇淼 80c54ad890 Merge pull request #1946 from neo-6/neo-6-patch-1
解决Invalid vnode type when creating vnode的警告问题
2024-12-04 20:29:35 +08:00
天梦 3272f3c8cc 修复长度验证中数字验证 2024-12-02 18:47:28 +08:00
天梦 6bfbfc4762 解决传参时提示错误警告 2024-12-02 18:29:44 +08:00
天梦 8d2735f6e9 解决Invalid vnode type when creating vnode的警告问题 2024-12-02 15:59:25 +08:00
ipanghu d72984be7e 修复 dockerfile 添加缓存层 (#1943) 2024-11-25 15:41:08 +08:00
pixelmaxQM 39212666c5 feat: 修复导出在baseApi配置为/时候的路径拼接错误 2024-11-21 20:00:27 +08:00
PiexlMax(奇淼 c909d32c56 fix: 无法自动化新增字段的bug 2024-11-19 16:31:43 +08:00
zayn 8073e989f5 查询不重置pageSize (#1940)
* 查询不重置pageSize
2024-11-18 18:07:38 +08:00
pixelmaxQM 4671013ea6 fix: 自动化代码回滚后不可复用的bug 2024-11-17 11:59:09 +08:00
task b954457ae4 Update date.js (#1937)
替换被弃用的RegExp.$1、substr
2024-11-16 13:24:19 +08:00
zayn f7889b9709 Update format.js (#1935)
在关闭详情弹窗后 detailFrom为空对象,arr为undefined 使用slice控制台会报错
2024-11-15 10:38:53 +08:00
pixelmaxQM a9894acd51 feat: 允许清除关联关系 2024-11-14 23:16:10 +08:00
Mr·Zhaoandadmin 51e1c62ee6 web/src/view/superAdmin/menu/icon.vue: 后台菜单管理中选择图标时增加可选自定义图标 (#1933)
Co-authored-by: admin <admin@example.com>
2024-11-12 22:52:30 +08:00
pixelmaxQM fbd0f4b9c6 fix: 自动化代码需检测简称,简称不可以重复。 2024-11-11 22:40:41 +08:00
PiexlMax(奇淼 58204373aa Update README.md 2024-11-10 23:35:30 +08:00
pixelmaxQM 710257da65 delete: 删除开发模式docker-compose环境 2024-11-10 22:37:18 +08:00
青菜白玉汤 f63803529a perf(projects): 增强文件校验的兼容性 (#1931) 2024-11-10 17:02:31 +08:00
piexlMax(奇淼 7d9af64f6d feat: 使用prettierrc对代码进行格式化 2024-11-09 10:32:26 +08:00
piexlMax(奇淼 87a4ce17e1 feat: 根据eslint 对项目进行规范化处理 2024-11-09 10:17:57 +08:00
Raindrop-YL fae6f413a5 fix: 适配 eslint v9 更新, 兼容低版本 node (#1930)
* fix: eslint v9 版本配置文件更新
2024-11-09 09:48:21 +08:00
piexlMax(奇淼 d8e36ab0f8 feat: 新增方法默认窗口关闭 2024-11-09 09:45:56 +08:00
piexlMax(奇淼 35fd5c8d65 feat: 更新dockerfile的node版本 2024-11-08 16:17:52 +08:00
PiexlMax(奇淼 5604424e6f Merge pull request #1924 from zayn-code/main
表单提交按钮增添loading,防连点
2024-11-08 13:54:23 +08:00
pixelmaxQM c4c5f01ee5 feat: 增加包ace-builds 2024-11-07 21:47:24 +08:00
pixelmaxQM e6d203d567 fix: AI生成代码强制处理首字母大写,提高容错 2024-11-07 20:15:09 +08:00
piexlMax(奇淼 e75fa0bd84 feat: 更换代码编辑器,增加不同node的兼容性。 2024-11-07 18:33:33 +08:00
piexlMax(奇淼 b2cfbb95b6 fix: 在导出表格之前取消掉用户自行添加的""和`` 2024-11-06 11:19:17 +08:00
zayn 0d84ea9523 Update form.vue.tpl
表单提交的时候按钮添加loading状态,防止手滑连点后重复创建
2024-11-04 19:39:52 -08:00
zayn e99fe70164 Update table.vue.tpl
表单提交的时候按钮添加loading状态,防止手滑连点后重复创建
2024-11-04 19:28:24 -08:00
pixelmaxQM 8bd337e08f fix: 字符串情况下搜索条件为空不再参与搜索筛选 2024-11-03 22:09:02 +08:00
pixelmaxQM 12124eb1aa feat: 完善自动化代码填充方法逻辑,增加成功率 2024-11-03 13:15:52 +08:00
pixelmaxQM e036395d18 fix: #1918 在包含delete_at的情况下,数据源自动过滤软删除数据 2024-10-31 20:24:18 +08:00
pixelmaxQM 41ba7ad6a5 fix: #1918 在包含delete_at的情况下,数据源自动过滤软删除数据 2024-10-31 20:10:06 +08:00
pixelmaxQM 3452eafe4f feat: 模板配置将自动同步本地有的模板和插件 2024-10-30 20:41:10 +08:00
pixelmaxQM e515ad3074 feat: UI细节优化 2024-10-30 20:32:39 +08:00
pixelmaxQM 255f138bdb feat: 模板配置可以读取系统原生携带的文件模板 2024-10-30 20:32:04 +08:00
PiexlMax(奇淼 08496c2c61 Merge pull request #1922 from cangqiaoyuzhuo/main
chore: fix function name in comment
2024-10-30 10:07:40 +08:00
piexlMax(奇淼 25a996fe51 fix: 新增字段在没有选择gvaModel的情况下,防止出现空指针 2024-10-30 09:48:40 +08:00
piexlMax(奇淼 9ba39f2eda fix: 新增字段在没有选择gvaModel的情况下,防止出现空指针 2024-10-30 09:46:38 +08:00
piexlMax(奇淼 4a70b38a99 fix: 修复关联模式下的sql语句bug 2024-10-30 09:42:37 +08:00
pixelmaxQM 0dc66adc0d feat: 参数管理功能示例代码动态化 2024-10-29 22:18:13 +08:00
bypanghu c2c11b29a7 fix:修复运行时 saas 报错 2024-10-29 22:08:17 +08:00
pixelmaxQM 071f48c3ca feat: 表格模板更名为导出模板 2024-10-29 22:05:03 +08:00
pixelmaxQM 65cef0b40f feat: 导入导出功能将可以直接看到代码模板。 2024-10-29 21:56:30 +08:00
pixelmaxQM f30912e02f fix: 不再自动对导出key进行处理,如遇到关键字需要使用对应数据库的字符串表达式包裹 2024-10-29 20:46:31 +08:00
cangqiaoyuzhuo 1b74dc8afd chore: fix function name in comment 2024-10-28 22:24:45 +08:00
pixelmaxQM 1840b343b2 feat: 自动化代码不允许创建与模板同名的的字段JSON。 2024-10-28 22:05:24 +08:00
pixelmaxQM 4f8030ecae fix: 修复LIKE查询下的模板bug
fix: 在模板模式下对AI进行disabled
2024-10-28 21:39:40 +08:00
PiexlMax(奇淼 bb6c0be9de Merge pull request #1921 from flipped-aurora/dev2.7.7
beta:2.7.7 AI版本发布
2024-10-27 10:36:40 +08:00
pixel(奇淼 a2d4c43047 feat: 插件模板搜索功能按照数组提供索引条件 2024-10-27 10:35:43 +08:00
pixel(奇淼 60184f12bd feat: 菜单主菜单css样式调整 2024-10-27 10:26:35 +08:00
pixel(奇淼 4ffa30e31a feat: 增加AI生成之前的确认行为 2024-10-27 10:21:48 +08:00
pixel(奇淼 7fff2833c3 feat: ai生成页面功能屏蔽 2024-10-26 12:37:27 +08:00
pixel(奇淼 d1da92d040 Merge branch 'main' into dev2.7.7
# Conflicts:
#	web/src/pathInfo.json
#	web/vitePlugin/componentName/index.js
2024-10-26 12:30:41 +08:00
pixel(奇淼 6bb8f8a030 fix: 修复空菜单无法切换为手动输入的bug,修复没有vueName无法读取到pathinfo.json中的bug 2024-10-26 12:17:54 +08:00
pixelmaxQM dcd0eb20e1 feat: 调整自动引入组件,新增html展示页面。 2024-10-25 22:19:13 +08:00
pixelMax(奇淼 7d6270079a feat: 增加ai绘制页面功能 2024-10-25 18:22:11 +08:00
pixelMax(奇淼 05242c0ad7 feat: 完善AI帮写内容 2024-10-25 10:35:14 +08:00
pixelMax(奇淼 30fb3a97d7 feat: 增加方法可以根据方法介绍自动补全 2024-10-25 10:22:09 +08:00
pixelMax(奇淼 4dec8cfb17 Merge branch 'dev2.7.7' of github.com:flipped-aurora/gin-vue-admin into dev2.7.7 2024-10-25 09:47:36 +08:00
pixelmaxQM bb8210b88e feat: autoFunc可以ai添加代码。 2024-10-24 22:55:15 +08:00
pixelMax(奇淼 b69858b6f7 feat: AddFunc在ai生成后支持页面编辑 2024-10-24 18:44:07 +08:00
pixelMax(奇淼 f191601ab4 feat: 增加AddFunc自动填充方法逻辑功能 2024-10-24 18:01:40 +08:00
PiexlMax(奇淼 7d62a55a92 Merge pull request #1917 from Brandon-lz/dev2.7.7
Dev2.7.7 新增支持minio分片上传大文件
2024-10-23 11:22:17 +08:00
Brandon lz eadcda4e30 modified: server/go.mod
modified:   server/go.sum
2024-10-22 07:05:18 +00:00
Brandon lz 45382d1446 支持大文件分片上传minio 2024-10-22 07:00:51 +00:00
PiexlMax(奇淼 0fd4f0bd7c Merge pull request #1911 from zyw0605688/dev2.7.7
修改模板文件table.vue.tpl
2024-10-22 13:29:18 +08:00
pixelmaxQM c3fd7b9077 fixed: 修复一对一一对多编辑时候,kv丢失的bug。 2024-10-21 20:16:59 +08:00
zyw0605688 0f6aa3df83 feat:'1.查询条件字段,如果关联业务表下拉查询,则参考form使用下拉框。2.新增和添加统一,变更好修改统一,查看详情弹框增加标题' 2024-10-19 11:32:14 +08:00
pixelmaxQM 48333c2ad2 Merge remote-tracking branch 'origin/main' into dev2.7.7 2024-10-18 21:25:27 +08:00
pixelmaxQM 9786886c3f feat: 在存在enum的情况下自动化代码时候会校验其赋值并且在错误时候自动包裹 2024-10-18 21:23:43 +08:00
pixelMax(奇淼 b0eedfd6f1 fix: AI导出需要必须选择表 2024-10-18 18:07:23 +08:00
pixelMax(奇淼 1753bf96a8 fix: AI导出表格模板获取表格信息错误的bug 2024-10-18 17:41:58 +08:00
pixelMax(奇淼 67315bf88e feat: 自动化代码string调整为指针类型 2024-10-18 13:53:48 +08:00
PiexlMax(奇淼 4a3dcf24e1 Merge pull request #1906 from Brandon-lz/main
新增支持minio oss
2024-10-18 10:35:44 +08:00
PiexlMax(奇淼 c1b18fe478 Merge branch 'dev2.7.7' into main 2024-10-18 10:35:35 +08:00
chenlianghong e918af0a0c adjust sys_user.go message when del logined self (#1909) 2024-10-18 10:34:24 +08:00
pixelmaxQM a847ad292f feat: 自动化代码可自行配置mod 2024-10-17 23:15:59 +08:00
pixelmaxQM efac72ecbb feat: 增加添加字段功能,方便用户粘贴赋值字段到对应代码位置 2024-10-17 22:29:52 +08:00
pixelMax(奇淼 ed5611810f feat: 自动化代码部分输入框样式调节 2024-10-17 10:03:44 +08:00
pixelMax(奇淼 b8d5e79c03 fixed: 修复无法直接设置router-view的bug 2024-10-16 15:26:09 +08:00
pixelMax(奇淼 3e72ea0650 delete: 去除无用的引用包 2024-10-16 13:17:03 +08:00
pixelMax(奇淼 8b8a0b61af delete: 剔除ws插件 2024-10-16 13:13:15 +08:00
pixelmaxQM f237ac981e feat: 增加自动化代码增加字段的可控参数 2024-10-15 23:28:47 +08:00
PiexlMax(奇淼andAzir 0ce5a63c1d update: 发布dev2.7.6Beta版本 (#1908)
* feat: 优化菜单管理的路径选择框

* fixed: 修复错误的文件命名

* feat: 增加参数管理功能,调整菜单选择组件。

* feat: 恢复config.yaml

* feat: 更新AI功能

* feat: 增加API自动填充功能

* feat: 增加AI自动填充表格导出模板

* feat: 增加AI自动填充表格导出模板和AI自动模板填充

* feat: 新增方法支持选择是否鉴权

---------

Co-authored-by: Azir <2075125282@qq.com>
2024-10-15 21:58:17 +08:00
Brandon-lz a483ac9174 minio 完善 2024-10-14 11:46:39 +00:00
Brandon-lz 91e4c89962 新增minio oss 功能 2024-10-14 10:03:28 +00:00
PiexlMax(奇淼 c34e3b4282 Update README.md 2024-10-11 17:36:25 +08:00
chenlianghong 6e38eb1d70 fix: support pluginPath svg file as component show list when dev mode (#1902) 2024-10-09 10:30:27 +08:00
piexlMax(奇淼 5d227d8d72 feat: 配置保存按钮移动到顶部 2024-10-08 13:14:43 +08:00
piexlMax(奇淼 ccdf725957 fixed: 修复暗夜模式失效的bug 2024-10-08 13:06:18 +08:00
86cffba4aa Beta:发布v2.7.5测试版本 (#1896)
* 生产环境时移除console

* 更新第三方库道最新版本,修正导致的兼容问题

* feat: 版本号变更,修复自动化历史的结构体描述

* feat: 放弃element的按需引用,增加自定义表单组件,替换原始的iframe引入模式。

* feat: 放开表单生成器的key输入

* feat: 自动化代码关联属性支持跨数据库关联

* fixed: 修复跨库关联模板

* feat: 允许清空跨数据关联的业务库选项

* feat: 增加用户搜索功能

* feat: 允许单条API同步
---------

Co-authored-by: task <121913992@qq.com>
Co-authored-by: task <ms.yangdan@gmail.com>
2024-09-30 21:27:16 +08:00
pixelMax(奇淼 2086a73557 feat: 兼容不同版本数据库的json操作 2024-09-30 16:05:45 +08:00
piexlMax(奇淼 a5e8980b23 fix: 消除swag init的不兼容bug 2024-09-29 10:17:59 +08:00
piexlMax(奇淼 360af93d8d fix: 增加图片选择器兼容性 2024-09-29 10:14:26 +08:00
3vilive 4c46bdaa7f feat: 上传文件到 oss 遇到错误时,应该返回错误,避免 panic (#1890) 2024-09-27 20:54:44 +08:00
pixelmaxQM b98094ceee feat: 修复文件选择组件的bug 2024-09-25 21:08:06 +08:00
pixelmaxQM 03330537fc feat: 优化图片选择器 2024-09-22 23:18:33 +08:00
task 2c7809b134 生产环境时移除console 2024-09-21 13:21:30 +08:00
task af287dcdce 生产环境时移除console 2024-09-21 13:21:30 +08:00
chenlianghong ed840a96e6 clean: Update global.js clean console.log svg component name 2024-09-21 13:21:30 +08:00
chenlianghong 04cfd0eb38 feat: edit global.js support plugin svg 2024-09-21 13:21:30 +08:00
pixelmaxQM 6386034c65 feat: 调整icon功能的绑定形式 升级vue和svg插件 2024-09-21 12:54:58 +08:00
chenlianghong 9b26d6c504 server: same Author "yourname" for gen Code (#1887) 2024-09-21 12:28:05 +08:00
chenlianghong 3529297fa4 clean: clean header index.vue repeat flex class (#1888) 2024-09-21 12:27:20 +08:00
pixelmaxQM ad699fa23c fixed: 方法名 ==> 方法介绍 2024-09-18 22:51:27 +08:00
pixelmaxQM 0fd9e951b9 fixed: 对JSONMap进行多数据库不同断言兼容 2024-09-18 22:48:41 +08:00
PiexlMax(奇淼 66bcd32ae7 Merge pull request #1886 from flipped-aurora/revert-1884-main
Revert "Update basetypes.go, fixed origin_setting column read error"
2024-09-18 22:41:24 +08:00
PiexlMax(奇淼 f0d91b0058 Revert "Update basetypes.go, fixed origin_setting column read error" 2024-09-18 22:41:06 +08:00
PiexlMax(奇淼 3d58213f0b Merge pull request #1884 from juneyx/main
Update basetypes.go, fixed origin_setting column read error
2024-09-18 22:37:12 +08:00
Juneyx 528d7411e1 Update basetypes.go, fixed origin_setting column read error 2024-09-18 14:53:13 +08:00
pixelmaxQM a6651ffe48 fixed: 字典页面默认值调整为拉回字典列表的第一个 2024-09-17 21:13:42 +08:00
pixelmaxQM a8e6dc3a3a fixed: 修复复用代码高级模式不展示可选项的bug 2024-09-17 09:43:19 +08:00
pixelmaxQM 8733b2463c fixed: 清理自动化方法的swagger入参 2024-09-16 20:01:45 +08:00
pixelmaxQM 37b0ef4599 fixed: 修复文件监听错误的bug 2024-09-14 18:16:17 +08:00
pixelmaxQM c72ed970fb feature: 增加basetype 兼容低版本数据库的json不兼容问题 2024-09-13 21:02:15 +08:00
pixelMax(奇淼 e9e42be139 fixed: 修复RedisList不受控制创建的bug 2024-09-13 16:39:43 +08:00
piexlMax(奇淼 b55ecd2808 fixed: api.js模板调整 2024-09-13 16:13:48 +08:00
pixelmaxQM f2a8829d1d feature: 版本号v2.7.3升级为v2.7.4 2024-09-12 21:03:35 +08:00
c20ea7e030 publish: 发布2.7.4版本Beta (#1880)
* 媒体库增加批量导入URL

* fix 描述错误

* feature: 自动化代码方法支持增加方法描述

* update: 更新依赖,升级为最新版本

* feature: 自动化代码预览部分支持黑夜模式

* fixed: 修复keepalive上线后失效的bug

* feature: 增加自动化基础模板功能

* feature: 增加自动化基础模板功能

* 将用户配置保存到数据库,刷新或者异地登录配置不丢失

* update: 清除无用的userinfo配置信息

* fixed: 清理开发阶段页面无端进入404的bug

* feature: 前端主题配置跟随用户,不再单独设置json编译生效。

* feature: 增加个人中心配置兼容性

* fix(package): 包名设置为中文会导致无法自动生成代码,禁止包名设置为中文

* feature: 格式化代码

* feature: 对严格模式新建根角色进行调整。

* feature: 版本变更为2.7.4

---------

Co-authored-by: sliboy <34034053+sliboy@users.noreply.github.com>
Co-authored-by: ba0ch3ng <ba0ch3ng@foxmail.com>
Co-authored-by: task <121913992@qq.com>
Co-authored-by: task <ms.yangdan@gmail.com>
Co-authored-by: 爱丽-黑子 <62006632+ailiheizi@users.noreply.github.com>
Co-authored-by: sliboy <sliboy@hotmail.com>
2024-09-12 20:48:03 +08:00
pixelmaxQM df3fc0a9ef fixed: 修复文件上传失败但是依然加入了文件列表的bug 2024-09-04 22:37:41 +08:00
pixel(奇淼 3c7a05b572 feature: 增加上传文件组件的成功失败回调事件 2024-08-31 22:06:36 +08:00
pixelmaxQM a155bcd11a fixed: 修复登陆页面小屏幕下背景色bug 2024-08-30 22:17:46 +08:00
pixelmaxQM 57f13f59b1 fixed: 修复loading无法消失的bug 2024-08-30 22:15:15 +08:00
pixelmaxQM 894cf8e6c3 feature: api默认忽略数据增加 /info/getInfoDataSource 和 /info/getInfoPublic 2024-08-27 21:44:15 +08:00
zayn fa3b952af3 column参数类型是number (#1865)
避免浏览器console的warn提示
Vue warn]: Invalid prop: type check failed for prop "column". Expected Number with value 1, got String with value "1".
2024-08-27 13:17:07 +08:00
chenlianghong b26db1910b Update model.go.template (#1866) 2024-08-27 13:16:39 +08:00
chenlianghong aab865be96 Update service.go.template (#1867)
清除生成代码多于空格
2024-08-27 13:16:18 +08:00
PiexlMax(奇淼andtask 866fa5643e Dev273 (#1868)
* fixed: 修复addFunction下前端api.js无法创建的bug。

* feature: 增加严格角色模式

* Update system.vue

* fixed: 多点登录拦截模式下,jwt换票期间不需要拉黑token。

* fixed: 修复使用ast时候产生无意义的换行的问题

* fixed: 修复跨级操作角色权限的越权问题

* feature: 优化严格模式角色鉴权操作。

* fixed: 增加菜单和api设置越权问题的限制

* feature: 增加插件打包前的自动化同步所需菜单和api的功能

* feature: 自动化代码可以默认生成导入导出

* feature: 自动化导入导出对模板进行回滚

* feature: 剔除无用的packfile代码包

* feature: 发布V2.7.3版本公测。

---------

Co-authored-by: task <ms.yangdan@gmail.com>
2024-08-27 13:15:56 +08:00
PiexlMax(奇淼 87ced16d63 Merge pull request #1862 from Eric54920/Eric-dev
feature: swagger接口请求优化
2024-08-24 23:20:23 +08:00
Eric54920 ed5463360e feature: swagger接口请求优化 2024-08-24 22:34:09 +08:00
chenlianghong 27edfac161 fix: add funcName is sure UpperChar (#1860)
* fix: add funcName is sure UpperChar
2024-08-23 18:14:40 +08:00
pixelMax(奇淼 7f70e69c8e fixed: 修复自动化代码产生的详情功能图片不可用的bug 2024-08-20 10:55:41 +08:00
pixelMax(奇淼 c70fedfb43 fixed: 修复addFunction下前端api.js无法创建的bug。 2024-08-15 18:05:43 +08:00
pixelMax(奇淼 85d7b5fd5d fixed: 修复addFunction下前端api.js无法创建的bug。 2024-08-15 18:04:33 +08:00
pixelMax(奇淼 cbace6f97e feature: 调整全量引入功能对格式化后的代码依然生效 2024-08-15 15:52:35 +08:00
pixelMax(奇淼 bec5dc4476 fixed: 模板中el-image默认添加preview-teleported,用户在预览时候方式弹出层被遮罩。 2024-08-15 15:38:29 +08:00
sliboy f7ddd8bbbb chore(user.vue): Update user.vue, alter userInfo username to userName. (#1855) 2024-08-15 10:49:31 +08:00
马国栋 43d0c291ed feature:swagger 接口请求方式优化 (#1854) 2024-08-15 10:46:41 +08:00
pixelmaxQM 0956edd0d0 feat: 初始化完成后主动获取GVA_ACTIVE_DBNAME。 2024-08-14 20:48:47 +08:00
c9477d37fa V2.7.2版本发布 (#1853)
* feat: 自动化代码增加json导出和导入功能

* feat: 自动化代码前端可见分为Table和Form分别选中

* feature: 调整代码预览为左边栏模式的tabs。

* feat: 增加方法自动添加前端api

* feat: 自动化生成前端支持详情功能

* feat: 增加自动创建可控权限按钮功能

* fixed: 顶栏样式菜单样式细节bug修复

* fixed: 修改视频地址

* fixed: 自动获取表结构和数据库表列结构保持一致

* fixed: casbin 设置空权限无需调用 AddPolicies 方法 (#1850)

* feat:对象存储支持配置Cloudflare R2 (#1849)

* fixed:设为首页和菜单勾选互为必选

---------

Co-authored-by: SliverHorn <503551462@qq.com>
Co-authored-by: 千石 <CN_QianShi@hotmail.com>

* feat: 复杂数据类型的查询将不会生成查询语句,会以string形式接收参数,用户自行实现复杂查询逻辑。

* feat: 创建新角色默认携带字典和长传权限。
禁止删除有首页占用的菜单。
不允许切换至无首页的角色。
自动化代码创建失败将返回错误信息。

* feat: 当package或plugin结构异常时候,阻止创建自动化代码。

---------

Co-authored-by: krank <emosick@qq.com>
Co-authored-by: SliverHorn <503551462@qq.com>
Co-authored-by: 千石 <CN_QianShi@hotmail.com>
2024-08-13 21:55:27 +08:00
千石 3b5c96d7cb feat:对象存储支持配置Cloudflare R2 (#1849) 2024-08-12 22:30:14 +08:00
SliverHorn c3c049b225 fixed: casbin 设置空权限无需调用 AddPolicies 方法 (#1850) 2024-08-12 22:29:50 +08:00
lbbniu 6fedb9773b fix: 代码自动生成选择业务库自动迁移代码生成异常 (#1848) 2024-08-12 15:08:17 +08:00
pixelmaxQM 332a8de2e9 fixed: 修复其他数据库类型下无法获取表列表的bug 2024-08-05 20:05:23 +08:00
PiexlMax(奇淼andkrank 7121968081 2.7.1版本提交 (#1844)
* feature:表格模板自动化生成 (#1841)

* feature:  为导出模板增加自动化功能

* feature:  视频按钮修改

* feature: 发布2.7.1Beta版本,视频集中处理。

---------

Co-authored-by: krank <emosick@qq.com>
2024-08-04 16:06:00 +08:00
pixelmaxQM a44133d0c9 fixed: 修复在同时开启多个窗口的情况下刷新页面导致的死循环情况 2024-08-04 11:12:43 +08:00
pixelmaxQM 3c3d9487d0 fixed:修复复用代码无法改变主键的bug 2024-08-03 15:08:25 +08:00
PiexlMax(奇淼 15b5083d17 Update README.md 2024-08-03 14:55:11 +08:00
pixelMax(奇淼 e25cafe2b4 fixed: 调整重复创建代码的提示 2024-08-02 14:35:16 +08:00
pixelMax(奇淼 b5c44e47ff feature: 调整baseUrl方法 2024-08-01 18:24:11 +08:00
pixelMax(奇淼 5d04b8deea fixed: 调整autoCode标签 2024-08-01 14:20:18 +08:00
pixelMax(奇淼 1207291249 fixed: 修复自动化模板多了}的问题 2024-08-01 14:08:05 +08:00
pixelMax(奇淼 06bf641e7a fixed: 修复自动化代码路径不匹配的bug 2024-07-31 18:09:12 +08:00
pixelMax(奇淼 ce764082b8 feature: 修改vite.config.js注释 2024-07-31 16:23:09 +08:00
pixelMax(奇淼 aebc301b05 feature: swagger自动化模板优化 2024-07-31 15:55:31 +08:00
pixelMax(奇淼 3b93a073c3 feature: swagger 优化 2024-07-31 15:52:23 +08:00
pixelMax(奇淼 a4a7b44da9 feature: Local优化文件删除逻辑 2024-07-31 11:22:56 +08:00
maxwell e65be6ee36 feat: tab支持使用鼠标中键关闭 (#1840)
* fix: 修复注释错误

* feat: tab支持使用鼠标中键进行关闭
2024-07-31 11:20:14 +08:00
LixvYang 2d0b9ecac0 add cloudflare r2 storage (#1835) 2024-07-30 15:31:23 +08:00
pixelmaxQM 5a5b86aeec fixed:新增方法清空已经输入的内容 2024-07-27 22:25:13 +08:00
pixelmaxQM ff41fe0577 fixed:对导出关键字进行处理 2024-07-27 17:59:00 +08:00
pixelmaxQM c97b60b2da fixed:插件api增加空方法模板调整。 2024-07-27 14:29:02 +08:00
pixelmaxQM 2645dcdddf fixed:插件api增加空方法模板调整。 2024-07-27 14:25:22 +08:00
pixelmaxQM 6debb09b0f Merge remote-tracking branch 'origin/main' 2024-07-27 00:17:02 +08:00
pixelmaxQM 62b84d454a feature:提取创建claims和token的方法,方便后续插件扩展。 2024-07-27 00:16:48 +08:00
pixelMax(奇淼 26dc3f32d9 feature: 优化自动化api模板 2024-07-26 14:52:24 +08:00
SliverHorn 84f8b6e1da fixed: package template api.go.tpl Update 2024-07-26 14:47:47 +08:00
SliverHorn 70e3d40c3e Merge remote-tracking branch 'origin/main' 2024-07-26 14:45:28 +08:00
SliverHorn 432b2f04d7 fixed: plugin template api.go.template and package template api.go.tpl 2024-07-26 14:45:10 +08:00
pixelMax(奇淼 63c82cf705 feature: 优化pathInfo.json生成功能 2024-07-26 14:00:08 +08:00
pixelMax(奇淼 5c7d121e67 feature: 放弃自己研发的代码定位功能,集成vite官方的devtool工具 2024-07-26 13:38:21 +08:00
SliverHorn 055198ccd5 fixed: plugin template api.go.template {{.Abbreviation}}.UpdatedBy rename info.UpdatedBy 2024-07-26 13:01:06 +08:00
SliverHorn 0993e81e00 fixed: package template api.go.tpl 作用域问题 2024-07-26 11:58:39 +08:00
pixelMax(奇淼 15d22b7726 feature: 增加空方法后续业务逻辑处理 2024-07-26 11:30:41 +08:00
pixelMax(奇淼 bb3a54a312 feature: 优化添加空方法的apiPath 2024-07-26 11:22:30 +08:00
pixelMax(奇淼 7ad6b9c32a feature: 自动关联可能的apiGroup 2024-07-26 11:15:02 +08:00
pixelMax(奇淼 4814f21017 feature: 增加新初始化api 2024-07-26 10:28:21 +08:00
pixelMax(奇淼 1f962f21b3 fixed: 修复自动化代码字段名称key编辑时候失去焦点的bug 2024-07-26 10:24:48 +08:00
pixelMax(奇淼 397e1e2bf1 opt: 优化模板逻辑 2024-07-26 10:04:56 +08:00
pixelmaxQM b10c7297fd feature:方法结束关闭file 2024-07-25 21:55:40 +08:00
PiexlMax(奇淼 7f9194f475 feater: 可对自动化代码增加空方法 (#1834)
* feature:自动化代码可从自动化代码管理中增加空方法,用户不用自行组织其中的关系。
2024-07-25 21:29:20 +08:00
lonevle 0fc1edf895 Dockerfile修复工作路径的问题 (#1833) 2024-07-25 21:27:20 +08:00
pixelMax(奇淼 c973c0cce5 feature: 调整自动化代码菜单和api注册逻辑 2024-07-25 16:43:11 +08:00
pixelMax(奇淼 48f3bdc80c fixed:前端文件创建路径错误 2024-07-25 16:11:33 +08:00
pixelMax(奇淼 0fc43fcf42 opt: 调整Viper配置文件路径展示代码 2024-07-25 10:05:48 +08:00
pixelMax(奇淼 e593ec604e opt: 调整import注入和回滚带别名无法识别的bug 2024-07-24 16:48:49 +08:00
PiexlMax(奇淼 1494bc9db3 2.7.0Beta2 (#1829)
* opt: 优化自动化package注册gorm_biz代码,替换为Inspect

* opt: 自动化代码插件gorm改造完成

* opt: 自动化代码插件路由注册改造完成
2024-07-24 15:24:50 +08:00
pixelMax(奇淼 4512aa7ff8 feature: 修复下标越界的bug,调整enter ast 代码 2024-07-23 18:36:35 +08:00
pixelMax(奇淼 de782e629f feature: 修复package下gorm数据添加和回滚的异常 2024-07-23 18:26:19 +08:00
pixelMax(奇淼 b7c6a7ffd9 feature: 修复package下gorm数据添加和回滚的异常 2024-07-23 17:35:17 +08:00
pixelMax(奇淼 ca4118cc8e feature: 插件enter回滚当数据为空时候删除import 2024-07-23 16:27:41 +08:00
pixelMax(奇淼 a561e7dc2b feature: 修复自动化插件会创建两个var的bug 2024-07-23 15:56:17 +08:00
PiexlMax(奇淼 b3a0f187d7 2.7.0Beta Bug修复 (#1826)
* feature:调整package注入路由方法

* feature:调整package回滚路由方法

* feature:调整创建自动化代码enter重复import的问题

* feature:调整package创建时enter的问题

* feature:调整package回滚问题
2024-07-23 00:19:21 +08:00
PiexlMax(奇淼 39be2d0351 BetaBug修复 (#1825)
* feature:调整package注入路由方法

* feature:调整package回滚路由方法

* feature:调整创建自动化代码enter重复import的问题
2024-07-22 23:53:48 +08:00
pixelMax(奇淼 5492e0db50 feature: 修复插件无法安装的bug 2024-07-22 11:33:47 +08:00
pixelMax(奇淼 db038c29e8 feature: 修复插件无法安装的bug 2024-07-22 11:30:46 +08:00
pixelmaxQM 4fe1f5c225 feature:菜单选择文件时自动同步path 2024-07-21 22:00:52 +08:00
pixelmaxQM ac374bab22 feature: 调整自动化代码web模板 2024-07-21 21:58:23 +08:00
pixelmaxQM 01f6814a25 feature: 调整插件自动注册逻辑。 2024-07-21 21:36:25 +08:00
6e4dc10c49 文件结构调整,支持插件自动化 (#1824)
* Update index.vue

多个详情页之间切换tab,页面没有重新渲染

* feature:新增同步API功能

* feature: 同步表数据

* feature:新增同步API功能

* feature: 增加V2插件注册

* feature:给Enter的依赖结构增加单独的New 方便引用

* feature: 调整关联属性的选择模式

* feature: 增加component组件和name的映射插件,防止keepalive的懒加载失效。

* update: PluginInitializeRouter  && 修复TypePluginInitializeMenu ast 类型错误

* update: 测试文件的astType 类型错误

* feature: 文件变更自动同步componentName.json。

* feature: 文件变更自动同步componentName.json。

* feat: UI美化

* feat: 自动化页面顺序调整

* feature:修改404页面

* update: PluginInitializeMenu

* update: Plugin template

* fixed systemApi 重复声明

* api.vue:update:修改API分组为下拉列表

* update: import添加注释

* update: plugin_enter_test.go 增加测试用例

* update: ast 预览文件路径

* update: config Autocode 新增Module字段以及如果为空的情况下自动获取运行目录下的go.mod文件

* update: auto_code_package.go 完善调用ast工具类的封装使用

* update: auto_code_template.go Create方法和修正SysAutoCodeHistory

* feat:调整自动化package为模板,增加初始化配置信息,调整页面信息。

* update: ast PreviewPath MkdirAll

* update: ast type错误, PluginEnter and PackageModuleEnter add TemplatePath模版路径

* update: autoCodePackage and autoCodeTemplate bug修正

* update: PackageInitializeRouter 传入两个路由组

* update: PackageModuleEnter 处理空变量时与type冲突注入

* update: Package 模版更新

* update: utils/ast 优化统一

* update: 注入内容修复错误

* fix: 修复注释错误

* update: plugin 模版 完成

* feature: 文件watch功能只在development下开启

* update: viper.go.template 因为viper不区分配置的key的大小写所以用package

* update: ast 测试代码规范化

* update: package 删除api和router多余导包

* update: plugin template

* update: auto_code_package 问题修复

* update: ast 测试插件的预览功能

* update: gorm_biz 更新注册方式

* update: go.mod tidy

* remove: plugin template gen main.go.template

* update: ast 重构, 分离读取和写入步骤支持

* update: AutoCodePackageApi 传入参数错误修复

* rename: sys_autocode_history.go => sys_auto_code_history.go

* update: 预览无需落盘, 创建落盘,抽离公共参数

* update: api.go.tpl 导包位置fmt 和package js位置存放错误

* update: 测试用例修复 and PackageInitializeGorm 重构

* update: ast 新增相对路径, 代码生成器历史回滚功能

* update: ast 工具类回滚失败修复以及测试文件

* update: 代码生成器历史 回滚问题修复

* update: 代码生成器模版忽略.DS_Store

* featute: 自动化GORM结构的注入和剔除

* feature: 插件模板调整

* feature: 增加公告插件示例,调整代码模板。

* feature: 自动注册插件V2。

---------

Co-authored-by: zayn <972858472@qq.com>
Co-authored-by: SliverHorn <sliver_horn@qq.com>
Co-authored-by: krank <emosick@qq.com>
Co-authored-by: cjk <wlicjk@126.com>
Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: maxwell <zhong.maxwell@gmail.com>
2024-07-21 11:33:25 +08:00
jameschcc 6b3a9024d3 README.md: correct typo (#1823) 2024-07-21 11:30:36 +08:00
PiexlMax(奇淼 b4841843f7 Update ci.yaml 2024-07-17 13:24:52 +08:00
pixelMax(奇淼 35efc07b2e fixed: 增加导出模板特殊字段说明,添加默认darkMode 2024-07-10 17:53:57 +08:00
pixelMax(奇淼 954160ebd9 feature: 调整导出的时间格式处理 2024-07-10 17:52:53 +08:00
pixelMax(奇淼 ea1633ad52 fixed: 修复darkMode失效的bug 2024-07-10 17:34:56 +08:00
pixelmaxQM fb5d5ea1be feature:版本变更v2.6.7 2024-07-06 12:17:17 +08:00
PiexlMax(奇淼 02f5d6fea2 增加同步API功能 (#1811)
* feature:新增同步API功能
2024-07-04 21:19:20 +08:00
zayn 227755b892 Update index.vue (#1810)
多个详情页之间切换tab,页面没有重新渲染
2024-07-04 21:14:12 +08:00
SliverHorn eebd8771bd Merge pull request #1809 from SliverHorn/ai
Update: mv system ai-path to autocode
2024-07-03 09:31:34 +08:00
SliverHorn 36fed0cc6f Update: mv system ai-path to autocode 2024-07-03 09:27:30 +08:00
pixelmaxQM 08f3b64243 feature:增加AI提问的长度限制 2024-07-02 23:40:14 +08:00
PiexlMax(奇淼 59cfe96fe3 增加AI辅助功能 (#1808)
* feature: 增加两个辅助AI,小奇和小淼

* feature:调整AI自动反写部分
2024-07-02 22:53:59 +08:00
PiexlMax(奇淼 128e810f77 调整镜像和依赖 2024-07-02 11:07:33 +08:00
PiexlMax(奇淼 bbe9322f75 Update Makefile 2024-07-02 11:03:38 +08:00
pixelMax(奇淼 35186b41ff feature:调整多图下不换行的问题 2024-07-02 10:46:38 +08:00
pixelMax(奇淼 0c846f0fea feature:url调整兼容各类情况下的图片展示 2024-07-02 10:46:30 +08:00
Wallandwall-js d497e96407 feat: 调整逻辑无论是否创建菜单或API都注册自动化代码历史 (#1804)
* feat: 调整逻辑无论是否创建菜单或API都注册自动化代码历史

---------

Co-authored-by: wall-js <wall_js@foxmail.com>
2024-07-01 10:43:32 +08:00
Qing Liang a4f139f855 后端dockerfile正确设置时区 && 忽略后端server/uploads文件夹 (#1803)
* dockerfile后端设置时区

* gitignore忽略后端uploads文件夹
2024-07-01 10:14:24 +08:00
pixelmaxQM e386b28ba4 feature:插件注册功能多给一个engine 准备后续扩展 2024-06-29 00:22:53 +08:00
pixelmaxQM aa8ef48246 fixed:侧边宽度调整防止出现横向滚动条 2024-06-28 21:59:07 +08:00
pixelmaxQM 6bac462359 fixed:图片展示功能调整 2024-06-28 21:46:37 +08:00
pixelMax(奇淼 24e4d05157 feature:url调整让上传文件支持/模式 2024-06-28 11:37:59 +08:00
SliverHornandSliverHorn 737c051466 Update: .gitignore (#1800)
* Update: .gitignore server

---------

Co-authored-by: SliverHorn <caiwei.lai@jutze.com.cn>
2024-06-27 17:33:52 +08:00
SliverHorn 4ab50882a4 Merge pull request #1801 from jedyang/patch-1
业务路由的代码错误
2024-06-27 16:40:20 +08:00
yunsheng 06a07865f3 Update router_biz.go
privateGroup应该是切片的第一个。publicGroup应该是切片的第一个。
2024-06-27 15:02:11 +08:00
pixelMax(奇淼 5607702be9 fixed: 导出模板调整limit为指针 2024-06-27 14:57:57 +08:00
pixelMax(奇淼 e9be009f49 fixed: 导出模板调整limit为指针 2024-06-27 14:57:01 +08:00
pixelMax(奇淼 bb4e938bd2 fixed: 业务库导出问题调整 2024-06-27 10:20:44 +08:00
Wallandwall-js 45f723c07f feat: 调整自动化代码逻辑,重复创建的菜单和api需要用户手动取消自动创建 (#1798)
* feat: 调整自动化代码逻辑,重复创建的菜单和api需要用户手动取消自动创建

---------

Co-authored-by: wall-js <wall_js@foxmail.com>
2024-06-27 09:41:35 +08:00
pixelmaxQM 640f44fd10 fixed:修复左侧无法滚动的bug 2024-06-26 19:58:57 +08:00
Jupiterandhxl 821dd02aa4 feat: 优化布局结构 统一使用 drawer (#1796)
* sysDictionary.vue: perf 系统统一使用 drawer 抽屉 新增或编辑时form 取消校验

---------

Co-authored-by: hxl <52553624@qq.com>
2024-06-25 10:54:35 +08:00
pixelmaxQM 6e2140258e feature:后端路由注册和数据库注册方法与原始框架分离,自定业务不再干扰原始框架内容。 2024-06-23 17:01:39 +08:00
b628bd7769 调整配置文件默认灰度不生效问题 (#1795)
修复:在默认配置config.json文件修改灰色模式后,启动项目后不生效问题。

---------

Co-authored-by: zsc1003 <11476303+zsc1003@user.noreply.gitee.com>
Co-authored-by: Isaacedvr1003 <152384462+Isaacedvr1003@users.noreply.github.com>
2024-06-22 21:46:42 +08:00
pixelmaxQM f23cd22110 feature:增加静态目录public,调整在线logo地址到public。 2024-06-22 21:16:50 +08:00
PiexlMax(奇淼andSliverHorn 8ef4f408bf feat: 优化自动化代码结构,增加顶栏侧边栏组合式结构 (#1793)
* feature:增加顶栏组合模式。

* Update:
1. request.go.tpl and model.go.tpl indent problem
2. api.go.tpl, request.go.tpl, service.go.tpl struct {}

* Update:
1. model.go.tpl import blank line

* feature:增加顶栏组合模式。

* feature:增加左侧检测逻辑保证存在左侧菜单。

---------

Co-authored-by: SliverHorn <caiwei.lai@jutze.com.cn>
2024-06-21 21:03:47 +08:00
PiexlMax(奇淼 01139a2e6b Merge pull request #1792 from sliboy/main
chore(spell check): rename /server/utils/clamis.go to /server/utils/claims.go
2024-06-21 20:15:15 +08:00
pixelMax(奇淼 08606f740d feature: swagdoc调整 2024-06-21 14:59:30 +08:00
LiDahan 42c6bc11cc chore(spell check): rename clamis.go to claims.go 2024-06-21 09:50:49 +08:00
Wallandwall-js d6703e82e2 fixed: 修复自动化代码form模板,find接口调整未调整完全 (#1790)
Co-authored-by: wall-js <wall_js@foxmail.com>
2024-06-20 17:45:56 +08:00
Wallandwall-js 8f1692e394 fixed: 修复生成代码element-ui接口启用警告问题 (#1787)
* fixed: 修复生成代码element-ui接口启用警告问题

---------

Co-authored-by: wall-js <wall_js@foxmail.com>
2024-06-18 13:17:09 +08:00
pixelMax(奇淼 3e55234a24 feature: 可以选择不自动迁移表结构 2024-06-17 17:17:25 +08:00
pixelMax(奇淼 7df246c25a feature: 可以选择不自动迁移表结构 2024-06-17 17:15:15 +08:00
pixelMax(奇淼 fbffbce090 fixed:调整顶栏模式自动缩进bug 2024-06-17 15:15:28 +08:00
Juneyx 18e9b6d84c Fixed system.vue: 日志留存时间json key错误 (#1785)
后端对应的json key是retention-day
2024-06-16 23:33:59 +08:00
03e5bc515f v2.6.6版本发布 (#1784)
* 前端支持顶部菜单栏模式

* 自动化代码单条获取方法不再需要取data.xxx直接取用data

* 自动化代码支持选择索引

* 自动化代码回滚支持自行选择是否删除菜单、API、表

* 日志增加定期清理功能

* 权限配置API部分,支持根据API真实path进行筛选

* 修复了一些已知bug

* 修复了一个sql注入漏洞

---------

Co-authored-by: xuedinge <781408517@qq.com>
Co-authored-by: Qing Liang <106448173+xue-ding-e@users.noreply.github.com>
Co-authored-by: wall-js <wall_js@foxmail.com>
Co-authored-by: Wall <307606056@qq.com>
Co-authored-by: leooza <leooza@163.com>
Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: hxl <52553624@qq.com>
Co-authored-by: zsc1003 <11476303+zsc1003@user.noreply.gitee.com>
2024-06-16 00:27:40 +08:00
Juneyx b336529d42 添加通过点击展开/收起控制显示更多的查询条件的功能 (#1771)
* 给table.vue模板添加控制显示/隐藏更多查询条件的语句块和按钮

* sys_auto_code.go: 添加隐藏查询条件控制字段

* table.vue.tpl: 按照FieldSearchHide字段自动将隐藏的查询条件写到对应的代码块里

* fieldDialog.vue: 添加隐藏查询条件的控制开关

* 只有已经选择了查询条件的情况下才能选择
2024-06-12 23:33:19 +08:00
青菜白玉汤 bbf716b28e style(login): 优化登陆部分代码,提升可读性 (#1772) 2024-06-12 23:32:18 +08:00
pixelMax(奇淼 725f6fe3ec fixed: 自动化请求结构中不应该携带JSON 2024-06-11 14:33:44 +08:00
Dale f773a02ce0 [fixed] 优化错误判断 (#1762) 2024-06-07 11:17:25 +08:00
Deng 21266be1ed perf: 优化 api 和 service 中方法注释不正确的问题 (#1765) 2024-06-05 20:30:08 +08:00
pixelmaxQM 53d0338218 feature:修复已知安全问题。 2024-06-02 21:13:51 +08:00
pixelmaxQM 2f67c23c5c feature:在选择图片时候增加删除按钮,可以在媒体库中直接删除图片。 2024-06-02 20:50:55 +08:00
poppingkaka e64be755f9 优化如果join表时出现重复的字段或者需要有函数时可以导出别名的值 (#1761) 2024-05-31 10:45:39 +08:00
SliverHornandSliverHorn 23952c5f5f Update: (#1758)
1.config gorm相关移除DBBASE实现改为GeneralDB实现LogLevel函数
2.移除initializel/internal/logger实现,改为gorm_logger_writer实现gorm的logger通过zap输出到文件或者控制台
3.优化initializel/internal/gorm代码

Co-authored-by: SliverHorn <caiwei.lai@jutze.com.cn>
2024-05-27 10:24:19 +08:00
02fc5036d7 v2.6.5版本更新 (#1757)
* feature:增加资源加载loading

* feature:修正sql无法落盘的问题

* fixed: 修复切换角色出现404的问题。

* 删除selectImage.vue中chooseImg下多余的console.log(url)

---------

Co-authored-by: krank <emosick@qq.com>
Co-authored-by: Qing Liang <106448173+xue-ding-e@users.noreply.github.com>
2024-05-26 21:49:34 +08:00
a6a65ed9f4 fixed:修复自动化生成表格缺少的prop (#1755)
* fixed:修复自动化生成表格缺少的prop

---------

Co-authored-by: wall-js <liujun@grectronics.cn>
Co-authored-by: wall-js <wall_js@foxmail.com>
2024-05-26 21:24:33 +08:00
Wallandwall-js 369f657aa6 fixed:修复自动化代码无法识别json类型,去掉插件路由冗余代码 (#1751)
* fix(bug): [api.go.tpl]自动化代码swag路径冲突

---------

Co-authored-by: wall-js <liujun@grectronics.cn>
2024-05-22 16:56:55 +08:00
pixelmaxQM 1801e5b30f fixed:selectImage组件图片偏移的bug 2024-05-21 21:26:16 +08:00
pixelmaxQM b10d5103f3 fixed:selectImage组件重构 2024-05-20 22:07:45 +08:00
pixelmaxQM 9964bfef8b fixed:修复特殊符号下无法预览图片的bug 2024-05-20 21:08:32 +08:00
Juneyx 9945a19f2c state.vue: 修复展示多硬盘信息时无法上下滚动的bug (#1749) 2024-05-20 10:27:32 +08:00
pixelmaxQM a5d43e6f14 fixed:修复右上角focus-visible状态下会出现outline的bug 2024-05-18 23:11:28 +08:00
pixelmaxQM b61b9a06dd feature:增加首页插件推荐 2024-05-18 21:58:50 +08:00
pixelmaxQM f28570fa98 feature:新版树组件适配暗夜模式 2024-05-18 21:48:42 +08:00
Juneyx fb53d639be 添加展示多硬盘用量信息的功能 (#1747)
* featurel: 添加多磁盘用量信息展示
2024-05-18 11:52:44 +08:00
nonstop 42de9257c3 fixed: 修复文件分片上传在已选择文件的情况下,再次选择并取消出现控制台飘红且原文件清空的bug (#1746) 2024-05-18 11:48:28 +08:00
Wallandwall-js 0fba597a61 fixed:调整自动化代码swagger文档返回值类型 (#1742)
* fix(bug): [api.go.tpl]自动化代码swag路径冲突

* fixed:调整自动化代码swagger文档返回值类型

* fixed:修复RouterPrefix修改后不影响插件路由问题

---------

Co-authored-by: wall-js <liujun@grectronics.cn>
2024-05-17 16:22:16 +08:00
pixelMax(奇淼 d0393c4e9f fixed:调整前端打包的base路径,适配history模式路由。 2024-05-17 13:25:31 +08:00
pixelMax(奇淼 a21d2a591e feature:优化数据源字段和数组字段展示 2024-05-17 11:26:51 +08:00
pixelMax(奇淼 de54688c56 fixed:自动导入功能将根据表内字段自动创建created_at和updated_at的时间 2024-05-17 10:26:47 +08:00
pixelmaxQM 3c486d9117 feature:暗夜模式兼容调整,初始化需要手动写入初始密码。 2024-05-16 21:55:32 +08:00
pixelmaxQM e8128250f4 feature:暗夜模式兼容调整,初始化需要手动写入初始密码。 2024-05-16 21:49:56 +08:00
pixelmaxQM 58a1b72910 fixed:登录页面暗夜模式适配 2024-05-16 21:02:16 +08:00
SliverHornandSliverHorn ee00d29afd Update: (#1743)
1. 移除zap配置文件MaxAge字段
2. 重构自定义Cutter切分日志
3. 自定义ZapCore, 可实现根据fields自定义功能文件输出

Co-authored-by: SliverHorn <caiwei.lai@jutze.com.cn>
2024-05-16 18:21:30 +08:00
pixelMax(奇淼 5cfcc538a8 fixed:左侧菜单栏超长支持滚动 2024-05-16 15:22:21 +08:00
pixelmaxQM e7c8a9d420 feature:增加自动化代码页面暂时存储功能 2024-05-15 21:40:36 +08:00
pixelmaxQM 6b07ffe8f7 feature:增加数据源一对多关系。 2024-05-15 21:26:32 +08:00
pixelmaxQM 0d17340445 feature:增加数据源一对多关系。 2024-05-15 21:15:41 +08:00
pixelMax(奇淼 2a0b92713b fixed:兼容旧自动化数据 2024-05-15 10:50:22 +08:00
pixelMax(奇淼 fb22eb4178 fixed:修复生成json类文件关闭弹窗后再开启的错误 2024-05-14 15:29:34 +08:00
pixelMax(奇淼 136fb2f394 fixed:修复更新api失败的bug 2024-05-14 12:45:33 +08:00
pixelMax(奇淼 c515805f0a fixed:表格增加左右-1px的边距,防止表格边框线导致宽度超出页面从而无限延伸的bug。 2024-05-14 10:44:36 +08:00
PiexlMax(奇淼 613ba9ba20 Update README-en.md 2024-05-11 11:30:12 +08:00
PiexlMax(奇淼 f6314d3581 Update README.md 2024-05-11 11:29:51 +08:00
pixelmaxQM 043f5c78c2 feature:调整autoPackage弹窗 2024-05-10 21:28:53 +08:00
pixelMax(奇淼 0f9e519b0e feature:调整侧边栏暗夜模式的hover错误 2024-05-10 15:17:04 +08:00
PiexlMax(奇淼 0d17a2351f Update ci.yaml 2024-05-10 14:34:21 +08:00
pixelMax(奇淼 1b388664cb feature:水印密集度调整 2024-05-10 13:16:06 +08:00
pixelMax(奇淼 1edb0c529f feature:调整bottomInfo组件位置 2024-05-10 13:05:36 +08:00
pixelMax(奇淼 f07a58bff4 feature:readme版权相关文案调整 2024-05-10 11:18:48 +08:00
pixelMax(奇淼 c054840aec feature:上线前细节数据调整 2024-05-10 11:15:38 +08:00
PiexlMax(奇淼 e259418398 Update README.md 2024-05-09 21:42:11 +08:00
PiexlMax(奇淼andbypanghu df1d68a724 新版前端UI,预发布2.6.4版本。 (#1735)
* fix: 修改 layout 中相关 emit 和 重复声明的 theme ,采用最新的vue api

* fix:修改 eslintrc 的配置文件,删除大多数无用配置

* fix: 修复 layout 切换手机样式模糊层的 bug

* feature: 重构 layout , 添加暗黑模式 , 删除侧边栏颜色

* fix:细节调整,activeColor摘除。

* feature:右侧滚动模式调整

* feature:无用代码剔除

* fix: 修复暗黑模式相关细节

* fix: custome config layout

* feature:样式细节调整

* fix: 增加前端样式配置文件

* feature:调整基础配置,增加表格边框

* feature:buttomInfo取消底色,a标签更改为活跃色

* feature:调整阴影颜色和配置同步

* feature:版本调整2.6.3==>2.6.4

---------

Co-authored-by: bypanghu <bypanghu@163.com>
2024-05-09 21:35:39 +08:00
Wallandwall-js 9d58390e11 fix(bug): [api.go.tpl]自动化代码swag路径冲突 (#1732)
Co-authored-by: wall-js <liujun@grectronics.cn>
2024-05-09 11:48:15 +08:00
pixelMax(奇淼 db4c7a8bda fixed:修复富文本无法编辑的bug 2024-05-09 10:12:20 +08:00
PiexlMax(奇淼 ab163fc0ef Update ci.yaml 2024-05-06 21:20:20 +08:00
pixelmaxQM 0265801830 fixed:表格模板删除查看详情功能。 2024-05-06 21:15:37 +08:00
pixelmaxQM 5fa7bbbc0f fixed:导出模板顺序一致性调整 2024-05-06 21:10:01 +08:00
PiexlMax(奇淼 e15351e1c5 Update README.md 2024-04-29 17:10:22 +08:00
pixelmaxQM 5eb0133b5c feature:升级后端依赖,前端代码调优 2024-04-28 22:05:50 +08:00
pixelmaxQM ff8344d671 feature:自动化代码增加数据源配置功能 2024-04-27 21:48:24 +08:00
pixelmaxQM d9a43ea1d6 feature:自动化代码增加数据源配置功能 2024-04-27 21:35:29 +08:00
pixelmaxQM 6c62d73afb feature:v2.6.3发布 2024-04-27 17:16:42 +08:00
pixelmaxQM d23d6c342a feature:自动化增加前端可控显隐。 2024-04-25 21:13:55 +08:00
pixelmaxQM 90549a09e1 feature:自动化增加前端可控显隐和自定义class。 2024-04-25 21:02:43 +08:00
pixelmaxQM 17d3639443 feature:优化api代码逻辑,调整pgsql下 more than once的bug。 2024-04-23 21:13:09 +08:00
pixelmaxQM e8a096b8fe feature:调整Update方法,不再使用save全量更新。 2024-04-23 20:56:30 +08:00
pixelmaxQM fea136e513 fixed:修改agent的数据库存储方式,防止日志过长存储失败。 2024-04-23 20:43:50 +08:00
pixelMax(奇淼 f3a4095462 增加丢失的vue-router 2024-04-23 14:45:56 +08:00
pixelmaxQM d7d25cf69b feature:调整抽屉的title属性,消除warning 2024-04-22 22:14:25 +08:00
pixelmaxQM 3b33fe83e6 feature:代码生成器可拖拽行,修复pgsql从库创建代码的bug,增加默认值属性。 2024-04-22 22:04:29 +08:00
pixelmaxQM 56f4d223ab fixed:适配pgsql编辑菜单触发 more than once的bug 2024-04-22 20:59:15 +08:00
pixelMax(奇淼 c07317a619 调整openDocument 2024-04-17 10:39:55 +08:00
Qing Liang 4798f7688b 点击跳转代码插件修复websotrm bug (#1715) 2024-04-17 10:35:32 +08:00
pixelmaxQM 24db0eb5aa fixed:切换角色功能适配新版gorm 2024-04-14 23:43:21 +08:00
Haoran Wu 1ece13c43d sys_export_template.go: 修复导入Excel时前几条为空数据的问题 (#1713) 2024-04-14 21:03:44 +08:00
pixelmaxQM 48268309b9 fixed:回滚时候自动清理掉router下空的作用域 2024-04-14 21:02:35 +08:00
4074a52b1b 修复pgsql和数据库导入bug,增加默认mod中的datatypes (#1712)
* 多文件: fix error specified more than once in PG

* Update sys_authority.go

* Update sys_authority.go

* sys_export_template.go: 导入Excel时使用批量插入提高性能

* 添加gorm.io/datatypes

---------

Co-authored-by: crazyrunsnail <fjyuan1991@163.com>
Co-authored-by: XiMo-210 <2831802697@qq.com>
2024-04-13 18:46:58 +08:00
pixelMax(奇淼 61dd524c26 fixed:修复根目录为O的错误 2024-04-12 14:54:28 +08:00
pixelMax(奇淼 61a678a318 调整无法创建根菜单的bug 2024-04-12 14:47:16 +08:00
pixelmaxQM 8ecec6a14f Merge branch 'fixed_menu'
# Conflicts:
#	server/service/system/sys_base_menu.go
#	web/src/view/superAdmin/menu/menu.vue
2024-04-11 21:27:44 +08:00
PiexlMax(奇淼andcrazyrunsnail e3f8b8a394 fixed:菜单删除功能细节调优 (#1705)
* 多文件: 菜单parentId由string改成uint

* sys_base_menu.go: fix table name "sys_base_menus" specified more than once (SQLSTATE 42712) (#1704)

---------

Co-authored-by: crazyrunsnail <fjyuan1991@163.com>
2024-04-11 21:17:49 +08:00
pixelmaxQM eebddbafcc feature:调整菜单删除逻辑 2024-04-11 21:15:35 +08:00
PiexlMax(奇淼 50cbce0f7a Merge pull request #1702 from crazyrunsnail/fix-model-idtype
多文件: 菜单parentId由string改成uint
2024-04-11 20:56:07 +08:00
fakedavid f9974a8971 sys_base_menu.go: fix table name "sys_base_menus" specified more than once (SQLSTATE 42712) (#1704) 2024-04-11 20:55:46 +08:00
crazyrunsnail baa48a1679 多文件: 菜单parentId由string改成uint 2024-04-11 16:38:09 +08:00
pixelmaxQM 032910f87a feature:插件自动化添加自动注册菜单和api的模板供给修改 2024-04-10 21:48:20 +08:00
pixelmaxQM 773ef95b70 feature:增加插件自动化的前端功能页面 后端api生成自动添加一个开放的接口示例 2024-04-10 21:24:46 +08:00
pixelmaxQM 18c2f84771 feature:表格导出功能增加join支持多表关联导出 2024-04-09 22:05:12 +08:00
pixelmaxQM ea721a71b5 feature:防止自动化代码中的路径穿越 2024-04-09 21:09:01 +08:00
pixelMax(奇淼 b1b7427c6e fixed:修复GHSA-gv3w-m57p-3wc4 2024-04-09 18:09:09 +08:00
pixelmaxQM 7bc7c30510 fixed:#1695 对资源属性进行检测 2024-04-07 21:35:40 +08:00
pixelmaxQM d1e055430d feature:前端自动化增加分包 2024-04-07 21:20:27 +08:00
pixelmaxQM 736534379a fixed:字典限制仅字符串模式可选择 2024-04-07 20:40:02 +08:00
pixelMax(奇淼 f6b71e157c fixed:升级postgres的驱动到1.5.7 2024-04-07 10:16:51 +08:00
ShuBo6 53e9f931f2 fix: 应该调用filepath.Ext的地方调用了path.Ext (#1696)
* fix: 应该调用filepath.Ext的地方调用了path.Ext

* fix: typo
2024-04-03 16:25:09 +08:00
PiexlMax(奇淼 c226a9476f Merge pull request #1694 from xue-ding-e/main
增加redis集群设置
2024-03-31 17:51:56 +08:00
pixelmaxQM 8ca5600286 feature: 修改版本号发布v2.6.2 2024-03-31 17:50:07 +08:00
薛定饿了不养喵 9729bc00a0 删掉了不必要的增加(就是之前说的那个样式bug其实不是bug)
style="width:194px"
2024-03-31 03:58:55 +08:00
xuedinge f9c9af8261 增加redis集群连接方式 2024-03-31 01:15:20 +08:00
薛定饿了不养喵 c9e64373fb Merge branch 'flipped-aurora:main' into main 2024-03-31 00:33:51 +08:00
pixelmaxQM 262febf486 feature:增加API导入导出,方便填写录入,暂时屏蔽自动书写导入的创建时间的功能,等待gorm合并pr后恢复。 2024-03-30 20:54:34 +08:00
pixelmaxQM eca9c4d7f8 fixed:#1692 统一前端操作模式 2024-03-29 20:53:19 +08:00
薛定饿了不养喵 a20083bb9c Merge branch 'flipped-aurora:main' into main 2024-03-28 01:59:21 +08:00
piexlMax d31b01415b feature:自动化代码支持基础菜单创建 2024-03-27 21:18:34 +08:00
piexlMax 26cdb472f0 feature:自动创建基本菜单 2024-03-27 20:55:03 +08:00
pixelMax(奇淼 3c2595aaf9 feature:调整jwt令牌过期展现形式和返回错误编码形式,方便用户重新登录和知晓错误原因。 2024-03-27 17:35:24 +08:00
PiexlMax(奇淼 ad323a0dff Update config.js 2024-03-27 16:48:22 +08:00
PiexlMax(奇淼 9a0417b1a7 Update server.go 2024-03-27 16:47:59 +08:00
PiexlMax(奇淼 3324a816ee Update README.md 2024-03-27 16:47:32 +08:00
piexlmax(奇淼 cc4135a2d7 feature:禁止选中角色的子以及后代节点 2024-03-27 10:45:19 +08:00
piexlmax(奇淼 2d884c83cc feature:调整jwt续期功能,保证新的token返回和一致性 2024-03-27 10:39:19 +08:00
piexlmax(奇淼 619c5b5e1d feature:消除icon缓存 2024-03-27 10:11:19 +08:00
傅鹏 33afa9adfc feat: ignore go debug bin file (#1687)
* fix: k8s cpu num

* feat: ignore go debug bin file
2024-03-25 13:38:40 +08:00
CC11001100 0c141cc6f7 fix: 应该调用filepath.Join的地方调用了path.Join (#1688) 2024-03-25 13:38:22 +08:00
傅鹏 efdff2ab0c fix: k8s cpu num (#1685) 2024-03-21 10:16:06 +08:00
hooraymanand胡浩 ebefb0eba4 feat: docker-compose healthz check (#1680)
Co-authored-by: 胡浩 <huhao@anesec.cn>
2024-03-20 15:08:39 +08:00
奇淼(piexlmax d4b9c2c97b loading增加定制属性,可自行配置 (#1683)
* feature:增加区域loading功能

* feature:增加修改loading配置
2024-03-20 10:44:21 +08:00
piexlMax d4db16b501 增加json model模板 2024-03-18 22:32:14 +08:00
piexlMax a5cbd7387b feature:#1647 自动化代码支持纯json 2024-03-18 22:25:50 +08:00
piexlMax 99d6b4a361 feature:#1671调整字典的value属性为string 自动化模板随改 2024-03-18 21:44:14 +08:00
piexlMax 18365689e6 调整字典的value属性为string 不再限制为int 2024-03-18 21:23:53 +08:00
piexlMax 8ea827412a 同步清理前端timer配置 2024-03-17 12:52:57 +08:00
piexlMax 4d8979c4ad 调整抽屉框格式 2024-03-16 00:29:03 +08:00
piexlMax 236357baa8 调整自动化代码的新增,编辑,删除为抽屉模式 2024-03-16 00:22:36 +08:00
piexlMax 5ef4b21858 增加表格导出多数据库支持 2024-03-15 23:22:20 +08:00
piexlmax(奇淼 3b3441851c feature:保证存在GVA默认结构的表格导入自动填充created和updated 2024-03-15 14:55:20 +08:00
piexlmax(奇淼 5517987e14 feature:保证表格导出的列顺序和json录入顺序一致 2024-03-15 11:38:34 +08:00
奇淼(piexlmax 7e98f61bec Revert "fix:保证excel每次导出列顺序一致 (#1677)" (#1678)
This reverts commit e2d360e8b1.
2024-03-15 11:23:21 +08:00
e2d360e8b1 fix:保证excel每次导出列顺序一致 (#1677)
* fix:保证excel每次导出列顺序一致

* Update sys_export_template.go

---------

Co-authored-by: Li vito <vito.li@shopee.com>
Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2024-03-15 11:16:24 +08:00
piexlmax(奇淼 57cfedfd7c typo修复,正则字符串修复 2024-03-14 14:50:41 +08:00
piexlMax 50b1d21d13 调整删除方法 放弃使用el-popover 删除操作使用弹窗提示 2024-03-13 22:37:07 +08:00
Alex Lin 7b79ec6c66 fixed: api管理中的 popover 触发改为 click (#1673) 2024-03-13 20:14:27 +08:00
piexlmax(奇淼 7a5b31530f 清理错误提交的测试代码 2024-03-13 16:25:01 +08:00
piexlmax(奇淼 e9100a9542 替换v-model API 为 defineModel 2024-03-13 15:17:57 +08:00
piexlmax(奇淼 421304d4a3 提升最低VUE版本至3.4.x 2024-03-13 14:49:28 +08:00
piexlMax 10d61bbbb3 导出功能可传入limit、offset和order,优先级高于默认配置 2024-03-12 21:08:25 +08:00
piexlmax(奇淼 095709fb19 fixed:退出只清理特定的localStorage 不再进行全部清理操作 2024-03-11 11:47:59 +08:00
piexlMax 725f4150fc 统一调整element form inline元素的属性 2024-03-07 22:35:02 +08:00
andywu1998 93ac2e70d2 feat(gin.Mode()): 由环境变量决定,不再依赖于配置文件system.Env (#1668)
* feat(gin.Mode()): 由环境变量决定,不再依赖于配置文件system.Env

* feat(casbin):不需要判断是否是debug模式,都要附带参数

* feat(前端配置):去掉环境之的配置
2024-03-06 23:38:17 +08:00
andywu1998 f4c2b50ca5 feat(config init log): modify constant value GIN_MODE to gin.Mode() (#1667) 2024-03-06 22:32:42 +08:00
piexlMax 3354edbb1c 在初始化时候添加excelTemplate的关联表 2024-03-06 22:22:27 +08:00
piexlMax d3600499af fixed:剔除错误提交的测试用代码 2024-03-06 00:19:17 +08:00
奇淼(piexlmax 35e2c2cfe8 feature:表格导出支持配置limit order和where条件 (#1665)
* feature:导出功能可携带条件

* feature:组件增加导出入参

* 带条件导出Excel功能
2024-03-05 23:29:59 +08:00
piexlmax(奇淼 1e4970469f publish:调整版本号v2.6.1 2024-03-04 17:06:34 +08:00
piexlMax 4cbfd7c9b1 消除el-descriptions的warning 2024-03-03 17:35:38 +08:00
piexlmax(奇淼 deb32fa0fa fixed:#1659 调整table中sort驼峰对应不到数据库字段的问题 2024-03-01 11:04:52 +08:00
piexlmax(奇淼 f17a738780 fix:switchTab,query=>params。 2024-03-01 10:04:18 +08:00
piexlmax(奇淼 2f53d0efae feat:增加全局订阅switchTab,用户可以给tab添加参数跳转且不打开新tab。 2024-02-29 18:06:29 +08:00
piexlmax(奇淼 3e43c2e6e6 type:限=>线 2024-02-29 16:34:53 +08:00
piexlmax(奇淼 96919a9f79 fix:取消重复方法 2024-02-29 16:34:08 +08:00
piexlmax(奇淼 a23fb627cd feat:#1658 增加全局订阅 setQuery 用户可以动态变更当前页query而不产生新的tab 2024-02-29 16:32:09 +08:00
Leo Wang aae915b092 fix: 解决build时,会有浏览器缓存问题。 (#1661) 2024-02-29 16:26:45 +08:00
Leo Wangand奇淼(piexlmax 160c8e814b bugfix:修复新增菜单强制默认icon的bug;修复production环境变量容易造成困惑的问题; (#1660)
* fix: 解决每次新增菜单时,默认都会选中第一个aim图标的问题

* fix: 修订production的环境变量,去除那些在生产环境会造成困惑的项目

* Update .env.production

合理性调整

---------

Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2024-02-29 16:18:07 +08:00
piexlmax(奇淼 88f48baba1 feat:#1658 增加全局订阅 setQuery 用户可以动态变更当前页query而不产生新的tab 2024-02-29 16:08:36 +08:00
piexlMax 7835efbf37 调整自动化代码模板的格式 2024-02-26 23:09:51 +08:00
shan_lu 455fbb505e fix the word spelling error for acitveAxios (#1655) 2024-02-23 11:31:15 +08:00
ipanghuand陶正虎 df3f7090e8 fix:修改操作记录中间件,文件类型统一记录为[文件] (#1656)
Co-authored-by: 陶正虎 <zhenghu.tao@jutze.com.cn>
2024-02-23 11:30:52 +08:00
piexlmax(奇淼 632b3c200c 调整cookie写入方法 2024-02-22 13:43:53 +08:00
piexlmax(奇淼 5b203326ae 清理文本输出之前的sleep 2024-02-21 17:44:25 +08:00
piexlMax fd87aca57d 前端跟随增加cookie管理方法,防止后端无法设置cookie的情况下导致的某些功能不可用问题。 2024-02-20 16:06:08 +08:00
piexlMax b9b7e556e3 修复表格导出和模板导出的bug 2024-02-20 15:06:17 +08:00
piexlmax(奇淼 5b9a7e6a2a 调整mssql自动化 2024-02-19 10:48:38 +08:00
rightSun d278e19367 dictionary.js update 优化字典文字展示方法 (#1652)
优化字典文字展示方法
新增可配置的参数 keyCode 和valueCode 使用字典字段更加灵活
2024-02-07 17:40:01 +08:00
piexlmax(奇淼 342030ca47 Merge remote-tracking branch 'origin/main' 2024-02-04 17:47:43 +08:00
piexlmax(奇淼 f90e241cc9 调整mssql初始化 2024-02-04 17:47:30 +08:00
lenandwangshenglei ff6bcc437c [Bug]:修复使用页面内按钮权限不生效问题 (#1621)
Co-authored-by: wangshenglei <wangshenglei@zhuanzhuan.com>
2024-02-04 11:36:06 +08:00
G-XD e32dbb5125 fix: 更新api路径时使用binary区分大小写进行查询 (#1645)
* fix: 更新api路径时使用`binary`区分大小写进行查询

* fix: 修改相同api路径判断逻辑
2024-02-04 11:35:45 +08:00
Sonui 06701cc7d1 fix(Server): 静态资源目录错误 (#1648) 2024-02-04 11:33:29 +08:00
piexlMax ccb31bc1b4 调整静态文件读取 防止文件目录暴露 2024-01-30 23:33:38 +08:00
myface-wang 7e2e29e2e8 Update svgIcon.vue (#1642)
删除不必要的导入,defineProps
2024-01-30 22:56:02 +08:00
piexlMax 0c76995f6d 修复菜单select展示的bug 2024-01-30 22:43:22 +08:00
piexlMax 17cab8fcb7 更换版本号 2024-01-28 16:40:08 +08:00
Krane d64753859d 解决drawer和dialog层级冲突问题 (#1640) 2024-01-26 14:35:54 +08:00
piexlMax 48b1c24c95 [fixed]:修复超出26个英文字母后表格的导出导入bug 2024-01-25 19:41:52 +08:00
piexlmax(奇淼 7e5e12b139 前端dist代码位置变更 2024-01-25 16:14:28 +08:00
59ba4752c0 [server/config/system.go]: fix a comment error (#1638)
Co-authored-by: liweiwu.wlw <liweiwu.wlw@xiaoman.cn>
Co-authored-by: 奇淼(piexlmax <303176530@qq.com>
2024-01-24 16:01:36 +08:00
piexlmax(奇淼 189219c673 typo修复 2024-01-24 15:59:02 +08:00
piexlmax(奇淼 4b54262edd Merge remote-tracking branch 'origin/main' 2024-01-24 15:50:37 +08:00
piexlmax(奇淼 458b035a7e 增加字典方法 GetDictionaryList,GetDictionaryListByType,GetDictionaryInfoByValue, GetDictionaryInfoByTypeValue 方便后台直接获取字典属性
前端增加extend属性获取
2024-01-24 15:50:15 +08:00
piexlmax(奇淼 abe85cf6e7 增加字典方法 GetDictionaryList,GetDictionaryListByType,GetDictionaryInfoByValue, GetDictionaryInfoByTypeValue 方便后台直接获取字典属性
前端增加extend属性获取
2024-01-24 15:50:14 +08:00
奇淼(piexlmax 379b63275a 自动化代码可选不使用官方global.Model结构 (#1637)
* 自动化代码可自行选择默认结构

* 调整自动化模板

* 增加自动化模板中对timer的处理
2024-01-22 17:37:03 +08:00
yunshengand01471076 07cde689b1 mongo use auth-source (#1635)
Co-authored-by: 01471076 <yangyunsheng.it@haier.com>
2024-01-20 12:33:27 +08:00
薛定饿了不养喵 26606f138d 修改样式 系统工具 -> 代码生成器 下的 '点这里从现有数据库创建代码' 内容显示不全 (#1632) 2024-01-20 12:33:10 +08:00
haimait 24c4774f7e 代码打包的插件,从后台安装失败,认不到目录的问题 (#1634)
https://github.com/flipped-aurora/gin-vue-admin/issues/1633
2024-01-20 12:32:59 +08:00
xuedinge 6bbb4f577e 修改样式 系统工具 -> 代码生成器 下的 '点这里从现有数据库创建代码' 内容显示不全 2024-01-18 18:48:47 +08:00
piexlMax(奇淼 4890de5052 Merge remote-tracking branch 'upstream/main' 2024-01-18 13:16:52 +08:00
haimait 746af37899 解决打包插件解压报错的问题 (#1630)
https://github.com/flipped-aurora/gin-vue-admin/issues/1628
2024-01-18 13:16:39 +08:00
haimait 0136ce7034 解决打包插件解压报错的问题 (#1630)
https://github.com/flipped-aurora/gin-vue-admin/issues/1628
2024-01-18 13:11:54 +08:00
piexlMax(奇淼 5ca47a91a6 开发环境允许设置cookie 2024-01-18 13:08:14 +08:00
piexlMax(奇淼 d849df41be 代码定位功能默认关闭。 2024-01-17 16:05:32 +08:00
奇淼(piexlmax a2269bcdd5 优化自定义图标功能,修复上线后无法展示自定义图标的问题。 (#1625)
* 修改自定义图标使用方式

* 优化自定义icon功能
2024-01-16 22:07:59 +08:00
ipanghu d41394c70a fix:修复首页 dashboard echarts 页面变化导致的变性, 修复 vite.config.js 中 proxy 代理 https 时的 bug (#1623)
add : 添加 “@vueuse/core” 的依赖,添加全局 hooks (use-windows-resize)使用方法查看 dashboard 页面
2024-01-15 13:10:42 +08:00
haimait 756f73bbd2 修复代码生成器 列表中数据库字段描述回显错误 (#1622) 2024-01-15 13:10:24 +08:00
piexlMax 95eb17b6d1 [fixed]:默认注释静态资源 2024-01-13 12:38:07 +08:00
piexlMax 773fd1f221 Merge remote-tracking branch 'origin/main' 2024-01-13 12:09:49 +08:00
piexlMax c95b436680 [fixed]:静态资源基础path修复 2024-01-13 12:08:37 +08:00
piexlmax(奇淼 3f47151678 默认增加 gorm.io/datatypes 2024-01-11 15:57:20 +08:00
piexlmax(奇淼 dbf1e7136c 调整更换绑定后的自动化代码结构 2024-01-11 15:56:38 +08:00
piexlMax 84b44eef91 [fixed]:调整过期token更换new-token时间,防止多机操作业务延迟带来的token失效的bug 2024-01-08 21:50:25 +08:00
piexlMax 686ada1e49 [fixed]:调整自动化表格TemplateInfo字段类型为text防止超长 2024-01-08 19:55:21 +08:00
piexlmax(奇淼 d9f6bc058a 调整自动化验证为gin自带binding tag 2024-01-08 16:45:19 +08:00
piexlMax 6f531793f0 清理错误添加的测试代码 2024-01-06 17:26:39 +08:00
piexlMax f8794bef5f 导入导出功能性bug修复 2024-01-06 16:16:50 +08:00
piexlMax 9daf103669 增加导入成功回调 2024-01-05 23:27:59 +08:00
piexlMax 26fa047fe4 基于cookie模式下,剔除所有的上传文件的x-token头 2024-01-05 23:13:04 +08:00
piexlMax 1a04bb535d 增加表格导入,增加导入模板下载,修复日志中间件的截断bug。 2024-01-05 23:09:07 +08:00
piexlMax ad41b7b434 [fixed]:初始化添加自动导出功能表 2024-01-05 21:28:57 +08:00
piexlMax 6791b1dbdc [fixed]:修复切换角色不生效的bug 2024-01-05 20:11:16 +08:00
piexlMax dc1b84130c 完善cookie模式 2024-01-04 22:25:13 +08:00
piexlMax e70a933090 完善cookie模式 2024-01-04 22:21:37 +08:00
piexlMax 08617f2fd4 完善cookie模式 2024-01-04 22:15:54 +08:00
thy 8aefb5db8e feat: 开启recovery (#1615) 2024-01-04 17:06:52 +08:00
piexlMax(奇淼 e1d214b91a 剔除GPT相关功能,后续独立新开源项目制作。 2024-01-03 14:49:28 +08:00
奇淼(piexlmax 0285de50e5 修复#1611提及的反引号导致pgsql搜索不支持的bug (#1612) 2024-01-03 11:21:08 +08:00
piexlmax(奇淼 5f7caa0535 降低自定义button圆角权重 2024-01-02 17:23:34 +08:00
piexlMax df9d2bc472 消除误提交的测试代码 2023-12-31 20:22:47 +08:00
piexlMax a923b6beca 更新版本号2.5.9 2023-12-31 11:09:00 +08:00
piexlMax 760ef77593 消除误提交的测试代码 2023-12-30 20:49:24 +08:00
piexlMax 64f703856e 调整初始化信息 2023-12-30 20:42:24 +08:00
piexlMax 36eba36bf2 调整建表结构 2023-12-30 20:32:05 +08:00
piexlMax 332176a619 增加新功能初始化数据 2023-12-30 20:29:49 +08:00
piexlMax cd5b60c8cc 增加excel模板配置,增加前端导出工具。token迁移至cookie x-token且保留header x-token 两者兼容。 2023-12-30 20:29:47 +08:00
thy 5ea8947fc9 feat: 将placeholder替换为tooltip (#1606) 2023-12-28 09:55:32 +08:00
piexlmax(奇淼 474a5c8e42 清理RemoveTaskByName的重复锁导致系统卡死的问题 2023-12-26 09:53:26 +08:00
piexlMax 952062d5be 调整弹出气泡无法取消的bug 2023-12-25 22:04:27 +08:00
奇淼(piexlmax c071564de4 Update ci.yaml 2023-12-25 10:26:50 +08:00
huoxiao b2fa7563d3 web/src/view/routerHolder.vue:Fix Vue warn Component inside <Transition> renders non-element root node that cannot be animated (#1603) 2023-12-25 09:53:45 +08:00
piexlmax(奇淼 22f68fedcb swag文档默认属性调整 2023-12-22 10:27:51 +08:00
奇淼(piexlmax 0a4cda26cb Update README.md 2023-12-22 10:19:21 +08:00
piexlmax(奇淼 54eb84e690 将task拆分为cron与task两部分,使其呈现父子结构,切单独可控。 2023-12-22 10:08:54 +08:00
piexlmax(奇淼 5cd33814fc 将task拆分为cron与task两部分,使其呈现父子结构,切单独可控。 2023-12-22 09:55:57 +08:00
奇淼(piexlmax 90f19679e7 Update README.md 2023-12-19 17:26:43 +08:00
奇淼(piexlmax 38ade9e498 Update go.mod 2023-12-19 17:26:07 +08:00
faker-wang 4c77831001 zapcore.WarnLevel修改成zapcore.ErrorLevel (#1602) 2023-12-19 17:17:02 +08:00
piexlMax 722fe556e3 增加初始字典内容,兼容自动化使用pgsql读取表的数据格式 2023-12-17 17:40:00 +08:00
xinyan818 98b83c0078 fix: typo (#1591) 2023-12-13 15:01:35 +08:00
yang hao 85646b5ffa sys_auto_code fix: log文字提示错误 (#1592) 2023-12-13 15:01:19 +08:00
Zmzblink d3f5ed7d60 修改el-tag中type属性的默认值, type属性枚举不包含primary (#1593) 2023-12-13 15:01:02 +08:00
piexlmax(奇淼 e0a8e93704 定位功能调整为 shift+alt+左键 2023-12-12 10:50:23 +08:00
piexlmax(奇淼 3aab5e9eb7 路由增加meta.client 属性,添加本属性为true则跳过前端路由拦截器 2023-12-11 16:28:40 +08:00
piexlMax 2307ac88cb 对不合法名称icon做检测停止加入图标库 2023-12-10 23:47:30 +08:00
piexlMax 0f2018d913 增加自动icon功能,所有添加到web/assets/icons下的svg会自动被注册为icon组件使用【可用于menu和直接用标签加文件名使用】 2023-12-10 23:30:39 +08:00
piexlMax 8b9a75ba5a 清除ast中无用的测试用例 2023-12-06 23:06:43 +08:00
SliverHorn 7872e0ce38 Update: 修复mongodb index默认name太长而导致创建索引失败, 在组装keys数据进行排序以便符合bson.M的构造 (#1580) 2023-12-05 23:04:23 +08:00
xinyan818 d28ac73987 fix: use db list (#1588) 2023-12-05 23:03:54 +08:00
ning2510 2c8c7a8b51 Update ast_gorm_test.go (#1587) 2023-12-05 23:01:50 +08:00
奇淼(piexlmaxandyang hao f98fc6bf3c swag中id错误问题的修复 (#1589)
* model.go: fix swagger请求的id问题

* 验证码逻辑修回

---------

Co-authored-by: yang hao <1013055366@qq.com>
2023-12-05 23:01:27 +08:00
奇淼(piexlmax d42958734f 清理掉定时任务config配置,修改为代码内书写 (#1584) 2023-12-04 22:12:01 +08:00
piexlMax 6f2c785713 调整为新的timer模式 增加每个task内具体方法的描述方便对接后续的页面控制 2023-12-04 22:12:01 +08:00
奇淼(piexlmax 05a1ce51f0 清理掉定时任务config配置,修改为代码内书写 (#1584) 2023-12-04 22:05:19 +08:00
piexlMax(奇淼 58b063770d 调整swag 2023-12-01 14:42:54 +08:00
Sun Dadiand奇淼(piexlmax 6f9a83709d [selectImage.vue]: 增加selectImage组件,最多上传图片的功能 (#1568)
* 增加selectImage组件,最多上传图片的功能

* 增加selectImage组件,最多上传图片的功能

* Update config.yaml

* Update config.yaml

---------

Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2023-11-21 22:54:39 +08:00
奇淼(piexlmax bd2a3ddfba 清理掉定时任务config配置,修改为代码内书写 (#1578) 2023-11-20 23:38:15 +08:00
SliverHorn 4433b6623e Merge pull request #1577 from flipped-aurora/transaction
[feature]:调整角色的创建,删除操作为事务模式
2023-11-19 14:17:30 +08:00
piexlMax e1ca17637f casbin相关操作修改为事务 2023-11-19 11:50:30 +08:00
ZongQiangandzongqiang 5ef0e43312 缺少事务可能出现数据不一致风险 (#1575)
Co-authored-by: zongqiang <zongq@rp-pet.cn>
2023-11-18 22:20:26 +08:00
aa6ca95f13 初始化失败panic (#1573)
* 初始化失败panic

* Update gorm_mssql.go

* Update gorm_pgsql.go

* Update gorm_mysql.go

---------

Co-authored-by: zongqiang <zongq@rp-pet.cn>
Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2023-11-18 21:01:44 +08:00
奇淼(piexlmax 2523467c97 Update LICENSE 2023-11-15 16:31:51 +08:00
奇淼(piexlmax b38eb6709e Update README.md 2023-11-14 10:38:25 +08:00
piexlMax(奇淼 f6dacdb046 优化自动化模板,防止按钮被折叠 2023-11-13 11:03:51 +08:00
piexlMax(奇淼 cc0903f74d 调整表格的适配性 2023-11-13 10:53:30 +08:00
piexlMax(奇淼 72936fc0d1 版权信息不再和appName绑定 2023-11-07 14:48:22 +08:00
SliverHorn 4b7f552885 Merge pull request #1569 from 729343861/main
web/src/view/systemTools/system/system.vue : fix 图形验证码配置 bug
2023-11-06 11:25:17 +08:00
729343861 9b2fc60d79 web/src/view/systemTools/system/system.vue : fix 图形验证码配置 bug 2023-11-06 11:09:12 +08:00
piexlMax 3e5a26b95a 修改开发环境的中间件 2023-11-04 21:48:01 +08:00
SliverHorn a5f3139784 fixed: deploy/docker/Dockerfile #1518 (#1567) 2023-10-31 17:52:38 +08:00
piexlMax 9ca9fcdb09 SelectFile组件建议添加limit和accept属性,控制文件的上传数量和类型 2023-10-26 22:41:37 +08:00
piexlMax 913db35b23 添加分配菜单和分配api的滚动条 2023-10-26 22:26:04 +08:00
piexlMax(奇淼 8eba3ba4f7 修复字典展示bug
修复自动化代码字典类型渲染bug
2023-10-25 17:14:09 +08:00
piexlMax(奇淼 5bd0f24a84 增加package为空判断 #1564
Co-authored-by: @saikey0379
2023-10-24 18:42:50 +08:00
piexlMax e8fb3180db 字典使用模式调整 2023-10-22 20:59:47 +08:00
SliverHorn 232aaad090 feature: mongoDB 支持 (#1565)
* feature: mongoDB 支持

* update: 修改错误mongo索引示例

* update: 在system添加use-mongo 开关开启或者关闭mongo
2023-10-14 13:59:30 +08:00
piexlMax(奇淼 b3dbb8d4be 解决打包错误的bug 2023-10-10 18:57:46 +08:00
piexlMax(奇淼 3caf070056 优化打包 2023-10-10 18:52:39 +08:00
piexlMax(奇淼 1e24bbc3e2 修复UI BUG #1562 2023-10-10 16:46:08 +08:00
18694fd24a 修复富文本bug,调整日志输出,修复已知bug (#1563)
* operation.go: fix 调用respPool.Put归还对象前清空对象会造成下次调用无法正常copy
redis.go: fix NewDefaultRedisStore方法实例化的对象直接使用会造成空指针异常

* 设置为发布模式时gin不再输出路由信息log

* 调整基础配置文件

* 修复富文本不回显的bug

---------

Co-authored-by: liuyahui <liuyahui@wjacloud.com>
Co-authored-by: Alan <alan.cd@qq.com>
Co-authored-by: wuqianang <wuqianang@163.com>
Co-authored-by: task <ms.yangdan@gmail.com>
2023-10-10 16:41:55 +08:00
piexlMax(奇淼 10dc003f20 修复富文本未创建前端输入字段的bug 2023-10-10 16:04:23 +08:00
809e2496c0 增加了自动化视频以及修复了一些已知漏洞 (#1554)
* 解决bug:为角色添加权限时,如果有重复api权限,该角色所有权限均添加失败(包括登录)

* 支持视频上传和选用。视频首帧作为封面预览。

* 增加自动化代码视频选项

* 媒体库可上传视频
SelectImage组件增加参数file-type="image|video" 方便用户对媒体库可选内容做限制

* 自动化代码bug修复

---------

Co-authored-by: liuyahui <liuyahui@wjacloud.com>
Co-authored-by: Alan <alan.cd@qq.com>
2023-09-24 15:49:58 +08:00
奇淼(piexlmax c1c37901b5 Merge pull request #1550 from Suixinee/main
初步构建了文件预览组件
2023-09-24 14:50:57 +08:00
SliverHorn 44e115f211 update: 去掉 github.com/lestrrat-go/file-rotatelogs 库的依赖, 实现zap.String("business", "xx")自定义业务日志数据路径, 输出文件路径为./global.GVA_CONFIG.Zap.Director/2006-01-02/xx/level(debug, info, warn, error, dpanic, panic, fatal).log (#1551) 2023-09-24 14:35:54 +08:00
ipanghu 217cc338a8 fix:修复自动代码的详情页面的bug,选择器,输入框添加 中文名称 (#1552) 2023-09-24 14:35:34 +08:00
suixinee 81eccc177d 初步文件预览组件构建 2023-09-22 10:47:16 +08:00
碎心Eand奇淼(piexlmax 4ea00b7e7b 调整了文件上传无法异步赋值的bug (#1547)
* watch了immediate参数,防止组件异步调用获取数据失败的问题

* watch添加了immediate参数,防止组件异步调用获取不到数据

* Update selectFile.vue

---------

Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2023-09-19 16:08:35 +08:00
奇淼(piexlmax 844699263d Update selectFile.vue 2023-09-19 16:08:14 +08:00
suixinee d72a548852 watch添加了immediate参数,防止组件异步调用获取不到数据 2023-09-19 12:05:21 +08:00
suixinee 722ed9bece watch了immediate参数,防止组件异步调用获取数据失败的问题 2023-09-19 11:57:41 +08:00
SummerBytes 8852367837 codeServer: fix 删除无用代码 (#1541) 2023-09-15 11:50:10 +08:00
piexlMax 5559f9b9af 调整模板代码中的中文解释 2023-09-15 11:44:16 +08:00
piexlMax 39526edafd 代码模板调整name挂载位置 2023-09-14 18:49:59 +08:00
piexlMax a4f86354d3 前端eslint调整 2023-09-14 18:47:47 +08:00
piexlMax 636204bbaf 修复eslint问题 2023-09-14 18:06:26 +08:00
piexlMax 08494834c2 字典增加扩展值字段,优化自动化生成搜索条件默认语句。 2023-09-13 21:33:36 +08:00
piexlMax 2247f34b89 修改富文本组件默认高度 2023-09-13 11:42:25 +08:00
tomoyo233 5c84412238 Update sys_user.go (#1540)
验证码bug修复
2023-09-10 23:03:14 +08:00
piexlMax 13112aa4d8 调整table模板让详情功能适配多种数据类型 2023-09-10 00:27:46 +08:00
zyw0605688 836a165ff2 bugfix:'升级gin-swagger到最新版,解决swagger-ui界面上的Cannot read properties of undefined (reading '1')报错' (#1538) 2023-09-09 13:17:17 +08:00
piexlMax f36e0b39ed 修复#1537 环境变量不生效的问题 2023-09-09 11:25:55 +08:00
Jamieandmazhenming 74e2ec74e0 resource/autocode_template/server/model.go.tpl: swag文档添加中文信息 (#1535)
Co-authored-by: mazhenming <zhenmingma@qq.com>
2023-09-09 11:03:04 +08:00
zyw0605688 bcb6243f3b 批量删除按钮,未选中内容时不应该弹出确定提醒 (#1536)
table的批量删除按钮,未选中内容时候,悬浮提醒不应该显示。增加以下代码
:disabled="!multipleSelection.length"
2023-09-09 11:02:26 +08:00
piexlMax c00b628fb4 [fixed]修复业务库生成代码回滚时候删表位置错误的bug。 2023-09-08 16:54:41 +08:00
piexlMax 2fbed17ebc [fixed]修复业务库生成代码gorm自动迁移数据库name错误的问题。 2023-09-08 16:37:58 +08:00
Felixs 7bfea23958 补充form.vue里遗漏的SelectFile自动化组件 2023-09-06 11:40:30 +08:00
Felixs 91c567779b 恢复 btnAuth 2023-09-05 11:00:36 +08:00
piexlMax c4aeeb419e [update] 清理了一些无用文件 2023-08-31 18:17:06 +08:00
piexlMax 7808fbb852 [fixed] 修复富文本未引入watch的问题 #1528 2023-08-31 12:27:18 +08:00
wangzmgitandwangziming 9e64bd474b fix: 修复菜单折叠后再次展开右侧出现遮罩的问题 (#1529)
Co-authored-by: wangziming <wangziming@emsys.cn>
2023-08-31 11:18:19 +08:00
lubinandlubin 25a6aef472 修复接口实现问题 (#1524)
Co-authored-by: lubin <lubin@xiaoduotech.com>
2023-08-30 14:33:52 +08:00
zyw0605688 203ba521b0 分页列表接口,兼容不分页获取全部数据 (#1526)
* feat:'分页列表接口,兼容不分页获取全部数据'
2023-08-29 20:08:22 +08:00
piexlMax 287685420a [fixed]: 枚举类型条件查询的错误 #1525 2023-08-29 16:17:56 +08:00
piexlMax a6ae0ba4b0 富文本组件增加watch防止富文本无法加载的情况发生。 2023-08-23 18:12:03 +08:00
andywu1998 208346a480 优化config字段排列,使得内存对齐 (#1521)
* 调整字段顺序,解决config包内存对齐问题

* fix(config):修复内存对齐
2023-08-21 18:14:44 +08:00
DaMingandCodeLucifer 0d5c55a3b5 修复上次提交忘记把文件类型下载按钮描述的{{}}设置为字符串 (#1520)
* 修复上次提交忘记把文件类型下载按钮描述的{{}}设置为字符串
---------

Co-authored-by: CodeLucifer <tender_zhu@foxamil.com>
2023-08-19 22:49:29 +08:00
piexlMax 4fcd2bf14c 修改静态目录打包的配置 2023-08-19 11:29:44 +08:00
SDProgrammerandShi Dapeng deea1aba7f fix:修复不同系统环境下创建db文件路径错误的问题 (#1512)
Co-authored-by: Shi Dapeng <shidapeng@cmdi.chinamobile.com>
2023-08-17 17:23:14 +08:00
zhanghaixin246 3e31666cd6 feat:抛出上传文件错误信息 (#1515) 2023-08-17 17:22:50 +08:00
DaMingandCodeLucifer 197c4c46ab 生成代码模版文件新增了查看详情、详情内图片预览、文件下载 (#1516)
* 生成代码模版文件新增了查看详情、详情内图片预览、文件下载
前端工具文件主要修改了utils>format.js

* 替换富文本组建路径

---------

Co-authored-by: CodeLucifer <tender_zhu@foxamil.com>
2023-08-17 17:22:30 +08:00
奇淼(piexlmaxandkrank666 33cb2ed43d Tailwind css personel (#1509)
* css

* 修改persion页面的样式

* 优化persion样式

---------

Co-authored-by: krank666 <emosick@qq.com>
2023-08-11 01:12:51 +08:00
Felixs b56e521c5f 修复组件名称和icon名称重复导致的打包后富文本框被渲染到了不该出现的位置的bug. 2023-08-11 00:35:15 +08:00
SliverHorn 639b930ac9 Merge pull request #1508 from zdreamx/main-2
bugfix: fixed redis.go Set function
2023-08-10 16:59:48 +08:00
zdreamx 607235eb01 bugfix: fixed redis.go Set function 2023-08-10 16:51:58 +08:00
piexlMax dbfeb4b0fa 提升tailwindcss优先级 2023-08-09 17:19:05 +08:00
药要吃 432725b80d 更新 timed_task.go 增加了两个方法 (#1504)
Add:Timer工具增加AddTaskByFuncWithSeconds与AddTaskByJobWithSeconds方法
Fix:解决添加定时任务没有按时运行问题
2023-08-09 16:17:34 +08:00
taskandtask 91c2909c4a README gin版本标记错误 (#1505)
Co-authored-by: task <121913992@qq.com>
2023-08-09 16:16:28 +08:00
piexlMax 699a2f7956 [fixed]:issues #1501 2023-08-09 16:09:46 +08:00
piexlMax 7c2751ad37 提交v2.6.7版本,修复Sort使用的字段bug。 2023-08-09 15:59:58 +08:00
piexlMax 50b524fa7a 通用css 替换为tailwindcss模式,剔除无用css。 2023-08-09 15:51:18 +08:00
piexlMax aee26bc9b2 css 优化 2023-08-08 18:25:23 +08:00
piexlMax 78de254230 替换部分css为tailwindcss 删除某些无用css 2023-08-08 16:05:41 +08:00
piexlMax 22fe4053e9 增加多图片自动生成功能 2023-08-08 13:00:00 +08:00
piexlMax e73f9ac8f2 增加自动化富文本组件 2023-08-08 12:54:36 +08:00
piexlMax 19987234e5 增加部分功能视频教程快速链接 2023-08-06 15:48:02 +08:00
Tscuite 33239f28f8 feat: update ci add CGO_ENABLED=0 (#1497) 2023-08-04 17:30:41 +08:00
350f4572ed 集成tailwindcss 替换新的登陆页面和版权信息组件 (#1499)
* 集成tailwindcss

* fix: 修改登录,init 页面

* Update package.json

* 升级可升级的第三方库到新版本

* 细节调整

---------

Co-authored-by: bypanghu <bypanghu@163.com>
Co-authored-by: task <121913992@qq.com>
2023-08-04 17:03:21 +08:00
YinYongYou ab29267d64 fix: macos和linux下代码定位命令不对 #1495 (#1496) 2023-08-02 19:20:59 +08:00
xiaotianlu b410820868 Rename outer.go to other.go (#1490) 2023-08-02 10:51:58 +08:00
YinYongYou b1268e0001 feat: use description to name apiGroup (#1494) 2023-08-01 19:07:41 +08:00
奇淼(piexlmax 9fe661269d Merge pull request #1483 from ChengDaqi2023/oscs_fix_cis9at8au51vj78hfkt0
fix(sec): upgrade golang.org/x/image to 0.5.0
2023-07-21 16:15:49 +08:00
ChengDaqi2023 a715a77e76 update golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb to 0.5.0 2023-07-20 10:01:32 +08:00
奇淼(piexlmax 20933f77f5 修复marked问题 2023-07-19 15:05:56 +08:00
piexlMax c618fcafaa 增加多图片自动生成功能 2023-07-18 22:19:12 +08:00
piexlMax 350ce2ad35 修复element2.3.8以上i18n的问题 2023-07-18 00:00:26 +08:00
zhengtianbao eef8580e89 use filepath join instead of hardcode separator (#1479) 2023-07-14 21:23:12 +08:00
task 406fc05970 升级highlight.js marked (#1473)
* 升级highlight.js marked

* 升级highlight.js marked到新版本的兼容
2023-07-14 21:22:36 +08:00
Di Sheng 2b6cb775d8 FIX: globally fix typo 'Field' to 'failed' (#1471) 2023-07-14 21:22:10 +08:00
Rhon Joe fe27fd4c86 Fix #1365 (#1469)
* fix(web): 修复默认不存在时跳转问题

* feature(web): 图片组件增加预览
2023-07-14 21:21:25 +08:00
piexlMax 784dca2baa 路由嵌套情况下保证无边框功能可用 2023-07-11 22:24:47 +08:00
piexlMax 6cff6414c2 修复递归级别下无法将外层layout收起的bug 2023-07-11 22:05:58 +08:00
奇淼(piexlmax b84b6c3464 Update README.md 2023-07-02 16:54:51 +08:00
bd3931d62d [feature]:支持Sqlite数据库 (#1467)
* add sqlite3 support

* 修改gorm.io/driver/sqlite 为 github.com/glebarez/sqlite 适配windows用户无cgo环境

---------

Co-authored-by: Kafumio <linzehong1_2020@qq.com>
Co-authored-by: Kafumio <73083337+Kafumio@users.noreply.github.com>
Co-authored-by: sliverhorn <sliver_horn@qq.com>
2023-06-30 19:18:20 +08:00
奇淼(piexlmax 7ababb626b Merge pull request #1463 from zhanghaixin246/feature_modify_mysql_log_zh
feat:解决mysql配置日志等级不生效问题
2023-06-30 19:17:12 +08:00
zhangheng 62b2833c2f feat:解决mysql配置日志等级不生效问题 2023-06-28 19:14:19 +08:00
ipanghu 190c82bbe6 Merge pull request #1459 from bypanghu/main
fix:修复web在vscode打开的时候识别不了@符号的bug
2023-06-26 16:10:34 +08:00
ipanghu b8055d45e7 fix:修复web在vscode打开的时候识别不了@符号 2023-06-26 16:09:18 +08:00
piexlMax fe09bb3c91 修复插件打包丢失标准路径的bug 2023-06-24 18:04:47 +08:00
piexlMax 84d0a91c44 表单校验除string外不再添加whitespace判断 2023-06-23 13:49:57 +08:00
piexlMax 9d95f660e3 修复个人中心头像不居中的问题 2023-06-11 19:21:44 +08:00
piexlMax 2d76d1f50c 自动化代码搜索条件修正 2023-06-11 13:49:44 +08:00
piexlMax df3b921654 前端自动化页面选项修复 2023-06-10 22:31:18 +08:00
piexlMax e98fccdcfd 处理 图片文件同时存在时table下产生的bug 2023-06-10 22:20:03 +08:00
piexlMax 7b9b940b6a 处理 图片文件同时存在时table下产生的bug 2023-06-10 21:50:07 +08:00
piexlMax 3a4b750d93 调整版本号为2.5.6 2023-06-10 17:31:25 +08:00
小马and奇淼(piexlmax 40e3555d13 优化前端页面 (#1439)
* fix: 点击重置按钮时表格未刷新;
修复点击重置按钮时,筛选项被清空,但是下方表格未刷新的问题;

* fix: 未限制输入范围导致的报错;
后端使用了int类型,未限制输入会导致输入过大的数字时报错;

* fix: 未限制输入类型;
使用文本框会导致输入内容的类型未被限制,后端使用了int类型,输入非数字字符时会导致json绑定错误;

* feat: 添加创建时间验证规则;
后端仅在开始时间和结束时间同时有值时才进行搜索,所以前端会出现只选择一项内容时,搜索结果不符合预期的问题。添加验证规则使搜索结果符合预期。

* feat: 优化创建时间搜索项;
选择开始时间后,自动禁用结束时间中早于开始时间的选项;选择结束时间后,自动禁用开始时间中晚于结束时间的选项;增加校验规则,校验开始时间是否早于结束时间;点击搜索按钮时如果未通过校验则不进行搜索;

* fix: 角色id输入非数字字符时点击提交按钮后变为NaN;

* fix: 角色ID输入超大数字时报错;
后端使用int,输入的数字溢出会导致报错,所以限制输入长度;

* feat: 时间类型的选项增加验证规则;
选择开始时间后,自动禁用结束时间中早于开始时间的选项;选择结束时间后,自动禁用开始时间中晚于结束时间的选项;增加校验规则,校验开始时间是否早于结束时间;点击搜索按钮时如果未通过校验则不进行搜索;

* fix: 补全搜索form的ref引用;

* feat: 添加时间类型的搜索范围提示;
时间类型的搜索范围是开始时间(包含)至结束时间(不包含),为避免歧义,增加相关提示;

* feat: 将"时间"修改为"日期"确保字段名称一致性;

* feat: 将列名称从"按钮组"修改为更友好的"操作";

* feat: 将dialog标题修改为更友好的内容;

* fix: 使用了计算值的属性没有进行绑定;

* fix: 必填字段可以只填写空格;

---------

Co-authored-by: 奇淼(piexlmax <303176530@qq.com>
2023-06-10 17:27:52 +08:00
piexlMax 4b6adb3919 增加自动打包插件功能 2023-06-10 17:16:26 +08:00
piexlMax 66aece580f 增加自动化代码文件组件 bugFixed 2023-06-10 14:51:00 +08:00
qk winter 09fc200d55 Update clamis.go (#1450)
添加了GetUserName方法
2023-06-09 22:11:25 +08:00
piexlMax b17b56dba0 增加自动化代码文件组件 2023-06-09 22:10:18 +08:00
piexlMax a9d0531a56 调整代码自动定位无法识别windows的bug 2023-06-09 19:47:50 +08:00
piexlMax a7a2c85f82 增加自动化代码图片功能 修复 2023-06-09 17:51:16 +08:00
piexlMax 83a06fcd2b 增加自动化代码图片功能 2023-06-08 23:17:46 +08:00
piexlMax d2d7b22a8f 增加自动化代码图片功能 2023-06-08 23:17:46 +08:00
奇淼(piexlmax 92b78ab3c8 Update README.md 2023-06-07 14:28:29 +08:00
piexlMax 0bed3bab98 清理掉无用的casbin缓存刷新,增加重新loadPolicy接口。 2023-06-03 15:09:25 +08:00
piexlMax a60637fb79 修复自动引入代码element过于靠前的问题 2023-06-03 13:46:17 +08:00
piexlMax f1218264be 修复自动引入代码element过于靠前的问题 2023-06-03 13:46:17 +08:00
奇淼(piexlmax 18cf63facc Update README.md 2023-05-31 13:20:44 +08:00
奇淼(piexlmax 9f8e1775af AD 2023-05-31 13:15:38 +08:00
piexlMax 0e39f3ad05 调整swag为最新包 2023-05-23 00:08:53 +08:00
WWater 4fc90c0168 Fix go mod (#1421) 2023-05-22 23:50:19 +08:00
SliverHorn 57b4f539f9 去掉base/login 这个没有鉴权的api (#1427) 2023-05-22 16:07:31 +08:00
SliverHorn 8667ce5fb4 Merge pull request #1434 from wZuiShuai/main
修复接口返回未 return 问题
2023-05-18 20:25:13 +08:00
~ 0ed922bb29 修复接口返回未 return 问题 2023-05-18 17:25:17 +08:00
ipanghu 80eff97be3 Update README.md
fix:modify typos "分片长传"to "分片上传"
2023-04-25 16:32:38 +08:00
奇淼(piexlmax e5cfe5cd99 New fixed (#1418)
* fixed:#1416
* vite版本升级
2023-04-24 18:51:24 +08:00
奇淼(piexlmax 1d8b952a6d fixed:#1416 (#1417) 2023-04-24 17:22:10 +08:00
Albort-zand李展旗 c204f7a514 修复并发请求API情况下的读写冲突问题 (#1415)
Co-authored-by: 李展旗 <lizhanqi@inke.cn>
2023-04-24 17:21:38 +08:00
奇淼(piexlmaxandRowen 6e2ef1e29c Fixed (#1412)
* 菜单项如果有参数则携带参数跳转

* 剔除search冗余代码

---------

Co-authored-by: Rowen <wucenglou@qq.com>
2023-04-08 16:07:22 +08:00
奇淼(piexlmaxandkrank 5f0402043a feat: 指令菜单功能 (#1407)
* feat: 指令菜单功能

* 增加快捷指令功能

* 废弃jwt结构StandardClaims替换为RegisteredClaims #1409

* 调整快捷指令登出操作

---------

Co-authored-by: krank <emosick@qq.com>
2023-04-08 15:37:22 +08:00
piexlMax 6ad7ccdd6e 增加chatTable提示 2023-04-01 21:43:57 +08:00
FelixJiang 90a2fd7f19 优化万用表格Prompt 2023-04-01 21:32:28 +08:00
FelixJiang 58c8b11f85 优化万用表格Prompt 2023-04-01 20:16:37 +08:00
FelixJiang 4d700be9ae 优化万用表格Prompt 2023-04-01 20:16:15 +08:00
奇淼(piexlmax da0d02b990 Revert "修复并发请求API情况下的读写冲突问题 (#1395)" (#1404)
This reverts commit 69aa64f800.
2023-04-01 19:59:15 +08:00
小马 854cb59f6b doc: 避免引用行号变更带来的歧义 (#1400) 2023-04-01 19:58:28 +08:00
Albort-zand李展旗 33cbee23d4 修复并发请求API情况下的读写冲突问题 (#1395)
Co-authored-by: 李展旗 <lizhanqi@inke.cn>
2023-03-30 00:49:02 +08:00
奇淼(piexlmax 0497cf384d Revert "[feat]: config for TLS connection in init MySQL (#1388)" (#1392)
This reverts commit a4a240eace.
2023-03-27 11:09:19 +08:00
AONE acd8fa3810 fix: api layer can not get autofill primary key in automatically generated code (#1384) 2023-03-25 20:04:40 +08:00
TPEngineer 9d024bca3b Update sys_authority_btn.go (#1386)
增加 err 错误处理
2023-03-25 20:04:21 +08:00
Albort-z 7434c9db55 修复字典按ID排序而非sort排序问题 (#1387)
直接使用Preload加载的字典值是按ID排序的,在前端展示时并非希望的sort排序
2023-03-25 20:04:05 +08:00
conbanwa a3ab0b3243 [feat]: config for TLS connection in init MySQL (#1388) 2023-03-25 20:02:59 +08:00
64608f6b05 Gpt (#1389)
* fix:优化自动化代码搜索区域 (#1382)

* 增加gpt功能(万用表格)

* feat: chatTable页面
---------

Co-authored-by: ipanghu <bypanghu@163.com>
Co-authored-by: 陶正虎 <zhenghu.tao@jutze.com.cn>
Co-authored-by: krank <emosick@qq.com>
2023-03-25 20:02:14 +08:00
piexlmax a207c982b7 [fixed]: 点击菜单项跳转无效 #1378 2023-03-18 14:21:34 +08:00
piexlmax 072acac399 [fixed]:自动生成代码pkg和结构简称相同导致编译不通过 #1379 2023-03-18 14:21:34 +08:00
piexlmax 8049466dff 清理刷新路由时出现的warning 2023-03-18 14:21:34 +08:00
SliverHorn 80077ba94d Merge pull request #1376 from SliverHorn/fix_middleware_jwt
fixed: middleware jwt
2023-03-13 16:17:27 +08:00
sliverhorn bd4744557f fixed: middleware jwt err == utils.TokenExpired 修改为 errors.Is(err, utils.TokenExpired) 2023-03-13 15:56:40 +08:00
piexlmax d8072634ef 自动化回滚可以回滚gorm.go 和 router.go 2023-03-11 18:26:55 +08:00
piexlmax 27158f7075 路由跳转后自动页面回归顶部 2023-03-09 23:52:54 +08:00
xin053 f06f1fb7f1 fixbug: 修复代码生成器无法自动导入 time 包问题 (#1368)
原本 for 循环下 if 判断只有 HasTimer 判断,加了 break 可以提前跳出循环,但另外新增了 NeedValid 和 NeedSort 判断后,直接跳出循环会导致无法正常设置 HasTimer ,NeedValid 和 NeedSort
2023-03-07 18:22:26 +08:00
奇淼(piexlmax 8bb7b75f05 Update README.md
修复github 表单生成器使用规则
2023-03-06 20:47:42 +08:00
Jankin 0c9e92abb0 华为obs,file.Open后缺少close,uploadFile返回值顺序不对 (#1367) 2023-03-06 20:45:56 +08:00
= 7a8787b1a0 修复分配角色权限底部超出原始应有范围的问题 2023-03-06 10:27:22 +08:00
SliverHorn 78f71c8b13 fixed: #1352 (#1364) 2023-03-02 16:28:42 +08:00
piexlmax a0a35e8253 修复自动化package驼峰问题 2023-03-01 22:05:04 +08:00
a1140314368and奇淼(piexlmax e892e3f9e1 新增权限初始化时适配数据库的出错日志 (#1359)
* 新增权限初始化时适配数据库的出错日志

* 修改报错详情

修改报错详情

---------

Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2023-02-28 14:43:48 +08:00
= 2dadc98485 调整按需加载下element的国际化为中文 2023-02-27 16:05:56 +08:00
SliverHorn 1bd2b4629e Merge pull request #1357 from Macadamianuts/main
本地文件服务 gin路由报错
2023-02-27 12:52:19 +08:00
WWater ce52cbf6ac Update router.go 2023-02-27 12:44:55 +08:00
奇淼(piexlmax 0abcb5aba1 重构自动化代码,修复皮肤bug (#1355)
* 增加读取ast方法和AddImport 方法来增加引用包功能

* 增加在指定方法中添加头部声明global.DB业务库的方法

* 增加了自动添加AutoMigrate方法。

* 将自动化产生自动迁移功能替换为新ast

* 增加了自动注册router块的功能

* 废除旧的对router和gorm的处理方法,替换为新的自动化方法

* 修复开发模式下皮肤失效的问题
2023-02-25 14:46:02 +08:00
奇淼(piexlmax ca7bdc913e 补充按需加载遗漏的指令加载方式的css (#1351)
Co-authored-by: piexlmax(奇淼 <303176530@qq.com>
2023-02-20 14:48:48 +08:00
piexlmax 2de7d34b4a 区分环境进行按需加载,提升本地开发加载速度。
更改侧边栏活跃色,让其和element-ui皮肤统一。
修复issue https://github.com/flipped-aurora/gin-vue-admin/issues/1347
2023-02-18 14:08:42 +08:00
奇淼(piexlmax 0eea78f796 调整为按需加载,element样式调整为皮肤模式,不再使用全局变量覆盖。 (#1349)
* 调整element为自动按需引入,减少打包体积。

* 调整element样式变更为变量模式不再使用全局css覆盖

* 修改element自动化模板适配element皮肤变量模式

---------

Co-authored-by: piexlmax<303176530@qq.com>
2023-02-16 19:03:51 +08:00
Ackerman 95fa7e8130 fix(operation): 修复操作日志中间件,record.Resp写错的问题 (#1342) 2023-02-11 14:32:56 +08:00
ccfish fd78876dd3 Update system.vue (#1341) 2023-02-08 21:05:00 +08:00
piexlmax eaa3075516 初始化引导着重提示mysql需要使用innoDB 2023-02-08 00:24:15 +08:00
XiaoK29 92338fd219 fix:修复用户管理手机号邮箱无法置空bug (#1339) 2023-02-08 00:20:28 +08:00
ipanghuand陶正虎 26d32c02ea fix: 修复上传图片返回的错误信息,修复登录跳转的转跳函数 (#1340)
* fix : 修改登录转跳是replace

* fix:修复上传图片组件的 报错

---------

Co-authored-by: 陶正虎 <zhenghu.tao@jutze.com.cn>
2023-02-08 00:20:07 +08:00
奇淼(piexlmax e03efc33d7 调整资源管理提示 2023-01-31 15:58:07 +08:00
jerjjj 2d1188af11 update nhooyr.io/websocket v1.8.6 to 1.8.7 (#1338) 2023-01-28 14:53:08 +08:00
奇淼(piexlmax 66666ed5fd 调整eslint,优化oc判断 2023-01-14 10:52:15 +08:00
奇淼(piexlmax dfcb283899 fixed:#1336 (#1337) 2023-01-14 10:27:07 +08:00
znonymous 24215f8b28 feat:backend add router global prefix (#1333)
* feat:backend add router global prefix

* feat: global prefix in plugin router

* feat: remove plugin router prefix and add web router setting
2023-01-14 10:22:46 +08:00
Yexk_M ddc2b4c2ad feat: 监听搜索框部分提供回车键提交搜索 (#1335)
* feat: #1334 按回车键搜索
2023-01-14 10:20:13 +08:00
piexlmax 10cef483f4 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2023-01-07 16:26:51 +08:00
piexlmax 51dde2f71e fixed:issue#1321 2023-01-07 16:26:29 +08:00
5e0117e7c6 Captcha (#1329)
* feat: #807 自定义验证码开关,可以自行配置

* 添加数据库列表支持:SQL SERVER

* [user.vue]: 新增邮箱手机合法性校验,邮箱手机非必填

* [menu.js]: 修复错误的API注释

* 调整配置文件 是其可以支持oracle和mssql

Co-authored-by: Yexk <yexk@yexk.cn>
Co-authored-by: 逆光飞翔 <191180776@qq.com>
Co-authored-by: chenteng <cc17854330572@163.com>
2023-01-01 01:26:57 +08:00
奇淼(piexlmax 3b3535faec 2.5.4升级为2.5.5 2022-12-14 15:39:34 +08:00
mengtiantangandxdefei 3e1067faba web/src/view/layout/aside/historyComponent: fix 浏览器自带返回按钮点击多次才能返回上一页, 多次往路由栈push当前页面路由记录的bug (#1311)
Co-authored-by: xdefei <13523376917@163.com>
2022-12-14 15:31:28 +08:00
奇淼(piexlmax 722382f60e 自动化代码列表可直接进行简单编辑。 2022-12-14 15:23:05 +08:00
奇淼(piexlmax e47a512fc8 取消表格导出功能,修复回滚(删表)功能的painc (#1310)
* [feature]:取消表格导出功能

* 修复回滚(删表)painc的问题

* [feature]:修改初始化
2022-12-12 14:42:47 +08:00
奇淼(piexlmax 0627359b6e [fixed]:解决路径判断的错误 #1304 2022-12-08 19:13:31 +08:00
coke 01d1e4c7f5 fix:service\system\sys_authority.go: (#1295)
DeleteAuthority方法修改没有正确处理err导致返回的err信息不正确
GetAuthorityInfoList方法取消多余的if判断,减少阅读疑惑
2022-12-08 18:15:31 +08:00
TonghuaRoot(童话) 3f564e8179 router.go: 将状态码由 200 调整为 http.StatusOK (#1299) 2022-12-08 18:14:10 +08:00
andywu1998and奇淼(piexlmax b6f3038a73 bugfix: 通过修改配置文件使得跨域白名单正常生效 (#1296)
* bugfix: 通过修改配置文件使得跨域白名单正常生效

Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2022-11-30 16:52:00 +08:00
Carrot2 e67354f34c fix: go version error (#1297) 2022-11-30 16:49:14 +08:00
Jary a04982425f closeLoading()的时候先判断接口是否开启了loading,解决showLoading()失效问题 (#1287) 2022-11-25 18:34:25 +08:00
cokeandwangxd01 2e6f99edf0 修改获取角色列表没有检查err,优化查询逻辑 (#1238)
Co-authored-by: wangxd01 <wangxd01@mingyuanyun.com>
2022-11-22 11:26:31 +08:00
奇淼(piexlmax 9307d08bb6 增加字典方法 showDictLabel(字典,字典value)返回字典 label 2022-11-18 14:40:53 +08:00
飞龙Test 2cdcd98e08 修复手机端顶部标题栏溢出、分页溢出的问题 (#1284) 2022-11-17 17:51:19 +08:00
奇淼(piexlmax 7540ee942f [fixed]:解决无法深层校验的bug #1283 2022-11-16 11:17:03 +08:00
spartacus 7bfad03b2e k8s部署的配置文件修改为config.docker.yaml (#1277) 2022-11-10 12:11:29 +08:00
奇淼(piexlmaxand吴璟 9dacd7056b Develop init (#1280)
* 修改数据库初始化方式,增加引擎配置、统一表前缀、是否关闭复数表名

* 修改拦截器逻辑,develop模式不走数据库权限验证

* 增加表前缀,复数表,数据库引擎配置。

Co-authored-by: 吴璟 <hypf2008@126.com>
2022-11-10 12:08:13 +08:00
Sakishum 4ebe66a29c @sakishum 去除 json tag 多余的双引号 (#1279)
去除结构体 SysCaptchaResponse 字段CaptchaLength 的 json tag 多余的双引号
2022-11-09 12:03:00 +08:00
Yexk_M 6ebed9eff6 logger.go: fix nil pointer dereference (#1271) 2022-11-04 13:45:44 +08:00
piexlmax cc13685062 修复丢失的key 2022-10-30 21:31:18 +08:00
奇淼(piexlmax 6b28490d7b Update ci.yaml 2022-10-30 21:14:57 +08:00
zyw0605688and奇淼(piexlmax 27ba592434 feat:'左侧菜单item修改左内边距' (#1272)
* feat:'左侧菜单修改边距'

Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2022-10-30 21:06:50 +08:00
piexlmax cf5daffe69 根据tab决定是否keepalive (动态keepalive) 2022-10-30 21:00:57 +08:00
piexlmax 192c0e529d 增加自动化排序功能 2022-10-30 20:27:22 +08:00
piexlmax c300e16de9 修复无法将子角色重置修改为根角色的bug 2022-10-29 20:26:45 +08:00
奇淼(piexlmax e46eecfc8e Merge pull request #1269 from longzhang83/master
Update email.go
2022-10-27 17:25:22 +08:00
longzhang83 1e2add4b97 Update email.go
EmailTest  修改From 为 To
2022-10-26 17:50:39 +08:00
奇淼(piexlmaxandbypanghu 975f515691 前端细节调整 (#1268)
* fix: 修改 autoCode 引用文件报错,fixed issue 1266

Co-authored-by: bypanghu <bypanghu@163.com>
2022-10-25 17:30:08 +08:00
05f8ae2aae 增加自动化代码选择业务库功能,增加无边框页面功能。 (#1264)
* feat:增加无边框页面路由

* 更改基础页面文字说明

* 修复安装插件路径穿越漏洞

* 添加业务库数据库选择功能

Co-authored-by: dzwvip <dzwvip@qq.com>
Co-authored-by: znonymous <fly1029@yeah.net>
2022-10-23 21:04:17 +08:00
Tscuite 525b3a0da9 feat: CI (#1255)
* feat: 发布release前,自动更新版本号文件
2022-10-23 18:32:47 +08:00
03265e03fc 增加自动化代码匹配进入业务库功能 (#1249)
* Update api.go.tpl

修复不创建资源标识时 批量删除 方法内 deletedBy 未声明的问题

* 可自动创建业务库

* 自动化业务库回滚适配

* 修复断点续传路径穿越漏洞

* 增加指定菜单亮起功能

* 增加菜单高亮功能,调整版本号

* fixed: 用户后台注册没接收手机号和邮箱

Co-authored-by: dzwvip <dzwvip@qq.com>
Co-authored-by: SliverHorn <503551462@qq.com>
2022-10-15 13:55:47 +08:00
奇淼(piexlmaxanddzwvip 28c928890a 修改自动化代码不携带资源标识的created_by错误 (#1247)
* Update api.go.tpl

修复不创建资源标识时 批量删除 方法内 deletedBy 未声明的问题

* 调整配置文件结构

Co-authored-by: dzwvip <dzwvip@qq.com>
2022-10-13 12:15:35 +08:00
tscuite 6f3e8683a0 fix: 数据库默认用户设置为普通用户gva (#1245) 2022-10-13 11:47:09 +08:00
Bin ba7a16250b fix: (#1242)
* feat:perfect

* fix:buffer time

* fix:zap freifx
2022-10-06 21:48:19 +08:00
piexlmax 1cbbce741a 调整字典管理路由监听模式 2022-10-01 17:07:58 +08:00
奇淼(piexlmaxandzyw0605688 9f9f6b7a08 修改前端日志配置页面对应key (#1237)
* Update web/src/view/systemTools/system/system.vue

去掉 系统工具/系统配置/jwt签名有效期缓冲器后面的提示语(秒),现在已改为天,不加为好。
系统工具/系统配置/数据库配置 日志模式字段对应为log-zap

* 调整配置文件结构

Co-authored-by: zyw0605688 <40220158+zyw0605688@users.noreply.github.com>
2022-09-29 12:26:28 +08:00
奇淼(piexlmax 3ec4823533 为菜单添加默认值 2022-09-26 15:57:28 +08:00
SliverHorn 31d316f5b2 Merge pull request #1231 from SliverHorn/fix
fixed: c.ShouldBindXxx 未处理错误 以及注释错误
2022-09-25 16:53:20 +08:00
SliverHorn 8f31d6fcbd fixed: c.ShouldBindXxx 未处理错误 以及注释错误 2022-09-25 16:38:19 +08:00
SliverHorn 7b80ea528c Update sys_user.go
fixed: #1230
2022-09-25 15:50:11 +08:00
piexlmax ee388b01db 升级版本2.5.4 2022-09-25 13:35:11 +08:00
SliverHorn 2d4b16db46 Fixed: c.ShouldBindXXX 未错误处理 #1224 (#1229)
* Fixed: c.ShouldBindXXX 未错误处理 #1224
- api层错误处理以及代码格式统一化
* Update: 代码生成器 api.go ShouldBindXxx 错误处理
2022-09-25 13:23:44 +08:00
SliverHorn a7715648d0 Merge pull request #1226 from freespace8/master
fix: GetUserInfo没有使用正确传参
2022-09-22 14:46:15 +08:00
freespace8 4ebc4e01cd fix: GetUserInfo没有使用正确传参 2022-09-22 12:37:17 +08:00
piexlmax fd0625f2eb 自动化代码样式微调,目录结构调整。 2022-09-21 23:41:29 +08:00
ef35c53712 增加shift+鼠标左键定位代码功能,增加自动创建资源权限标识功能,细节调优。 (#1225)
* fix: 增加索引解决登录太慢的问题

* 增加shift+鼠标左键自动定位到编辑工具代码行的功能

* 过滤功能性标签 防止意外错误

* [utils\validator.go]:修复了当判断字符长度时,当字符串长度为中文,会判断错误。

* 增加资源标识

Co-authored-by: hexiang3000 <91460121+hexiang3000@users.noreply.github.com>
Co-authored-by: fanyibo <29974992@qq.com>
2022-09-21 21:42:10 +08:00
奇淼(piexlmaxandsongzhibin97 b5c79be625 整理配置文件,jwt过期时间和缓冲时间支持1d2h3m4s事件类型 (#1218)
* feat: human duration

* Update config.yaml

* 调整配置文件结构

Co-authored-by: songzhibin97 <718428482@qq.com>
2022-09-13 16:26:02 +08:00
SliverHorn ee7b9b0cff update: 用户默认角色的默认路由如果为空则赋值404, 公共方法抽离并优化 (#1215) 2022-09-09 11:33:58 +08:00
piexlmax 3289405b17 修复回滚bug 2022-09-07 21:30:53 +08:00
ipanghu b9a30b9ffe [Feature] 新增页面切换进度条 (#1213)
新增页面切换进度条
2022-09-06 10:17:05 +08:00
piexlmax f606c7c891 调整casbin为缓存模式 2022-09-03 13:26:36 +08:00
piexl c76eb01b68 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2022-09-02 17:02:33 +08:00
piexl 34b6e5ebae a标签样式恢复便于集成富文本 2022-09-02 17:02:17 +08:00
myface-wang 7d771a56e6 优化,合并update方法 (#1212) 2022-09-01 17:11:20 +08:00
piexl f1017e345b form模板mini调整为small 2022-08-31 17:59:43 +08:00
XiaoK29 091b61bd10 调整ioutil为go1.16推荐语法 (#1209)
* perf:根据go1.16后的提议修改包使用

* perf:根据go1.16后的提议修改包使用以及修改中间件的代码冗余
2022-08-29 15:40:40 +08:00
奇淼(piexlmaxandmngma ed9ca764d4 增加范围搜索自动化,调整了一些已知的bug (#1206)
* 测试build是否成功

* 增加自动化范围搜索,调整字典查询

* 调整默认用户名

* 避免页面加载后立即触发一次验证,页面出现一片红色的警告的情况

* 避免登录接口成功后,push 时间太长但是加载框已经消失,让人误以为登录失败

Co-authored-by: mngma <enmingma@126.com>
2022-08-24 11:36:28 +08:00
奇淼(piexlmax 70c6480ae9 修复某些环境下build失败的bug
修复某些环境下build失败的bug
2022-08-12 12:05:08 +08:00
ZZ a0ebb3ef58 更新api/api.js接口文档 (#1196) 2022-08-11 18:07:51 +08:00
dhb52 1efb68b11f banckend style-fix 2022-08-11 09:58:59 +08:00
dhb52 9c564df350 frontend eslint 2022-08-11 09:58:59 +08:00
SliverHorn 767e7650e0 fix: #1193 (#1194) 2022-08-10 22:35:32 +08:00
piexlmax f32ed3a5c8 调整用户切换角色路由跳转逻辑 2022-08-06 19:47:55 +08:00
piexl 7e7c869fc4 调整html lang 为 zh-cn 2022-08-03 16:12:47 +08:00
songzhibin97 9da64c34ff Feat dependence upgrade (#1190)
* feat: dependence-upgrade
2022-08-01 14:53:27 +08:00
Leonard Wang 23266d12ec 修复插件模板中的提示和代码生成中的问题 (#1186) 2022-07-30 16:31:36 +08:00
piexl 3920d151af 修复参数或者路由中携带-导致关闭左侧和关闭右侧失效的问题 2022-07-29 15:29:28 +08:00
piexl 9551cdf18a fixed:#1185 2022-07-28 17:55:59 +08:00
SliverHorn 1ec90895da Merge pull request #1183 from WangLeonard/bugfix/fix_commit_in_about
修复关于我们中的提交时间
2022-07-27 22:37:55 +08:00
Leonard Wang bd67b8bf7f 修复关于我们中的提交时间 2022-07-27 22:22:22 +08:00
piexl 53c116309e 修改模板列表返回结构 2022-07-26 15:05:09 +08:00
piexl 5a53ae0d34 取消rollupOptions保证build后可用 2022-07-26 11:56:34 +08:00
Yaya Liu 207c0e3708 upload.vue: fix wrong words (#1180) 2022-07-26 09:32:23 +08:00
songzhibin97 7b7d76e977 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2022-07-24 09:02:54 +08:00
songzhibin97 a1d3b5c887 Update zap.go 2022-07-24 09:02:49 +08:00
奇淼(piexlmax 796bcb34ad Update README.md 2022-07-23 23:53:23 +08:00
奇淼(piexlmax 9f274308ca Update build_test.yml 2022-07-23 23:47:04 +08:00
奇淼(piexlmaxandqiang 7feb152b35 前端性能优化,体验优化 (#1178)
* 优化角色管理中菜单和api管理的确定按钮,固定在右上角,更容易操作,每次修改完不需要拉到最上面再确定

* 角色管理中 api和菜单树 增加筛选框

* vite更新至3.0

* 取消sass-loader

* 取消*zoom 的打包报错

Co-authored-by: qiang <1604864658@qq.com>
2022-07-23 23:41:16 +08:00
piexl 4fad8b77bf 修复登录页验证码校验的bug 2022-07-22 12:44:46 +08:00
piexl 2c90c90610 readme数据库引擎提示 2022-07-22 12:18:02 +08:00
tscuite 9ac66f57fa 增加makefile快速打包插件 (#1173)
* 更新插件快捷打包

使用方法:make plugin PLUGIN="这里是插件文件夹名称,默认为email"
2022-07-19 18:47:29 +08:00
奇淼(piexlmax 82fcc196df Update config.yaml 2022-07-16 20:06:59 +08:00
piexlmax c7dbcbf336 修复必填项自动化 2022-07-16 19:40:26 +08:00
piexlmax 5591c60c14 Merge remote-tracking branch 'origin/main' 2022-07-16 19:04:22 +08:00
piexlmax dcdcf0bbbe 调整误提的config 2022-07-16 19:04:07 +08:00
奇淼(piexlmax e899f85101 Update .gitattributes 2022-07-16 13:52:45 +08:00
piexlmax 96ef70b943 发布版本2.5.3b 2022-07-16 12:57:09 +08:00
piexlmax 1f24e135d9 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2022-07-16 12:54:30 +08:00
piexlmax 26d0cb1f3d 更换表单生成器为v2 v3兼容版 2022-07-16 12:52:50 +08:00
tscuite 5256e468db Update README.md (#1171) 2022-07-15 10:07:24 +08:00
piexlmax 82ade2a8f3 修复typo 2022-07-14 20:52:48 +08:00
奇淼(piexlmaxandbypanghu f0d31fd48d 增加必填校验 提升casbin版本 (#1170)
* 添加rule检测

* 调整初始化顺序,防止在数据库创建错误的时候,修改了配置文件。

* (feat):自动生产代码新增校验

* 增加校验功能 升级casbin

Co-authored-by: bypanghu <bypanghu@163.com>
2022-07-14 16:20:34 +08:00
piexl 14de145c02 修改package.son 2022-07-14 10:23:16 +08:00
piexl 060cc38e84 升级element 修改文档地址 2022-07-13 10:28:00 +08:00
piexlmax 453a9b30e9 调整菜单管理中table列的排列方式 2022-07-10 21:07:40 +08:00
piexlmax 73d982ebad 发布2.5.3版本 2022-07-09 16:26:28 +08:00
奇淼(piexlmaxandsongzhibin97 e6ba8e94db 插件安装提示优化 (#1162)
* fix: automatic installation

* fix: #1160

* 自动插件模式鉴定调整

* 插件安装提示优化

Co-authored-by: songzhibin97 <718428482@qq.com>
2022-07-09 15:56:47 +08:00
tscuite 05f13c61fc fix: 修改k8s部署,增加ingress,容器化CICD开启。 (#1158) 2022-07-09 14:27:37 +08:00
奇淼(piexlmaxandsongzhibin97 d52d909171 自动插件模式鉴定调整 (#1161)
* fix: #1160

* 自动插件模式鉴定调整

Co-authored-by: songzhibin97 <718428482@qq.com>
2022-07-09 14:27:04 +08:00
SliverHorn d6c6f39387 Merge pull request #1159 from flipped-aurora/filter-test-suffix
fix:#1157
2022-07-09 10:09:23 +08:00
piexlmax 31946032ba 插件安装权限调整 2022-07-08 22:11:34 +08:00
piexlmax 609e3d42a1 调整初始化casbin权限 2022-07-08 21:22:19 +08:00
songzhibin97 016b7d231a Update sys_auto_code.go 2022-07-08 10:22:40 +08:00
piexlmax 7c61961c55 增加插件api 菜单自动检测并注册功能插件(插件市场同步增加,无需全量更新即可使用) 2022-07-07 22:48:38 +08:00
songzhibin97 89746b3338 feat:filter_test_suffix 2022-07-07 19:10:10 +08:00
Stefan阿钢and何秀钢 64ab6a28b3 单词拼写调整 (#1156)
* modified 单词拼写调整

Co-authored-by: 何秀钢 <xiugang.he@skyee360.com>
2022-07-07 19:05:43 +08:00
4bf872d292 增加插件安装功能并提升其他功能稳定性 (#1155)
* 增加安装插件demo

* 前端上传demo

* 插件安装初版

* 调整菜单结构

* fix: 修改密码校验 jwt 中的用户 id

* router.go:fix  logger的中间件是默认的,这边日志可以删除;cors的日志打印应当在上面两行启用的时候再进行注释

* 登陆==>登录

* 抽离插件安装方法

* 调整插件功能 提升灵活度

Co-authored-by: zeromake <a390720046@gmail.com>
Co-authored-by: Lu JJ <275955589@qq.com>
Co-authored-by: pnck <hio131@gmail.com>
Co-authored-by: feixuanyu <994085848@qq.com>
2022-07-07 12:34:54 +08:00
piexlmax 063ceffb11 恢复zip的自动定位代码行功能 2022-07-01 17:59:46 +08:00
piexlmax f68ca5ab73 暂时清理embed转内部研发兼容 2022-07-01 17:51:31 +08:00
realpg eb47b5d08a BUGFIX. 兼容最近添加的embed.go (#1147)
VSCode工作区文件配置文件调整,使调试功能兼容最近添加的embed.go
2022-07-01 10:51:10 +08:00
piexlmax 2665ea1203 修复字典类型搜索结果清空后导致的查询错误bug 2022-06-30 12:52:19 +08:00
piexlmax b2dc150f03 调整自动化代码搜索栏字典型input为select 2022-06-30 12:03:53 +08:00
piexlmax 70ff8ead90 自动化代码结构体无需手动添加time包 2022-06-30 11:57:24 +08:00
0610419e38 调整角色ID为uint格式,增加embed打包,更改日志格式。 (#1144)
* feature: 根据 #377 pr进行修改embed, 打包静态文件夹与配置文件

* 修改角色id为uint

* 修改日志格式

Co-authored-by: SliverHorn <503551462@qq.com>
Co-authored-by: cg81344 <cg831344@126.com>
2022-06-29 22:12:53 +08:00
SliverHorn cd68d1f198 update: github.com/shirou/gopsutil/v3 升级为v3版本, 解决打包或运行的时候报警告问题 (#1140) 2022-06-28 17:28:46 +08:00
奇淼(piexlmaxandLyon.Nee 091f83ff59 Drop view (#1137)
* sys_initdb_mysql/pgsql.go: 优化流程, 创建database前,如果dbname为空直接返回

* 删除视图逻辑

* 摘除视图初始化逻辑

* 移除dialog废弃的title标签修改为header

* 解决部分浏览器登录后遮罩不消失的bug

* 修复角色菜单逻辑

* element 2.2.2=>2.2.5

* 修复插件模板

* 调整自动插件模板到插件功能下

* 切换角色切换至角色首页

Co-authored-by: Lyon.Nee <lyon.nee@outlook.com>
2022-06-23 22:30:15 +08:00
piexl 8504e9bf74 清理无用代码 2022-06-22 14:47:39 +08:00
SliverHorn 013d1ed056 Merge pull request #1135 from YanCunJu/main
server/config/zap.go: fix max-age 名称错误
2022-06-22 14:28:41 +08:00
realpg 8d7d6eee76 修复BUG (#1136)
如果在这里数据库查询出现错误,err != nil 就会两次返回 出现返回结果为

{"code":7,"data":{},"msg":"设置失败"}{"code":0,"data":{},"msg":"设置成功"}
这种形式,导致vue js无法正确处理返回
2022-06-22 12:49:12 +08:00
yancunju cba2ed5424 server/config/zap.go: fix max-age 名称错误 2022-06-22 12:26:45 +08:00
奇淼(piexlmaxandLyon.Nee d913ce8e1a sys_initdb_mysql/pgsql.go: 优化流程, 创建database前,如果dbname为空直接返回 (#1134)
Co-authored-by: Lyon.Nee <lyon.nee@outlook.com>
2022-06-22 11:51:09 +08:00
spartacus 84e7c4df49 web/src/view/systemTools/system/system.vue定时任务复选框和字段修改 (#1131) 2022-06-22 11:39:55 +08:00
piexl 71a2f4c284 修改提示文案,增加禁用主动检测(需要手动开启) 2022-06-22 11:37:24 +08:00
奇淼(piexlmax 777f49002e Merge pull request #1133 from yesgs/main
添加用户的冻结功能
2022-06-22 10:59:22 +08:00
king 1e6dfbff96 添加用户的冻结功能 2022-06-21 22:18:06 +08:00
piexlmax 053f414ef6 完善枚举值自动化 2022-06-21 21:52:42 +08:00
piexlmax 6321564bed 自动化插件模板调整 2022-06-19 21:51:20 +08:00
piexlmax 76be6b8847 清除number控件样式 2022-06-19 13:48:49 +08:00
piexlmax 9205a39d3e 菜单\自动全部替换为/ 2022-06-19 13:46:25 +08:00
piexlmax 1471f165de 取消dashboard的v-auth 2022-06-19 13:17:02 +08:00
piexlmax e40d785e4e 前端增加插件化示例 2022-06-19 13:02:12 +08:00
piexlmax b6e2cf645b 修复title不跟随参数变更的bug 2022-06-18 23:24:57 +08:00
piexlmax 759fb6622d 增加删表回滚确认次数 2022-06-18 23:21:19 +08:00
piexlmax 7c7ca8d757 暴露TokenNext方法方便用户登录 2022-06-18 15:27:16 +08:00
piexlmax 0f3ff7bdbb Merge remote-tracking branch 'origin/main' 2022-06-18 00:21:42 +08:00
奇淼(piexlmaxandyancunju e0280a56ce 字典优化,tabs优化,自动化代码优化 (#1128)
* server/service/system/sys_dictionary.go: fix 获取字典单条数据时status失效的bug

* 增加关闭状态下折叠内容所在menu的高亮提示

* 修复字典变更无法打开的bug

* 增加详情页签区分功能

* 增加字典详情区分

* 修复字典功能

Co-authored-by: yancunju <yancunju@autouc.com>
2022-06-12 20:23:08 +08:00
SliverHorn 9da394f711 修复issues #1118 (#1119)
* - 修复issues #1118
- zap日志无法按照等级出现在对应log文件中
- zap.AddCaller()只有在global.GVA_CONFIG.Zap.ShowLine为true才生效
- rotatelogs.ForceNewFile(),取消这个, 这样每次启动不会出现同一天日志级别.1后缀的新文件

* 等级使用Transport进行转换,优化臃肿代码,优雅获取zapcore.Core
2022-06-10 09:57:25 +08:00
SliverHorn 582c39611d fix and optimize casbin (#1121)
* - 删除rabac_model.conf, 改为字符串代码, 方便部署
- 删除casbin相关配置文件

* fix: delete api时只传id导致casbin_rules表清空bug
2022-06-10 09:57:09 +08:00
piexlmax 7d82785ade 修复pgsql从数据库表获取key的问题 2022-06-09 14:53:57 +08:00
奇淼(piexlmaxandtask 4e8544ce97 2.5.3beta (#1117)
* element-ui升级至2.2.2 部分标签存在重大变化,请重新安装依赖

* popover变更

* 天气预报

* 天气功能抽离方便二开清理

* 侧边栏css优化

* 版本提升为2.5.3beta

* 提交丢失的package.json

Co-authored-by: task <121913992@qq.com>
2022-06-04 22:10:13 +08:00
奇淼(piexlmaxandtask a8d746e831 2.5.3beta版本提升 (#1116)
* element-ui升级至2.2.2 部分标签存在重大变化,请重新安装依赖

* popover变更

* 增加真实的天气信息获取

* 天气功能抽离方便二开清理

* 侧边栏css优化

* 版本提升为2.5.3beta

Co-authored-by: task <121913992@qq.com>
2022-06-03 21:42:45 +08:00
piexlmax 9d8df566fc 自动迁移将默认为true 2022-06-03 21:04:36 +08:00
Echowxsy 99156155b3 feat: use workspace & add launch config (#1114)
* feat: use workspace & add launch config
2022-06-02 17:25:16 +08:00
piexlmax 17fe4ac327 public 2.5.2 2022-06-02 15:39:23 +08:00
piexlmax 3b6e6495c5 public 2.5.2 2022-06-02 14:31:06 +08:00
piexlmax b20a54f7e9 fixed: #1102 2022-05-31 17:53:58 +08:00
SliverHorn 3bb4d74fab feature: viper 读取gin自带的环境变量GIN_MODE,用于区分开发,测试,生产三个环境 #1098 (#1105) 2022-05-30 22:33:14 +08:00
lin93hand奇淼(piexlmax 4dd9c06850 解决historyComponent无法删除问题 (#1108)
* 修复historyComponent无法删除问题

Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2022-05-30 21:44:45 +08:00
SliverHorn 2ca9322d82 Merge pull request #1104 from aaronwmy/main
将上传目录访问路径和存储路径分开成两个配置
2022-05-30 19:33:51 +08:00
aaronwmy 5e304a5a6b 修改系统工具-系统配置页面,增加本地文件存储路径的表单项。 2022-05-30 11:26:23 +08:00
aaronwmy 21eb039978 给后端的配置文件加上存储路径参数 2022-05-30 10:53:53 +08:00
aaronwmy 6026ac31b1 将上传目录访问路径和存储路径分开成两个配置 2022-05-29 12:21:24 +08:00
奇淼(piexlmax 72e11a7d31 侧边栏样式调整 (#1102)
* 添加侧边栏样式,增加变量配置,方便自定义主题

* 控制侧边栏二层传递样式
2022-05-28 23:59:09 +08:00
piexlmax b0656e70b8 清理误传配置文件 2022-05-28 22:02:04 +08:00
83141b3564 V2.5.2beta (#1101)
* fix: zap无法在运行时进行切割日志, config.docker.yaml与config.yaml同步 #1094

* feat: 为定时任务增加秒级控制

* feat: 调整代码结构,err更改为后置

* css 样式调整

Co-authored-by: SliverHorn <503551462@qq.com>
Co-authored-by: songzhibin97 <718428482@qq.com>
2022-05-28 19:22:23 +08:00
piexlmax b25c128051 排除多余css 2022-05-28 19:06:35 +08:00
piexlmax afc9d13d45 Merge remote-tracking branch 'origin/main' 2022-05-27 22:31:22 +08:00
piexlmax 7e106f3468 侧边栏样式微调 2022-05-27 22:30:44 +08:00
songzhibin97 e74a102700 Merge pull request #1096 from SliverHorn/fix-keyword
fix: 代码生成器 结构体简称发生的关键字冲突 #1089
2022-05-27 15:03:41 +08:00
SliverHorn 1037a1749b Merge pull request #1093 from nickmyb/fix_pgsql_initdb
fix: 修复初始化PostgreSQL时尝试数据库连接验证时用户名同名数据库不存在导致的初始化失败问题
2022-05-27 15:00:03 +08:00
SliverHorn 8c19622db2 fix: _ 加到后面 2022-05-27 14:51:10 +08:00
SliverHorn 0eae201401 fix: 代码生成器 结构体简称发生的关键字冲突 #1089 2022-05-27 13:50:27 +08:00
nickmyb 3de83d1178 fix: 修复初始化PostgreSQL时尝试数据库连接验证时用户名同名数据库不存在导致的初始化失败问题
https://www.postgresql.org/docs/current/app-initdb.html

The postgres database is a default database meant for use by users, utilities and third party applications.

默认数据库postgres一般存在,但用户名同名数据库不一定存在
2022-05-26 22:50:03 +08:00
piexlmax c17ebddcef Merge remote-tracking branch 'origin/main' 2022-05-26 14:45:34 +08:00
pnck 95fd9f92cd 一些小修复 (#1085)
* chore: 去掉初始化中误加的额外表

* chore: 修复初始化不应使用的GVA_DB
2022-05-26 14:45:20 +08:00
piexlmax fda1a2a728 Merge remote-tracking branch 'origin/main' 2022-05-26 14:38:40 +08:00
songzhibin97 98dc95d105 Merge pull request #1091 from songzhibin97/fix-db-list-alias-name
fix:alias name repetition
2022-05-26 14:26:12 +08:00
songzhibin97 c5da8d154d fix:alias name repetition 2022-05-26 14:24:59 +08:00
piexlmax 95209af8f9 Merge remote-tracking branch 'origin/main' 2022-05-26 10:27:16 +08:00
piexlmax 35255fdaee 将closeThisPage方法从global迁移到utils 2022-05-26 10:26:11 +08:00
SliverHorn cd7ad06a7d Merge pull request #1084 from masonFEI/main
修复分片上传-寻找目标文件(秒传)的请求方式有误
2022-05-25 17:34:15 +08:00
SliverHorn d0b8cd8221 Merge pull request #1087 from songzhibin97/fix-db-list-alias-name
fix:db list alias name
2022-05-25 17:32:48 +08:00
songzhibin97 1aac17aeff fix:db list alias name 2022-05-25 13:24:31 +08:00
piexlmax ccf0769f43 我偷偷改一个console错误不会有人知道吧 2022-05-24 21:43:38 +08:00
piexlmax 076e1092f0 发布2.5.1b 新增插件市场快捷入口 2022-05-24 21:33:58 +08:00
piexlmax 670df8c0cb Merge remote-tracking branch 'origin/main' 2022-05-24 21:24:31 +08:00
piexlmax a817dceb24 增加package空拦截 2022-05-24 21:23:47 +08:00
feixuanyu 227bcd509f 修复分片上传-寻找目标文件(秒传)的请求方式有误
会造成的问题是:项目初始化后,在菜单管理页面可以看到这个api的方式是post,然后再角色管理里面,普通用户的角色api的分片上传组-寻找目标文件(秒传)是没有选中的,如果勾选上点击确定提交,会造成断点续传功能无法上传文件,casbin校验不通过,因为数据被修改了。
如果对角色api这个复选框没有选中的情况不进行操作的话,不影响断点续传功能使用。
2022-05-24 20:34:48 +08:00
SliverHorn 1e6605ecd3 Merge pull request #1081 from pnck/main
fix: 修复多库模式不能使用 pg 的问题
2022-05-23 13:02:36 +08:00
pnck 84f35f55d4 fix: 修复多库模式不能使用 pg 的问题 2022-05-22 17:52:14 +08:00
pnck 43d1aa17a3 chore: 修正几个okwithdata 的误用 (#1077) 2022-05-20 14:55:28 +08:00
piexlmax fc0958e511 修改vite2.9.9的情况下右侧白页问题 2022-05-19 17:37:03 +08:00
piexlmax bfe3a861f5 Merge remote-tracking branch 'origin/main' 2022-05-19 12:07:38 +08:00
piexlmax 658ca60f58 修改本地文件的图片路径bug 2022-05-19 12:06:54 +08:00
songzhibin97 e4709c599b fix:replace the method of abandonment (#1075)
* fix:replace the method of abandonment
2022-05-19 11:10:05 +08:00
SliverHorn 02ffe71d80 Update config.yaml
更新初始化文档地址错误
2022-05-18 21:44:09 +08:00
tscuite 3ef3084070 修复docker中代码生成问题 (#1067)
* Update docker-compose-dev.yaml

* Update .env.development
2022-05-18 19:25:28 +08:00
Hessianand周海生 250fcf4bd6 自动生成代码添加枚举类型支持 (#1073)
* fieldDialog.vue feature 增加枚举字段类型支持

* model.go.tpl feature 增加枚举字段类型支持

Co-authored-by: 周海生 <zhouhaisheng@doxue.com>
2022-05-18 19:24:54 +08:00
songzhibin97andlongzhang83 86baabc452 规范自动化插件包功能
* 规范自动化插件包功能

Co-authored-by: longzhang83 <38556219+longzhang83@users.noreply.github.com>
2022-05-18 19:23:36 +08:00
piexlmax 6126aa146b 修复自动化代码复用不切换的bug 2022-05-18 18:59:53 +08:00
piexlmax 64ce7fedcd 修正jwt初始化位置,防止jwt出现配置错误。 2022-05-18 18:09:58 +08:00
piexlmax 6c85af386c 修复自动化插件模板的bug 2022-05-15 17:15:22 +08:00
piexlmax 7ff58c4e6d 发布2.5.1版本 2022-05-13 20:18:04 +08:00
piexlmax ecef8ddd72 Merge remote-tracking branch 'origin/main' 2022-05-11 22:22:03 +08:00
piexlmax 2f96e27adb 调整logo css,让菜单过长可以完整展示 2022-05-11 22:21:19 +08:00
spectatorMrZandspectatorMrZ 10bd7e9485 remove multi preload (#1062)
Co-authored-by: spectatorMrZ <13959374+SpectatorNan@users.noreply.github.com>
2022-05-11 22:04:58 +08:00
f6fa4c3064 Bug fix test (#1061)
* fix 腾讯云COS上传配置无效

* Create docker-cicd.yaml

* 修复InitDataFailed 打印bug

Co-authored-by: tesun <36953434+tesun@users.noreply.github.com>
Co-authored-by: task <ms.yangdan@gmail.com>
Co-authored-by: task <121913992@qq.com>
Co-authored-by: tscuite <tscuite@qq.com>
Co-authored-by: tscuite <64051240+tscuite@users.noreply.github.com>
Co-authored-by: wyh <yinhua_wu@arcplus.com.cn>
2022-05-10 14:24:36 +08:00
beyoung 64a525133b fix typo ymal -> yaml (#1059) 2022-05-10 14:23:49 +08:00
piexlmax 485b9f32df Merge remote-tracking branch 'origin/main' 2022-05-10 14:21:56 +08:00
piexlmax dc6859f4f0 删除会导致默认样式变化的css 2022-05-10 14:21:12 +08:00
xiushengxand奇淼(piexlmax f861f2ba3f 修复用户侧边主题更改不生效的问题 (#1052)
* 修复用户侧边主题更改不生效的问题

Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2022-05-01 13:37:48 +08:00
tscuite 3a9b39b94b 优化docker-compose,默认去除淘宝源 (#1053)
* 优化docker-compose
2022-05-01 13:30:06 +08:00
SliverHorn 9a5d3461fe fix: #985 日志未按照日期分割 修复完成 2022-04-28 21:59:06 +08:00
6add2094a6 v2.5.1 beta2 (#1048)
* 修复日志中间件报文过大的报错问题

* 修复 Token 失效后导致的白屏问题

* 增加自动创建插件模板功能

* 密码加密方式改为 hash

* 增加刷新防抖

Co-authored-by: songzhibin97 <718428482@qq.com>
Co-authored-by: icedays <icedays@163.com>
Co-authored-by: hedeqiang <laravel_code@163.com>
2022-04-25 17:34:17 +08:00
pnck 843e5a9ad4 update: update echarts version to 5.x (#1047) 2022-04-25 11:45:55 +08:00
xiao-shanfeng a8d41e289c 修改多个字典管理标签切换 (#1042) 2022-04-20 10:44:36 +08:00
Key 3a591a5574 修复自动化包的bug及书写错误 (#1041)
* Update sys_auto_code.go

修复[自动化package] 删除数据的错误

* Update sys_auto_code.go

方法接收者名称书写错误
2022-04-19 21:21:51 +08:00
xiushengx 6076b4cde1 cors.go fix 修复角色切换bug (#1033)
修复角色切换bug
2022-04-16 21:14:06 +08:00
奇淼(piexlmax b158849d07 Update README.md 2022-04-15 16:09:59 +08:00
fengyikang88and奇淼(piexlmax e4d448a661 Update exa_file_upload_and_download.go (#1029)
* 更改上传文件路由文件 代码注释错误


Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2022-04-14 17:58:24 +08:00
ShuBo6 42b51243a7 修改了Ram拼写错误 (#1030) 2022-04-14 17:56:01 +08:00
bx 8dd87d0172 更改自动化代码注释错别字
更改自动化代码注释错别字
2022-04-13 22:03:58 +08:00
lvshaoyuanandoldlv c92a94bdd2 email.go:再重新写回请求体body中,ioutil.ReadAll会清空c.Request.Body中的数据 (#1027)
Co-authored-by: oldlv <15237336850@163.com>
2022-04-13 21:20:09 +08:00
taskandtask c7ce98f1d5 初始化加入接口:/fileUploadAndDownload/editFileName (#1025)
* 初始化加入接口:/fileUploadAndDownload/editFileName

Co-authored-by: task <121913992@qq.com>
2022-04-13 12:29:32 +08:00
6fb6ac2d6c 修复漏洞,重构初始化功能,优化媒体库 (#1024)
* 媒体库增加 普通上传、压缩上传按钮,方便媒体库直接上传图片

* 增加数据类型切换后的的校验,避免使用错误的查询条件和字典条件。

* refactor: 重构初始化逻辑

* 媒体库功能丰富

* 修复注入漏洞和路径穿越

* 修复自动化接口获取数据库表失败后未能终止的bug

* 微调媒体库样式

Co-authored-by: bypanghu <bypanghu@163.com>
Co-authored-by: tesun <36953434+tesun@users.noreply.github.com>
Co-authored-by: pnck <hio131@gmail.com>
Co-authored-by: task <121913992@qq.com>
2022-04-12 17:57:11 +08:00
奇淼(piexlmax fe539baa34 Merge pull request #1020 from morya/main
fix swagger comment route typo
2022-04-12 14:44:59 +08:00
Morya 9aa7399484 fix swagger comment route typo
/authorityBtn/getAuthorityBtn -> /authorityBtn/setAuthorityBtn
2022-04-12 10:01:29 +08:00
eaa97e7eb8 Add upload (#1016)
* [style] 修改右上角图标,选择统一风格的iconfont

* [fix] fix webfont tree in readme file

* (fix) 菜单编辑的时候,icon不居中

* 更新为使用组件

* 媒体库增加 普通上传、压缩上传按钮,方便媒体库直接上传图片

* 普通上传组件

* 增加数据类型切换后的的校验,避免使用错误的查询条件和字典条件。

Co-authored-by: bypanghu <bypanghu@163.com>
Co-authored-by: tesun <36953434+tesun@users.noreply.github.com>
2022-04-10 22:01:36 +08:00
奇淼(piexlmax dd7e37ef6e Merge pull request #1004 from yesgs/main
增加请求发生异常的判断
2022-04-06 16:45:33 +08:00
king 64c46118b0 增加请求发生异常的判断 2022-04-02 17:02:37 +08:00
奇淼(piexlmax bdc5f69ae0 Merge pull request #999 from szluyu99/patch-2
exa_file_upload_download.go 注释错误
2022-04-02 16:40:51 +08:00
zhenyu 35616394bc exa_file_upload_download.go 注释错误 2022-04-01 15:47:13 +08:00
piexlmax f463e76f5e Merge remote-tracking branch 'origin/main' 2022-03-31 22:15:09 +08:00
piexlmax fb7b57210a 日志中间件对于上传文件做body过滤处理 2022-03-31 22:14:54 +08:00
奇淼(piexlmax 6ccd791574 Merge pull request #989 from szluyu99/patch-1
sys_user.go 注释错误
2022-03-31 21:53:07 +08:00
piexlmax 13b12d80da 增加回滚不删表按钮防止误删数据库重要数据 2022-03-30 22:48:43 +08:00
zhenyu 571de25e81 Update sys_user.go
注释错误
2022-03-29 16:23:04 +08:00
piexlmax 08c2b02be9 消除package warning 2022-03-29 12:20:33 +08:00
piexlmax 6e0a3387cd 修复密码错误遮罩不消失的bug 2022-03-29 11:45:45 +08:00
piexlmax c5f6e1262f 调整插件模板位置 2022-03-28 23:54:23 +08:00
piexlmax 27212da8df 自动化pkg不被允许以数字开头 2022-03-28 23:32:41 +08:00
奇淼(piexlmax 9d89d33701 Merge pull request #987 from songzhibin97/master
fix:config write back
2022-03-28 22:29:21 +08:00
songzhibin97 5754979918 fix:config write back 2022-03-28 20:38:27 +08:00
奇淼(piexlmax bf66fa386b Merge pull request #986 from flipped-aurora/fix-config
Fix config
2022-03-28 12:31:52 +08:00
piexlmax e91338a2e6 增加登录遮罩 2022-03-28 12:23:41 +08:00
piexlmax 58616d4927 修复右上角抽搐现象 2022-03-28 12:00:04 +08:00
piexlmax 2b2ac20feb 前端对应调整config 2022-03-27 19:58:37 +08:00
奇淼(piexlmax 7c11f8ab37 Merge pull request #984 from songzhibin97/master
fix:#977
2022-03-27 19:33:59 +08:00
songzhibin97 cc7fde9a27 feat:viper write back 2022-03-27 17:07:05 +08:00
songzhibin97 ed56a73821 fix:977 2022-03-27 16:52:11 +08:00
songzhibin97 7e7fa6af65 Merge remote-tracking branch 'upstream/main' 2022-03-27 16:21:48 +08:00
piexlmax 5d591bca35 初始化 config.yaml 2022-03-26 14:59:05 +08:00
piexlmax 0b8e15cad1 自动化代码不同包结构体不再冲突 2022-03-26 14:44:23 +08:00
piexlmax d96b963385 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2022-03-26 14:23:02 +08:00
piexlmax 671040a3a7 版本号 v2.5.0 => v2.5.1 beta 2022-03-26 14:22:40 +08:00
429353fa54 自动化代码可分包 (#982)
* [style] 修改右上角图标,选择统一风格的iconfont

* 增加路由排错处理

* 未输入tablename时前端自动生成下划线表名方式回滚误删表

* 支持自动化生成package功能

Co-authored-by: bypanghu <bypanghu@163.com>
Co-authored-by: songzhibin97 <718428482@qq.com>
2022-03-26 14:13:26 +08:00
weiyunxiao 8003603ffd 修复当字典没有详情列表时,删除字典提示失败的问题 (#976) 2022-03-24 10:28:19 +08:00
piexlmax f8e767511b 排除json循环引用的bug 2022-03-23 22:58:35 +08:00
songzhibin97 6a97980a18 mg 2022-03-21 10:19:51 +08:00
Leonardandyangping 2ab0df8e17 fixed(api/v1/example/exa_excel.go): 下载模版失败 (#916)
Co-authored-by: yangping <yangping@66nao.com>
2022-03-16 18:41:47 +08:00
songzhibin97 97a3ca223f Fix #942 #957
* fix:#957
* fix:#942
2022-03-16 18:21:15 +08:00
songzhibin97 bee9f61aa9 fix:#957 2022-03-16 16:05:34 +08:00
Kevin Wan c193eb155e chore: update docs of go-zero (#954) 2022-03-15 15:43:38 +08:00
junstyle cc5ac0c659 JSON.stringify出现循环引用错误 (#951)
JSON.stringify出现循环引用错误
2022-03-15 14:41:22 +08:00
奇淼(piexlmax 752d063d5f Update README.md 2022-03-15 14:31:33 +08:00
piexlmax 06229d0d1f Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2022-03-14 15:08:52 +08:00
piexlmax 4ac8f5a354 修复面包屑 2022-03-14 15:08:30 +08:00
cubeerand奇淼(piexlmax 6628715e40 spelling corrected: initMsqlDB -->initMysqlDB (#949)
* spell corrected:  initMsqlDB -->initMysqlDB

Co-authored-by: 奇淼(piexlmax <qimiaojiangjizhao@gmail.com>
2022-03-14 14:56:44 +08:00
无星夜 d84dc0dd48 Fix invalid orderKey (#950)
* fix unmatched type of id field

* fix invalid order key
2022-03-14 14:54:05 +08:00
piexlmax 253e2a58be Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2022-03-14 14:51:15 +08:00
piexlmax 5f8daf56b1 修复批量删除按钮失效问题 2022-03-14 14:51:02 +08:00
piexlmax cdd5aedadd 修复批量删除按钮失效问题 2022-03-14 14:49:44 +08:00
tscuite 52809a01d8 隐藏actios错误提示,Update docker-compose.yaml (#946)
* 隐藏actios错误提示

* Update docker-compose.yaml
2022-03-10 18:23:42 +08:00
b459413c0e 修复 开发环境中使用docker的一些问题 📝 (#944)
* 修复docker 开发环境问题 📝

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: tscuite <64051240+tscuite@users.noreply.github.com>
2022-03-10 16:54:38 +08:00
奇淼(piexlmax b147c4faaa Update README.md 2022-03-10 15:39:02 +08:00
奇淼(piexlmax e63ccb0541 Merge pull request #939 from junstyle/main 2022-03-03 11:52:08 +08:00
junstyle ea878ca627 这个isSame有问题
route1.query={}
route2.query={a:1}
route1的query,params为空时,还是会返回true
2022-03-02 20:05:42 +08:00
tscuite 2dc2a998ce 修复线上表单显示 (#935)
修复线上表单显示
2022-03-01 12:47:43 +08:00
piexlmax f747e01285 修复keepalive问题 #934 #903,调整刷新功能,增加页面跳转动画。 2022-03-01 12:40:56 +08:00
piexlmax d9a53805ee 增加角色按钮数据库备注 2022-02-28 11:54:10 +08:00
奇淼(piexlmax 9c3fc0dede Update README.md 2022-02-28 10:10:36 +08:00
RebellioncryandRebellioncry cc409fbab6 AwsS3新增配置属性,可以兼容minio (#932)
Co-authored-by: Rebellioncry <23714@aomai.com>
2022-02-26 20:28:11 +08:00
piexlmax 8de71ff2d3 Merge remote-tracking branch 'origin/main' 2022-02-26 20:23:18 +08:00
piexlmax 457768bb10 发布2.5.0正式版 2022-02-26 20:22:40 +08:00
songzhibin97 046b89efc5 fix: 规范yaml 2022-02-25 14:50:42 +08:00
piexlmax e7f7772a74 fixed:#933 调整vite版本到2.8.0 2022-02-24 18:16:41 +08:00
piexlmax 0082ebfdb1 Merge remote-tracking branch 'origin/main' 2022-02-24 12:03:58 +08:00
piexlmax a9f0c41cae 修复拷贝角色的错误提示 2022-02-24 12:03:37 +08:00
30b16984ed fixed:调整v2.5.0测试版bug (#931)
* update readme badge for en

* server/middleware/operation.go : fix 当记录日志当请求为GET时,不对query参数进行记录

* update element badge to element--plus-2.0.1-green

* fix unmatched type of id field

* update badge for vue gorm in readme

* fixed:#917

Co-authored-by: helight <helight@helight.info>
Co-authored-by: wan9xy <wan9xy@qq.com>
Co-authored-by: he <trumanhe0@gmail.com>
Co-authored-by: 无星夜 <31583810+TrumanH@users.noreply.github.com>
2022-02-24 11:49:37 +08:00
piexlmax c8ce379163 调整其他操作对按钮权限产生的影响 2022-02-24 10:52:29 +08:00
helight f5bfb0255c update reade gin badge to 1.7.0 (#925) 2022-02-22 11:01:35 +08:00
tscuite f2b92cc6e0 增加前端控制台开启redis (#924)
* 增加前端控制台开启redis

* 修复按钮控制权限加载问题
2022-02-22 11:01:22 +08:00
奇淼(piexlmaxandhelight 6a97f39f66 新增按钮权限,增加redis可独立配置 (#923)
* fix jwt to golang-jwt, gin to 1.7.0

* 增加按钮权限功能

* 增加redis可独立配置

Co-authored-by: helight <helight@helight.info>
2022-02-22 00:26:21 +08:00
piexlmax f389ff701a 增加主动使用redis的配置 2022-02-21 14:13:22 +08:00
piexlmax 648df02624 Merge remote-tracking branch 'origin/main' 2022-02-21 14:08:01 +08:00
piexlmax 4cee98bcce casbin结构修改为三方包内部结构,避免升级冲突。 2022-02-21 14:07:32 +08:00
songzhibin97 7e33dc7e25 Merge pull request #919 from songzhibin97/master
feat:zap.L
2022-02-20 15:59:25 +08:00
songzhibin97 6f68fbfd6d feat:zap.L 2022-02-20 15:58:47 +08:00
奇淼(piexlmax 7fe3c2b285 Merge pull request #914 from qazwsx9288/bugFix
bugfix:修复菜单未设置icon时,vue会弹出vnode警告的bug;
2022-02-15 17:22:39 +08:00
qazwsx9288 a07ba498d6 bugfix:修复菜单未设置icon时,vue会弹出vnode警告的bug; 2022-02-15 16:28:12 +08:00
piexlmax d7222c8e31 锁定关键信息ID 2022-02-14 14:59:22 +08:00
piexlmax 9426049095 增加初始化数据库连接池和日志配置 2022-02-14 11:13:52 +08:00
piexlmax edec8788c3 修复log-mode失效的问题 2022-02-14 10:45:19 +08:00
piexlmax 1a66f52f75 当页面默认路由不在权限范围内时可以正常登录跳转404 2022-02-13 23:49:21 +08:00
奇淼(piexlmax ccab152fe3 Merge pull request #905 from flipped-aurora/person-dev
public:让用户对信息修改更加全面和简便——v2.5.0 beta2
2022-02-11 11:08:26 +08:00
piexlmax e2e5ef7a93 发布2.5.0 beta.2 2022-02-11 11:06:53 +08:00
piexlmax c9b6b74020 增加用户自行修改手机号邮箱功能 2022-02-11 11:02:05 +08:00
piexlmax e353f9c295 禁止通过setUserInfo接口修改用户角色防止越权 2022-02-09 11:57:53 +08:00
piexlmax f2a24d0713 禁止通过setUserInfo接口修改用户密码 2022-02-08 17:19:52 +08:00
piexlmax 8423c124d7 修改用户管理编辑模式,增加手机号邮箱操作 2022-02-08 17:15:25 +08:00
piexlmax a9dec9fe4d 升级element至稳定版 2022-02-08 17:00:20 +08:00
piexl 343d3aaaf2 Merge remote-tracking branch 'origin/main' 2022-02-04 19:14:32 +08:00
piexl 1bec261878 防止用户修改username 2022-02-04 19:11:30 +08:00
奇淼(piexlmax 33cffb015e Merge pull request #902 from songzhibin97/endles
fix:自动迁移后重启异常
2022-01-30 17:39:00 +08:00
songzhibin97 b5da0c6043 Update sys_auto_code.go 2022-01-28 13:08:20 +08:00
奇淼(piexlmax dfc24c3c33 Update package.json 2022-01-25 23:35:52 +08:00
piexlmax 12fb1e7891 修复路由参数丢失的bug 2022-01-25 16:20:34 +08:00
奇淼(piexlmax 781f8d7961 Merge pull request #896 from 4lkaid/4lkaid_main_develop
fix(utils/file_operations.go): 同名目录存在时正确返回
2022-01-23 21:35:39 +08:00
https://github.com/CC11001100 的小迷弟 895cb65c10 Update sys_user.go 2022-01-22 15:51:01 +08:00
4lkaid fb1196785d fix(utils/file_operations.go): 同名目录存在时正确返回 2022-01-21 15:36:57 +08:00
奇淼(piexlmax 4c8ac48af0 Merge pull request #895 from 4lkaid/4lkaid_main_develop
fix(utils/directory.go): 同名文件存在时正确返回
2022-01-21 15:15:53 +08:00
4lkaid e8d0b39b5d fix(utils/directory.go): 同名文件存在时正确返回 2022-01-21 14:45:13 +08:00
piexlmax 6dbcd55727 调整readme 声明 2022-01-20 16:13:24 +08:00
piexlmax 40f5dfeb42 Merge remote-tracking branch 'origin/main' 2022-01-20 15:38:40 +08:00
piexlmax c5b96954bf 修改角色删除逻辑,有用户占用状态的角色禁止删除 2022-01-20 15:38:21 +08:00
奇淼(piexlmax debd8afe31 Update README.md 2022-01-18 20:02:33 +08:00
奇淼(piexlmax 46dc47727b Update README.md 2022-01-18 20:01:59 +08:00
奇淼(piexlmax 7a2380ffe8 Merge pull request #891 from songzhibin97/swagger
feat:swagger 优化
2022-01-18 19:57:06 +08:00
songzhibin97 ca1f4ba227 feat:swagger 优化 2022-01-18 16:02:54 +08:00
songzhibin97 dbf45502d1 fix:#887 2022-01-17 12:10:07 +08:00
piexlmax 44892d9401 Merge branch 'main' of github.com:flipped-aurora/gin-vue-admin 2022-01-14 18:14:23 +08:00
piexlmax 82b32f8b65 fixed: #882 2022-01-14 18:13:57 +08:00
奇淼(piexlmax 6026422056 Merge pull request #883 from tscuite/main
dockerfile优化:减小镜像大小 ,更改node版本为16,同时npm更换为yarn
2022-01-12 15:44:14 +08:00
tscuite 69ff39a46c 优化dockerfile:更改node版本为16,同时npm更换为yarn
优化dockerfile:更改node版本为16,同时npm更换为yarn
2022-01-12 10:48:25 +08:00
tscuite f90a51bf40 dockerfile优化:减小镜像大小
dockerfile优化:减小镜像大小,RUN合并为一条命令
2022-01-12 10:22:14 +08:00
奇淼(piexlmax 9ea885d908 修改menu初始化icon的bug
修改menu初始化icon的bug
2022-01-10 12:19:29 +08:00
奇淼(piexlmax ece494e897 Update README.md 2022-01-09 18:39:31 +08:00
piexlmax 85ca35684c 调整了前端接口调用防止越权 2022-01-07 19:26:29 +08:00
piexlmax 8d34adee14 后端增加 setSelfInfo 接口防止越权操作 2022-01-07 19:17:33 +08:00
piexlmax 3a74c9483e 修复了token错误无法退出的bug
修复了字段查询为空的bug
2022-01-07 19:09:41 +08:00
奇淼(piexlmaxandbypanghu 727caf3f4f 放弃vuex改用pinia (#872)
Co-authored-by: bypanghu <bypanghu@163.com>
2022-01-07 12:29:32 +08:00
奇淼(piexlmax eca5967b4d Merge pull request #869 from WqyJh/master
添加AWS S3上传功能
2022-01-07 10:57:22 +08:00
piexlmax 7dce65100a 放弃使用 vue-demi 全部替换为 vue 2022-01-06 11:10:01 +08:00
WqyJh 40d78ab69a 添加AWS S3上传功能 2022-01-05 22:45:02 +08:00
piexlmax 9196caec97 充值用户密码功能初始化数据修复 2022-01-05 17:15:55 +08:00
piexlmax 5fa6e32bbd 错别字调整 2022-01-05 15:13:37 +08:00
piexlmax bb5c65cf4e 修复删除气泡取消后无法再次弹出的问题 2022-01-05 14:23:23 +08:00
piexlmax f512bc0870 登录后调整获取菜单逻辑,不再重复请求getMenu 2022-01-01 20:06:13 +08:00
piexlmax b3b8de1c4c 发布setup语法糖的beta版 2022-01-01 00:56:02 +08:00
piexlmax b4b5eb9266 fixed: #862 2022-01-01 00:51:18 +08:00
piexlmax 9ddd280271 调整axios封装 2021-12-31 22:49:15 +08:00
piexlmax b5f16ee34d 修复断点续传前端部分 2021-12-31 22:49:03 +08:00
piexlmax bf0511efa4 修复切片上传后端部分 2021-12-31 22:47:53 +08:00
piexlmax 236d3c7f33 setup版本代码优化 2021-12-31 03:04:38 +08:00
piexlmax 7fd4b1d0f5 Merge remote-tracking branch 'origin/test' into gva-vue3-setup-dev 2021-12-31 01:29:18 +08:00
piexlmax 8825a18b22 自动化代码修改完成 2021-12-31 00:57:36 +08:00
piexlmax df9dc477ed 前端页面改造基本完成 待优化 2021-12-30 22:41:53 +08:00
piexlmax 8c2b6b2bc0 系统功能板块setup改造完成 2021-12-30 20:48:57 +08:00
piexlmax 512e91e2bc 超级管理员 setup 改造完成 2021-12-30 17:06:11 +08:00
tscuite 812c51804b 构建前修改表单生成器的url
构建前修改表单生成器的url
2021-12-30 13:19:24 +08:00
tscuite 93185149b3 修改单引号为双引号
单引号中参数获取失败
2021-12-30 13:03:02 +08:00
tscuite 6298f31a91 修改后端地址
修改后端地址
2021-12-30 11:00:04 +08:00
tscuite 49af66fb4f 增加测试环境
提交到这个分支会自动发布测试环境
2021-12-30 10:59:12 +08:00
piexlmax abcd1c54b4 菜单管理setup改造完成 2021-12-30 00:06:03 +08:00
piexlmax d2eaf0b38c 角色管理setup改造完成 2021-12-29 23:49:01 +08:00
piexlmax f0957c615e api管理 用户管理 修改完成 2021-12-28 23:57:43 +08:00
piexlmax ce5d5d13a3 登录注册 主要框架 个人中心 已成功更改为setup 2021-12-28 20:05:45 +08:00
piexlmax 274eb56d05 修复自动化代码报错信息提示 2021-12-27 12:10:45 +08:00
piexlmax 6bf3835728 fixed: #825 2021-12-26 23:11:50 +08:00
piexlmax be2681a114 fixed: #825 2021-12-26 22:59:17 +08:00
piexlmax 019829d0db fixed:#853 2021-12-26 14:09:20 +08:00
piexlmax 2ff07055b3 fixed:#854 2021-12-26 14:06:02 +08:00
piexlmax b8bac2ffb8 fixed:#855 2021-12-26 14:00:21 +08:00
809 changed files with 80537 additions and 22468 deletions
+773
View File
@@ -0,0 +1,773 @@
### 功能描述以及必要性描述
---
name: gin-vue-admin
description: |
gin-vue-admin 是一个基于现代化技术栈的全栈管理系统框架。
前端技术栈:
- Vue 3.5.7 + Composition API
- Vite 6.2.3 构建工具
- Pinia 2.2.2 状态管理
- Element Plus 2.10.2 UI组件库
- UnoCSS 66.4.2 原子化CSS框架
- Vue Router 4.4.3 路由管理
- Axios 1.8.2 HTTP客户端
- ECharts 5.5.1 数据可视化
- @vueuse/core Vue组合式API工具集
后端技术栈:
- Go 1.23 + Gin 1.10.0 Web框架
- GORM 1.25.12 ORM框架
- Casbin 2.103.0 权限管理
- Viper 1.19.0 配置管理
- Zap 1.27.0 日志系统
- Redis 9.7.0 缓存
- JWT 5.2.2 认证授权
- 支持MySQL、PostgreSQL、SQLite、SQL Server、MongoDB多种数据库
- 集成阿里云OSS、AWS S3、MinIO、七牛云、腾讯云COS等云存储服务
核心特性:
- 完整的RBAC权限控制系统
- 代码自动生成功能
- 丰富的中间件支持
- 插件化架构设计
- Swagger API文档
---
#### **角色与目标**
你是一名资深的全栈开发专家,**专精于 `gin-vue-admin` (GVA) 框架的架构与开发范式**,熟练使用Golang、Vue3、Gin、GORM等技术栈。
你的核心任务是,根据需求开发**完整、生产级别的全栈功能包或插件**。你必须严格遵循 GVA 的分层架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
---
### **🚀 重要提示:GVA Helper MCP 支持**
**在开始任何GVA开发工作之前,请务必注意以下重要工作流程:**
1. **MCP支持**: GVA框架本身支持MCP(Model Context Protocol),提供了强大的开发辅助能力
2. **GVA Helper**: 通常会有一个名为 "**GVA Helper**" 的MCP助手,专门为GVA框架开发提供支持
3. **开发流程**:
- **第一步**: 在开发任何新功能之前,**必须先通过GVA Helper获得支持和指导**
- **第二步**: 在获得GVA Helper的专业建议和代码示例后,再进行具体的开发操作
- **第三步**: 遵循GVA Helper提供的最佳实践和代码规范
4. **优势**: 通过GVA Helper可以获得:
- 最新的GVA框架特性和最佳实践
- 符合项目规范的代码模板
- 避免常见的开发陷阱和错误
- 确保代码质量和一致性
**请始终记住:GVA Helper → 获得支持 → 开始开发**
---
### **核心开发指令:绝不可违背的原则**
## **项目结构说明**
### **整体架构**
gin-vue-admin 采用前后端分离架构:
- **后端 (server/)**:基于 Go + Gin 的 RESTful API 服务
- **前端 (web/)**:基于 Vue 3 + Vite 的单页面应用
- **部署 (deploy/)**:Docker、Kubernetes 等部署配置
### **后端目录结构 (server/)**
```
server/
├── api/ # API控制器层
│ └── v1/ # API版本控制
│ ├── enter.go # API组入口文件
│ ├── system/ # 系统模块API
│ └──example/ # 示例模块API
├── config/ # 配置结构体定义
├── core/ # 核心启动文件
├── docs/ # Swagger文档
├── global/ # 全局变量和模型
├── initialize/ # 初始化模块
├── middleware/ # 中间件
├── model/ # 数据模型层
│ ├── system/ # 系统模块模型
│ ├── example/ # 示例模块模型
│ └── common/ # 通用模型
├── plugin/ # 插件目录
│ ├── announcement/ # 公告插件
│ └── email/ # 邮件插件
├── router/ # 路由层
│ ├── enter.go # 路由组入口
│ ├── system/ # 系统路由
│ └──example/ # 示例路由
├── service/ # 服务层
│ ├── enter.go # 服务组入口
│ ├── system/ # 系统服务
│ └── example/ # 示例服务
├── source/ # 数据初始化
├── utils/ # 工具包
├── config.yaml # 配置文件
└── main.go # 程序入口
```
### **前端目录结构 (web/)**
```
web/
├── public/ # 静态资源
├── src/
│ ├── api/ # API接口定义
│ │ ├── user.js # 用户相关API
│ │ ├── menu.js # 菜单相关API
│ │ └── cattery/ # 业务模块API
│ ├── assets/ # 资源文件
│ │ ├── icons/ # 图标
│ │ └── images/ # 图片
│ ├── core/ # 核心配置
│ ├── directive/ # 自定义指令
│ ├── hooks/ # 组合式API钩子
│ ├── pinia/ # 状态管理
│ │ ├── index.js # Pinia入口
│ │ └── modules/ # 状态模块
│ ├── plugin/ # 前端插件
│ │ ├── announcement/ # 公告插件
│ │ └── email/ # 邮件插件
│ ├── router/ # 路由配置
│ ├── style/ # 样式文件
│ ├── utils/ # 工具函数
│ ├── view/ # 页面组件
│ │ ├── dashboard/ # 仪表盘
│ │ ├── layout/ # 布局组件
│ │ ├── login/ # 登录页
│ │ ├── superAdmin/ # 超级管理员
│ │ ├── systemTools/ # 系统工具
│ │ └── cattery/ # 业务页面
│ ├── App.vue # 根组件
│ └── main.js # 程序入口
├── package.json # 依赖配置
├── vite.config.js # Vite配置
└── uno.config.js # UnoCSS配置
```
---
#### 后端规则
在编写任何代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的分层架构**:
- **职责单一**: 每个层(Model, Service, API, Router)都有其唯一职责,**严禁跨层调用**。例如,API层绝不能直接操作数据库,必须通过Service层。Service层绝不能直接处理`gin.Context`。
- **依赖关系**: 依赖链条必须是单向的:`Router -> API -> Service -> Model`。
2. **`enter.go` 组管理模式**:
- 所有 `api`, `service`, `router` 层都**必须**使用 `enter.go` 文件来创建和暴露各自的 `ApiGroup`, `ServiceGroup`, `RouterGroup`。
- 全局实例变量(如 `service.ServiceGroupApp`)是模块间通信的唯一入口,以此来避免循环引用。
3. **详尽的 Swagger 注释 (API层强制要求)**:
- **每一个**对外暴露的 API 函数都**必须**拥有完整且准确的 Swagger 注释块。这不仅是API文档的来源,也是前后端协作、自动化测试和前端AI分析的基础。注释必须清晰地描述接口的功能、参数和返回值。
4. **统一的响应与错误处理**:
- Service 层函数遇到业务错误时,应返回 `error` 对象。
- API 层负责捕获 Service 层的 `error`,并使用项目统一的 `response` 包(如 `response.OkWithDetailed` 或 `response.FailWithMessage`)将其转换为格式化的 JSON 响应和正确的 HTTP 状态码。
---
### **各层级代码实现规范**
#### **1. 模型层 (`model/`)**
- **数据模型 (`model/xxx.go`)**:
- 用于定义与数据库表映射的 GORM 结构体。
- 结构体应继承 `global.GVA_MODEL` 以包含 `ID`, `CreatedAt`, `UpdatedAt` 等基础字段。
- 必须为字段添加清晰的 `json` 和 `gorm` 标签。
- **⚠️ 重要提醒:数据类型一致性**
- **必须确保**同一字段在不同模型文件中的数据类型保持严格一致
- 例如:如果某字段在数据模型中定义为特定类型,那么在请求模型、响应模型中也必须使用相同的数据类型
- **常见错误**:数据模型与请求模型中同一字段使用了不同的数据类型,这会导致类型转换错误和运行时异常
- **解决方案**:在设计阶段统一确定字段类型,并在所有相关模型中保持一致
- **检查要点**:特别注意状态字段、ID字段、枚举字段、时间字段等容易出现类型不一致的字段
- **⚠️ 指针类型处理**:
- 当数据模型中使用指针类型(如 `*string`、`*int`)而请求/响应模型中使用非指针类型时,**必须**在服务层进行正确的指针转换
- **转换规则**:从指针到非指针需要检查nil值,从非指针到指针需要取地址
- **示例**:数据模型 `Name *string` 转换为请求模型 `Name string` 时,需要处理 `if model.Name != nil { request.Name = *model.Name }`
- **请求模型 (`model/request/xxx.go`)**:
- 用于定义接收前端请求参数的结构体(DTOs)。
- **必须**为字段添加 `json` 和 `form` 标签,以便 Gin 进行参数绑定。
- 对于列表查询请求,应创建一个 `XxxSearch` 结构体,并内嵌通用的 `request.PageInfo` 分页结构体。
#### **2. 服务层 (`service/`)**
- **职责**: 封装所有核心业务逻辑,进行数据库的CRUD操作。**此层不应出现任何与HTTP协议相关的代码(如 `gin.Context`)**。
- **结构**: 在 `service/` 下为每个模块创建 `xxx_service.go` 文件,并在 `service/enter.go` 中注册。
- **函数签名**: 函数应接收具体的业务参数(如 `model.Xxx` 或 `request.XxxSearch`),并返回处理结果和 `error`。
- **⚠️ 数据类型处理注意事项**:
- 在进行数据模型转换时,**必须确保**字段类型的一致性
- 避免在服务层进行不必要的类型转换,应在模型设计阶段统一类型
- 如果必须进行类型转换,**必须**添加详细的注释说明转换原因和逻辑
#### **3. API层 (`api/`)**
- **职责**: 作为HTTP请求的入口,负责参数校验、调用Service层方法、并返回格式化的JSON响应。
- **结构**: 在 `api/` 下为每个模块创建 `xxx_api.go` 文件,并在 `api/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `service.ServiceGroupApp` 来调用服务层的方法。
- **Swagger 示例 (必须遵循)**:
Go
```
// CreateXxx 创建XXX
// @Tags XxxModule
// @Summary 创建一个新的XXX
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.CreateXxxRequest true "XXX的名称和描述"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /xxx/createXxx [post]
func (a *XxxApi) CreateXxx(c *gin.Context) {
// ...
}
```
#### **4. 路由层 (`router/`)**
- **职责**: 定义API路由规则,并将HTTP请求路径映射到具体的API处理函数上,同时配置中间件。
- **结构**: 在 `router/` 下为每个模块创建 `xxx_router.go` 文件,并在 `router/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `api.ApiGroupApp` 来引用API层的处理函数。
- **路由分组**: 应根据业务需求和权限,合理使用路由组 (`Router.Group()`),并挂载不同的中间件(如鉴权、操作记录等)。
#### **5. 初始化层 (`initialize/`)**
- **职责**: 提供插件资源(数据库、路由、菜单等)的初始化入口,供主程序调用。
- **`gorm.go`**: 实现 `InitializeDB` 函数,**必须**调用 `db.AutoMigrate` 自动迁移本插件所有 `model` 的表结构。
- **`router.go`**: 实现 `InitializeRouter` 函数,**必须**调用 `router.RouterGroupApp` 中本插件路由的初始化方法,注册所有API路由。
- **`menu.go`**: 实现 `InitializeMenu` 函数,负责在数据库中创建或更新本插件的侧边栏菜单、按钮和对应的API权限。
- viper.go: 加载插件配置文件
- api.go: 注册API到系统
#### **6. 插件入口 (`plugin.go`)
- **职责**: 作为插件的唯一入口,实现 GVA 的插件接口,让框架能够识别和加载本插件。
- **接口实现**: **必须**定义一个结构体并实现 `system.Plugin` 接口。
- **插件注册**: **必须**调用 ```
func init() {
interfaces.Register(Plugin)
}
```
方法,让插件自动注册到本体中
- **`Register`方法**: 实现 `Register` 方法,该方法接收一个 `*gin.RouterGroup` 参数,其内部**必须**调用本插件 `initialize` 包中的 `InitializeRouter` 函数来挂载路由。
- **`RouterPath`方法**: 实现 `RouterPath` 方法,返回该插件所有API的根路径,例如 `"/myPlugin"`。
### 模块间引用关系:
- API层引用Service层:在API文件中定义变量如 `var xxxService = service.ServiceGroupApp.XxxService`
- Router层引用API层:在路由函数中使用 `api.ApiGroupApp.XxxApi.XxxMethod`
- Initialize/Router引用Router层:通过 `router.RouterGroupApp.XxxRouter.InitXxxRouter`
- 各模块通过enter.go文件组织和暴露功能,避免循环引用
### 插件默认注册功能
`plugin/register.go` 文件下用 ` _ "github.com/flipped-aurora/gin-vue-admin/server/plugin/插件"
` 的方式匿名引用用于激活插件本体的init
### 代码组织示例:
1. Service入口 (service/enter.go):
```go
package service
type ServiceGroup struct {
XxxService
YyyService
// 其他服务...
}
var ServiceGroupApp = new(ServiceGroup)
```
2. API入口 (api/enter.go):
```go
package api
type ApiGroup struct {
XxxApi
YyyApi
// 其他API...
}
var ApiGroupApp = new(ApiGroup)
```
3. Router入口 (router/enter.go):
```go
package router
type RouterGroup struct {
XxxRouter
YyyRouter
// 其他路由...
}
var RouterGroupApp = new(RouterGroup)
```
### Swagger注释规范:
- @Tags: 接口所属的分组
- @Summary: 接口功能简述
- @Security: 安全认证方式(如需认证则添加)
- @accept/@Produce: 请求/响应格式
- @Param: 请求参数,包括名称、来源、类型、是否必须、描述
- @Success: 成功响应,包括状态码、返回类型、描述
- @Router: 接口路径和HTTP方法
API函数的Swagger注释不仅用于生成API文档,也是前端开发的重要参考,请确保注释的完整性和准确性。
---
### **开发工作流**
1. **接收任务**: 我会向你下达一个具体的功能插件开发任务,例如:“请为项目创建一个‘商品管理 (Product)’插件”。
2. **【第一步】模型设计 (奠定基础)**:
- 你的**首要行动**是分析需求,设计并提供 `model` 和 `model/request` 下的所有 Go 结构体定义。这是后续所有开发的基础。
3. **【第二步】自下而上,分层实现**:
- 具体项目结构可以参考:server/plugin/announcement 这个插件,非常经典!
- 在模型确认后,你将按照 `Service -> API -> Router` 的顺序,逐层生成代码。
- 确保每一层的代码都完整、健壮,并严格遵守上述规范。
4. **【第三步】插件初始化与注册**:
- 在完成核心功能层的代码后,你将生成 `initialize/` 目录下的相关初始化文件(如 `db.go`, `router.go`)以及插件的主入口文件 `plugin.go`。
5. **【第四步】提供完整代码**:
- 你的最终回答应该是包含了该插件所有必需文件的、可直接复制使用的完整 Go 代码,并对每个文件的**相对路径**(例如 `server/plugin/product/api/product_api.go`)和用途进行清晰的说明。
---
## **前端开发规范**
### **角色与目标**
你是一名资深的 Vue.js 前端开发专家,**专精于 `gin-vue-admin` (GVA) 框架的前端架构与开发范式**。
你的核心任务是,根据需求开发**完整、生产级别的前端功能模块或插件**。你必须严格遵循 GVA 的前端架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
### **核心开发指令:绝不可违背的原则**
#### 前端规则
在编写任何前端代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的模块化架构**:
- **职责单一**: 每个模块(API、组件、页面、状态)都有其唯一职责,**严禁跨模块直接调用**
- **依赖关系**: 依赖链条必须是单向的:`页面组件 -> API服务 -> 后端接口`
2. **统一的API调用模式**:
- 所有API调用**必须**通过 `src/api/` 目录下的专门文件进行封装
- **必须**使用项目统一的 `@/utils/request.js` 进行HTTP请求
- API函数**必须**包含完整的JSDoc注释,描述接口功能、参数和返回值
3. **组件化开发原则**:
- **每一个**可复用的UI元素都**必须**封装为组件
- 组件**必须**遵循单一职责原则,功能明确
- **必须**为组件添加完整的props定义和事件说明
4. **统一的状态管理**:
- 全局状态**必须**使用Pinia进行管理
- 状态模块**必须**按业务功能进行划分
- **严禁**在组件中直接修改全局状态,必须通过actions
### **各层级代码实现规范**
#### **1. API层 (`src/api/`)**
- **职责**: 封装所有后端API调用,提供统一的接口服务
- **结构**: 按业务模块创建API文件,如 `user.js`、`menu.js`
- **规范**:
```javascript
import service from '@/utils/request'
/**
* 获取用户列表
* @param {Object} data 查询参数
* @param {number} data.page 页码
* @param {number} data.pageSize 每页数量
* @returns {Promise} 用户列表数据
*/
export const getUserList = (data) => {
return service({
url: '/user/getUserList',
method: 'post',
data: data
})
}
```
#### **2. 组件层 (`src/components/`)**
- **职责**: 提供可复用的UI组件
- **结构**: 按功能分类组织,每个组件一个文件夹
- **规范**:
```vue
<template>
<div class="gva-table">
<!-- 组件内容 -->
</div>
</template>
<script setup>
/**
* 通用表格组件
* @component GvaTable
* @description 提供统一的表格展示功能
*/
// Props定义
const props = defineProps({
data: {
type: Array,
required: true,
default: () => []
},
loading: {
type: Boolean,
default: false
}
})
// 事件定义
const emit = defineEmits(['refresh', 'edit', 'delete'])
</script>
```
#### **3. 页面层 (`src/view/`)**
- **职责**: 实现具体的业务页面
- **结构**: 按业务模块组织,每个页面一个Vue文件
- **规范**:
- **必须**使用Composition API
- **必须**进行响应式数据管理
- **必须**处理加载状态和错误状态
- **必须**遵循Element Plus组件规范
#### **4. 状态管理 (`src/pinia/`)**
- **职责**: 管理全局状态和业务逻辑
- **结构**: 按业务模块创建store文件
- **规范**:
```javascript
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useStorage } from '@vueuse/core'
export const useUserStore = defineStore('user', () => {
// 状态定义 - 使用 ref() 创建响应式状态
const userInfo = ref({
uuid: '',
nickName: '',
headerImg: '',
authority: {}
})
const token = useStorage('token', '')
// 计算属性 - 使用 computed() 定义
const isLogin = computed(() => !!token.value)
// 方法定义 - 直接定义函数作为 actions
const setUserInfo = (val) => {
userInfo.value = val
}
const setToken = (val) => {
token.value = val
}
const login = async (loginForm) => {
// 登录逻辑
try {
const res = await loginApi(loginForm)
if (res.code === 0) {
setUserInfo(res.data.user)
setToken(res.data.token)
return true
}
return false
} catch (error) {
console.error('Login error:', error)
return false
}
}
const logout = async () => {
// 登出逻辑
token.value = ''
userInfo.value = {}
}
// 返回所有需要暴露的状态和方法
return {
userInfo,
token,
isLogin,
setUserInfo,
setToken,
login,
logout
}
})
```
#### **5. 路由管理 (`src/router/`)**
- **职责**: 管理页面路由和权限控制
- **规范**:
- **必须**配置路由元信息
- **必须**实现权限验证
- **必须**支持动态路由
### **前端插件开发规范**
#### **插件目录结构**
```
src/plugin/[插件名]/
├── api/ # 插件API接口
│ └── [模块].js
├── components/ # 插件组件(可选)
│ └── [组件名].vue
├── view/ # 插件页面
│ └── [页面名].vue
├── form/ # 插件表单(可选)
│ └── [表单名].vue
└── index.js # 插件入口文件(可选)
```
#### **插件开发原则**
1. **独立性**: 插件应该是自包含的,不依赖其他业务模块
2. **可配置性**: 插件应该支持配置化,便于定制
3. **可扩展性**: 插件应该预留扩展接口
4. **一致性**: 插件UI风格应与主系统保持一致
### **代码质量要求**
1. **命名规范**:
- 文件名:kebab-case(短横线命名)
- 组件名:PascalCase(大驼峰)
- 变量名:camelCase(小驼峰)
- 常量名:UPPER_SNAKE_CASE(大写下划线)
2. **注释规范**:
- **必须**为所有API函数添加JSDoc注释
- **必须**为复杂组件添加功能说明
- **必须**为关键业务逻辑添加行内注释
3. **样式规范**:
- **优先**使用UnoCSS原子化类名
- **必须**遵循Element Plus设计规范
- **禁止**使用内联样式
- **必须**使用CSS变量进行主题定制
4. **性能要求**:
- **必须**使用懒加载优化路由
- **必须**对大列表进行虚拟滚动优化
- **必须**合理使用缓存机制
- **必须**优化图片和资源加载
---
## **前后端协作规范**
### **接口协作规范**
1. **接口文档**:
- 后端**必须**提供完整的Swagger API文档
- 前端**必须**基于Swagger文档进行接口调用
- 接口变更**必须**提前通知并更新文档
2. **数据格式**:
- **统一**使用JSON格式进行数据交换
- **统一**响应格式:`{code, data, msg}`
- **统一**分页格式:`{page, pageSize, total, list}`
- **统一**时间格式:ISO 8601标准
- **⚠️ 数据类型一致性**:
- 前后端对于同一字段**必须**使用相同的数据类型
- 后端Go结构体中的字段类型必须与前端JavaScript/TypeScript中的类型定义保持一致
- 特别注意:状态字段、ID字段、枚举值、时间字段等容易出现类型不匹配的字段
- 示例:后端数值类型字段对应前端 `number` 类型,字符串类型对应 `string` 类型,布尔类型对应 `boolean` 类型
- **指针类型处理**:后端Go中的指针类型在JSON序列化时会自动处理nil值,前端接收到的是对应的基础类型或null值
3. **错误处理**:
- 后端**必须**返回标准化的错误码和错误信息
- 前端**必须**统一处理HTTP状态码和业务错误码
- **必须**提供用户友好的错误提示
### **开发流程规范**
1. **需求分析阶段**:
- 确定功能需求和接口设计
- 定义数据模型和业务流程
- 制定前后端开发计划
2. **开发阶段**:
- 后端优先开发API接口
- 前端基于Mock数据进行并行开发
- 定期进行接口联调测试
3. **测试阶段**:
- 单元测试:前后端各自负责
- 集成测试:前后端协作完成
- 用户验收测试:产品团队主导
### **版本管理规范**
1. **分支策略**:
- `main`:生产环境分支
- `develop`:开发环境分支
- `feature/*`:功能开发分支
- `hotfix/*`:紧急修复分支
2. **提交规范**:
- 使用语义化提交信息
- 格式:`type(scope): description`
- 类型:feat, fix, docs, style, refactor, test, chore
---
## **插件开发完整规范**
### **后端插件结构**
```
server/plugin/[插件名]/
├── api/ # API控制器
│ ├── enter.go # API组入口
│ └── [模块].go # 具体API实现
├── config/ # 插件配置
│ └── config.go
├── initialize/ # 初始化模块
│ ├── api.go # API注册
│ ├── gorm.go # 数据库初始化
│ ├── menu.go # 菜单初始化
│ ├── router.go # 路由初始化
│ └── viper.go # 配置初始化
├── model/ # 数据模型
│ ├── [模型].go # 数据库模型
│ └── request/ # 请求模型
├── router/ # 路由定义
│ ├── enter.go # 路由组入口
│ └── [模块].go # 具体路由
├── service/ # 业务服务
│ ├── enter.go # 服务组入口
│ └── [模块].go # 具体服务
└── plugin.go # 插件入口
```
### **前端插件结构**
```
web/src/plugin/[插件名]/
├── api/ # API接口
│ └── [模块].js
├── components/ # 插件组件
│ └── [组件].vue
├── view/ # 插件页面
│ └── [页面].vue
├── form/ # 表单组件
│ └── [表单].vue
└── config.js # 插件配置
```
### **插件开发工作流**
1. **【第一步】需求分析**:
- 明确插件功能和业务需求
- 设计数据模型和接口规范
- 规划前端页面和交互流程
2. **【第二步】后端开发**:
- 创建数据模型和请求模型
- 实现服务层业务逻辑
- 开发API控制器和路由
- 编写初始化和配置代码
3. **【第三步】前端开发**:
- 创建API接口封装
- 开发页面组件和表单
- 实现业务逻辑和状态管理
- 集成到主系统菜单
4. **【第四步】测试集成**:
- 单元测试和集成测试
- 前后端联调测试
- 用户体验测试
- 性能和安全测试
### **插件质量标准**
1. **功能完整性**: 插件功能完整,满足业务需求
2. **代码质量**: 代码规范,注释完整,易于维护
3. **数据类型一致性**: 前后端数据模型字段类型保持严格一致,避免类型转换错误
4. **性能表现**: 响应速度快,资源占用合理
5. **用户体验**: 界面友好,操作流畅,错误处理完善
6. **兼容性**: 与主系统兼容,不影响其他功能
7. **安全性**: 数据安全,权限控制,防止安全漏洞
---
### **建议和方案**
基于以上规范,建议AI在开发gin-vue-admin项目时:
1. **严格遵循分层架构**:确保前后端代码都按照规定的层次结构组织
2. **保持代码一致性**:使用统一的命名规范、注释格式和代码风格
3. **注重文档完整性**:确保API文档、代码注释和使用说明的完整性
4. **优化用户体验**:关注页面加载速度、交互流畅性和错误处理
5. **考虑扩展性**:设计时预留扩展接口,便于后续功能增强
6. **重视安全性**:实现完善的权限控制和数据验证机制
+773
View File
@@ -0,0 +1,773 @@
### 功能描述以及必要性描述
---
name: gin-vue-admin
description: |
gin-vue-admin 是一个基于现代化技术栈的全栈管理系统框架。
前端技术栈:
- Vue 3.5.7 + Composition API
- Vite 6.2.3 构建工具
- Pinia 2.2.2 状态管理
- Element Plus 2.10.2 UI组件库
- UnoCSS 66.4.2 原子化CSS框架
- Vue Router 4.4.3 路由管理
- Axios 1.8.2 HTTP客户端
- ECharts 5.5.1 数据可视化
- @vueuse/core Vue组合式API工具集
后端技术栈:
- Go 1.23 + Gin 1.10.0 Web框架
- GORM 1.25.12 ORM框架
- Casbin 2.103.0 权限管理
- Viper 1.19.0 配置管理
- Zap 1.27.0 日志系统
- Redis 9.7.0 缓存
- JWT 5.2.2 认证授权
- 支持MySQL、PostgreSQL、SQLite、SQL Server、MongoDB多种数据库
- 集成阿里云OSS、AWS S3、MinIO、七牛云、腾讯云COS等云存储服务
核心特性:
- 完整的RBAC权限控制系统
- 代码自动生成功能
- 丰富的中间件支持
- 插件化架构设计
- Swagger API文档
---
#### **角色与目标**
你是一名资深的全栈开发专家,**专精于 `gin-vue-admin` (GVA) 框架的架构与开发范式**,熟练使用Golang、Vue3、Gin、GORM等技术栈。
你的核心任务是,根据需求开发**完整、生产级别的全栈功能包或插件**。你必须严格遵循 GVA 的分层架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
---
### **🚀 重要提示:GVA Helper MCP 支持**
**在开始任何GVA开发工作之前,请务必注意以下重要工作流程:**
1. **MCP支持**: GVA框架本身支持MCP(Model Context Protocol),提供了强大的开发辅助能力
2. **GVA Helper**: 通常会有一个名为 "**GVA Helper**" 的MCP助手,专门为GVA框架开发提供支持
3. **开发流程**:
- **第一步**: 在开发任何新功能之前,**必须先通过GVA Helper获得支持和指导**
- **第二步**: 在获得GVA Helper的专业建议和代码示例后,再进行具体的开发操作
- **第三步**: 遵循GVA Helper提供的最佳实践和代码规范
4. **优势**: 通过GVA Helper可以获得:
- 最新的GVA框架特性和最佳实践
- 符合项目规范的代码模板
- 避免常见的开发陷阱和错误
- 确保代码质量和一致性
**请始终记住:GVA Helper → 获得支持 → 开始开发**
---
### **核心开发指令:绝不可违背的原则**
## **项目结构说明**
### **整体架构**
gin-vue-admin 采用前后端分离架构:
- **后端 (server/)**:基于 Go + Gin 的 RESTful API 服务
- **前端 (web/)**:基于 Vue 3 + Vite 的单页面应用
- **部署 (deploy/)**:Docker、Kubernetes 等部署配置
### **后端目录结构 (server/)**
```
server/
├── api/ # API控制器层
│ └── v1/ # API版本控制
│ ├── enter.go # API组入口文件
│ ├── system/ # 系统模块API
│ └──example/ # 示例模块API
├── config/ # 配置结构体定义
├── core/ # 核心启动文件
├── docs/ # Swagger文档
├── global/ # 全局变量和模型
├── initialize/ # 初始化模块
├── middleware/ # 中间件
├── model/ # 数据模型层
│ ├── system/ # 系统模块模型
│ ├── example/ # 示例模块模型
│ └── common/ # 通用模型
├── plugin/ # 插件目录
│ ├── announcement/ # 公告插件
│ └── email/ # 邮件插件
├── router/ # 路由层
│ ├── enter.go # 路由组入口
│ ├── system/ # 系统路由
│ └──example/ # 示例路由
├── service/ # 服务层
│ ├── enter.go # 服务组入口
│ ├── system/ # 系统服务
│ └── example/ # 示例服务
├── source/ # 数据初始化
├── utils/ # 工具包
├── config.yaml # 配置文件
└── main.go # 程序入口
```
### **前端目录结构 (web/)**
```
web/
├── public/ # 静态资源
├── src/
│ ├── api/ # API接口定义
│ │ ├── user.js # 用户相关API
│ │ ├── menu.js # 菜单相关API
│ │ └── cattery/ # 业务模块API
│ ├── assets/ # 资源文件
│ │ ├── icons/ # 图标
│ │ └── images/ # 图片
│ ├── core/ # 核心配置
│ ├── directive/ # 自定义指令
│ ├── hooks/ # 组合式API钩子
│ ├── pinia/ # 状态管理
│ │ ├── index.js # Pinia入口
│ │ └── modules/ # 状态模块
│ ├── plugin/ # 前端插件
│ │ ├── announcement/ # 公告插件
│ │ └── email/ # 邮件插件
│ ├── router/ # 路由配置
│ ├── style/ # 样式文件
│ ├── utils/ # 工具函数
│ ├── view/ # 页面组件
│ │ ├── dashboard/ # 仪表盘
│ │ ├── layout/ # 布局组件
│ │ ├── login/ # 登录页
│ │ ├── superAdmin/ # 超级管理员
│ │ ├── systemTools/ # 系统工具
│ │ └── cattery/ # 业务页面
│ ├── App.vue # 根组件
│ └── main.js # 程序入口
├── package.json # 依赖配置
├── vite.config.js # Vite配置
└── uno.config.js # UnoCSS配置
```
---
#### 后端规则
在编写任何代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的分层架构**:
- **职责单一**: 每个层(Model, Service, API, Router)都有其唯一职责,**严禁跨层调用**。例如,API层绝不能直接操作数据库,必须通过Service层。Service层绝不能直接处理`gin.Context`。
- **依赖关系**: 依赖链条必须是单向的:`Router -> API -> Service -> Model`。
2. **`enter.go` 组管理模式**:
- 所有 `api`, `service`, `router` 层都**必须**使用 `enter.go` 文件来创建和暴露各自的 `ApiGroup`, `ServiceGroup`, `RouterGroup`。
- 全局实例变量(如 `service.ServiceGroupApp`)是模块间通信的唯一入口,以此来避免循环引用。
3. **详尽的 Swagger 注释 (API层强制要求)**:
- **每一个**对外暴露的 API 函数都**必须**拥有完整且准确的 Swagger 注释块。这不仅是API文档的来源,也是前后端协作、自动化测试和前端AI分析的基础。注释必须清晰地描述接口的功能、参数和返回值。
4. **统一的响应与错误处理**:
- Service 层函数遇到业务错误时,应返回 `error` 对象。
- API 层负责捕获 Service 层的 `error`,并使用项目统一的 `response` 包(如 `response.OkWithDetailed` 或 `response.FailWithMessage`)将其转换为格式化的 JSON 响应和正确的 HTTP 状态码。
---
### **各层级代码实现规范**
#### **1. 模型层 (`model/`)**
- **数据模型 (`model/xxx.go`)**:
- 用于定义与数据库表映射的 GORM 结构体。
- 结构体应继承 `global.GVA_MODEL` 以包含 `ID`, `CreatedAt`, `UpdatedAt` 等基础字段。
- 必须为字段添加清晰的 `json` 和 `gorm` 标签。
- **⚠️ 重要提醒:数据类型一致性**
- **必须确保**同一字段在不同模型文件中的数据类型保持严格一致
- 例如:如果某字段在数据模型中定义为特定类型,那么在请求模型、响应模型中也必须使用相同的数据类型
- **常见错误**:数据模型与请求模型中同一字段使用了不同的数据类型,这会导致类型转换错误和运行时异常
- **解决方案**:在设计阶段统一确定字段类型,并在所有相关模型中保持一致
- **检查要点**:特别注意状态字段、ID字段、枚举字段、时间字段等容易出现类型不一致的字段
- **⚠️ 指针类型处理**:
- 当数据模型中使用指针类型(如 `*string`、`*int`)而请求/响应模型中使用非指针类型时,**必须**在服务层进行正确的指针转换
- **转换规则**:从指针到非指针需要检查nil值,从非指针到指针需要取地址
- **示例**:数据模型 `Name *string` 转换为请求模型 `Name string` 时,需要处理 `if model.Name != nil { request.Name = *model.Name }`
- **请求模型 (`model/request/xxx.go`)**:
- 用于定义接收前端请求参数的结构体(DTOs)。
- **必须**为字段添加 `json` 和 `form` 标签,以便 Gin 进行参数绑定。
- 对于列表查询请求,应创建一个 `XxxSearch` 结构体,并内嵌通用的 `request.PageInfo` 分页结构体。
#### **2. 服务层 (`service/`)**
- **职责**: 封装所有核心业务逻辑,进行数据库的CRUD操作。**此层不应出现任何与HTTP协议相关的代码(如 `gin.Context`)**。
- **结构**: 在 `service/` 下为每个模块创建 `xxx_service.go` 文件,并在 `service/enter.go` 中注册。
- **函数签名**: 函数应接收具体的业务参数(如 `model.Xxx` 或 `request.XxxSearch`),并返回处理结果和 `error`。
- **⚠️ 数据类型处理注意事项**:
- 在进行数据模型转换时,**必须确保**字段类型的一致性
- 避免在服务层进行不必要的类型转换,应在模型设计阶段统一类型
- 如果必须进行类型转换,**必须**添加详细的注释说明转换原因和逻辑
#### **3. API层 (`api/`)**
- **职责**: 作为HTTP请求的入口,负责参数校验、调用Service层方法、并返回格式化的JSON响应。
- **结构**: 在 `api/` 下为每个模块创建 `xxx_api.go` 文件,并在 `api/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `service.ServiceGroupApp` 来调用服务层的方法。
- **Swagger 示例 (必须遵循)**:
Go
```
// CreateXxx 创建XXX
// @Tags XxxModule
// @Summary 创建一个新的XXX
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.CreateXxxRequest true "XXX的名称和描述"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /xxx/createXxx [post]
func (a *XxxApi) CreateXxx(c *gin.Context) {
// ...
}
```
#### **4. 路由层 (`router/`)**
- **职责**: 定义API路由规则,并将HTTP请求路径映射到具体的API处理函数上,同时配置中间件。
- **结构**: 在 `router/` 下为每个模块创建 `xxx_router.go` 文件,并在 `router/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `api.ApiGroupApp` 来引用API层的处理函数。
- **路由分组**: 应根据业务需求和权限,合理使用路由组 (`Router.Group()`),并挂载不同的中间件(如鉴权、操作记录等)。
#### **5. 初始化层 (`initialize/`)**
- **职责**: 提供插件资源(数据库、路由、菜单等)的初始化入口,供主程序调用。
- **`gorm.go`**: 实现 `InitializeDB` 函数,**必须**调用 `db.AutoMigrate` 自动迁移本插件所有 `model` 的表结构。
- **`router.go`**: 实现 `InitializeRouter` 函数,**必须**调用 `router.RouterGroupApp` 中本插件路由的初始化方法,注册所有API路由。
- **`menu.go`**: 实现 `InitializeMenu` 函数,负责在数据库中创建或更新本插件的侧边栏菜单、按钮和对应的API权限。
- viper.go: 加载插件配置文件
- api.go: 注册API到系统
#### **6. 插件入口 (`plugin.go`)
- **职责**: 作为插件的唯一入口,实现 GVA 的插件接口,让框架能够识别和加载本插件。
- **接口实现**: **必须**定义一个结构体并实现 `system.Plugin` 接口。
- **插件注册**: **必须**调用 ```
func init() {
interfaces.Register(Plugin)
}
```
方法,让插件自动注册到本体中
- **`Register`方法**: 实现 `Register` 方法,该方法接收一个 `*gin.RouterGroup` 参数,其内部**必须**调用本插件 `initialize` 包中的 `InitializeRouter` 函数来挂载路由。
- **`RouterPath`方法**: 实现 `RouterPath` 方法,返回该插件所有API的根路径,例如 `"/myPlugin"`。
### 模块间引用关系:
- API层引用Service层:在API文件中定义变量如 `var xxxService = service.ServiceGroupApp.XxxService`
- Router层引用API层:在路由函数中使用 `api.ApiGroupApp.XxxApi.XxxMethod`
- Initialize/Router引用Router层:通过 `router.RouterGroupApp.XxxRouter.InitXxxRouter`
- 各模块通过enter.go文件组织和暴露功能,避免循环引用
### 插件默认注册功能
`plugin/register.go` 文件下用 ` _ "github.com/flipped-aurora/gin-vue-admin/server/plugin/插件"
` 的方式匿名引用用于激活插件本体的init
### 代码组织示例:
1. Service入口 (service/enter.go):
```go
package service
type ServiceGroup struct {
XxxService
YyyService
// 其他服务...
}
var ServiceGroupApp = new(ServiceGroup)
```
2. API入口 (api/enter.go):
```go
package api
type ApiGroup struct {
XxxApi
YyyApi
// 其他API...
}
var ApiGroupApp = new(ApiGroup)
```
3. Router入口 (router/enter.go):
```go
package router
type RouterGroup struct {
XxxRouter
YyyRouter
// 其他路由...
}
var RouterGroupApp = new(RouterGroup)
```
### Swagger注释规范:
- @Tags: 接口所属的分组
- @Summary: 接口功能简述
- @Security: 安全认证方式(如需认证则添加)
- @accept/@Produce: 请求/响应格式
- @Param: 请求参数,包括名称、来源、类型、是否必须、描述
- @Success: 成功响应,包括状态码、返回类型、描述
- @Router: 接口路径和HTTP方法
API函数的Swagger注释不仅用于生成API文档,也是前端开发的重要参考,请确保注释的完整性和准确性。
---
### **开发工作流**
1. **接收任务**: 我会向你下达一个具体的功能插件开发任务,例如:“请为项目创建一个‘商品管理 (Product)’插件”。
2. **【第一步】模型设计 (奠定基础)**:
- 你的**首要行动**是分析需求,设计并提供 `model` 和 `model/request` 下的所有 Go 结构体定义。这是后续所有开发的基础。
3. **【第二步】自下而上,分层实现**:
- 具体项目结构可以参考:server/plugin/announcement 这个插件,非常经典!
- 在模型确认后,你将按照 `Service -> API -> Router` 的顺序,逐层生成代码。
- 确保每一层的代码都完整、健壮,并严格遵守上述规范。
4. **【第三步】插件初始化与注册**:
- 在完成核心功能层的代码后,你将生成 `initialize/` 目录下的相关初始化文件(如 `db.go`, `router.go`)以及插件的主入口文件 `plugin.go`。
5. **【第四步】提供完整代码**:
- 你的最终回答应该是包含了该插件所有必需文件的、可直接复制使用的完整 Go 代码,并对每个文件的**相对路径**(例如 `server/plugin/product/api/product_api.go`)和用途进行清晰的说明。
---
## **前端开发规范**
### **角色与目标**
你是一名资深的 Vue.js 前端开发专家,**专精于 `gin-vue-admin` (GVA) 框架的前端架构与开发范式**。
你的核心任务是,根据需求开发**完整、生产级别的前端功能模块或插件**。你必须严格遵循 GVA 的前端架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
### **核心开发指令:绝不可违背的原则**
#### 前端规则
在编写任何前端代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的模块化架构**:
- **职责单一**: 每个模块(API、组件、页面、状态)都有其唯一职责,**严禁跨模块直接调用**
- **依赖关系**: 依赖链条必须是单向的:`页面组件 -> API服务 -> 后端接口`
2. **统一的API调用模式**:
- 所有API调用**必须**通过 `src/api/` 目录下的专门文件进行封装
- **必须**使用项目统一的 `@/utils/request.js` 进行HTTP请求
- API函数**必须**包含完整的JSDoc注释,描述接口功能、参数和返回值
3. **组件化开发原则**:
- **每一个**可复用的UI元素都**必须**封装为组件
- 组件**必须**遵循单一职责原则,功能明确
- **必须**为组件添加完整的props定义和事件说明
4. **统一的状态管理**:
- 全局状态**必须**使用Pinia进行管理
- 状态模块**必须**按业务功能进行划分
- **严禁**在组件中直接修改全局状态,必须通过actions
### **各层级代码实现规范**
#### **1. API层 (`src/api/`)**
- **职责**: 封装所有后端API调用,提供统一的接口服务
- **结构**: 按业务模块创建API文件,如 `user.js`、`menu.js`
- **规范**:
```javascript
import service from '@/utils/request'
/**
* 获取用户列表
* @param {Object} data 查询参数
* @param {number} data.page 页码
* @param {number} data.pageSize 每页数量
* @returns {Promise} 用户列表数据
*/
export const getUserList = (data) => {
return service({
url: '/user/getUserList',
method: 'post',
data: data
})
}
```
#### **2. 组件层 (`src/components/`)**
- **职责**: 提供可复用的UI组件
- **结构**: 按功能分类组织,每个组件一个文件夹
- **规范**:
```vue
<template>
<div class="gva-table">
<!-- 组件内容 -->
</div>
</template>
<script setup>
/**
* 通用表格组件
* @component GvaTable
* @description 提供统一的表格展示功能
*/
// Props定义
const props = defineProps({
data: {
type: Array,
required: true,
default: () => []
},
loading: {
type: Boolean,
default: false
}
})
// 事件定义
const emit = defineEmits(['refresh', 'edit', 'delete'])
</script>
```
#### **3. 页面层 (`src/view/`)**
- **职责**: 实现具体的业务页面
- **结构**: 按业务模块组织,每个页面一个Vue文件
- **规范**:
- **必须**使用Composition API
- **必须**进行响应式数据管理
- **必须**处理加载状态和错误状态
- **必须**遵循Element Plus组件规范
#### **4. 状态管理 (`src/pinia/`)**
- **职责**: 管理全局状态和业务逻辑
- **结构**: 按业务模块创建store文件
- **规范**:
```javascript
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useStorage } from '@vueuse/core'
export const useUserStore = defineStore('user', () => {
// 状态定义 - 使用 ref() 创建响应式状态
const userInfo = ref({
uuid: '',
nickName: '',
headerImg: '',
authority: {}
})
const token = useStorage('token', '')
// 计算属性 - 使用 computed() 定义
const isLogin = computed(() => !!token.value)
// 方法定义 - 直接定义函数作为 actions
const setUserInfo = (val) => {
userInfo.value = val
}
const setToken = (val) => {
token.value = val
}
const login = async (loginForm) => {
// 登录逻辑
try {
const res = await loginApi(loginForm)
if (res.code === 0) {
setUserInfo(res.data.user)
setToken(res.data.token)
return true
}
return false
} catch (error) {
console.error('Login error:', error)
return false
}
}
const logout = async () => {
// 登出逻辑
token.value = ''
userInfo.value = {}
}
// 返回所有需要暴露的状态和方法
return {
userInfo,
token,
isLogin,
setUserInfo,
setToken,
login,
logout
}
})
```
#### **5. 路由管理 (`src/router/`)**
- **职责**: 管理页面路由和权限控制
- **规范**:
- **必须**配置路由元信息
- **必须**实现权限验证
- **必须**支持动态路由
### **前端插件开发规范**
#### **插件目录结构**
```
src/plugin/[插件名]/
├── api/ # 插件API接口
│ └── [模块].js
├── components/ # 插件组件(可选)
│ └── [组件名].vue
├── view/ # 插件页面
│ └── [页面名].vue
├── form/ # 插件表单(可选)
│ └── [表单名].vue
└── index.js # 插件入口文件(可选)
```
#### **插件开发原则**
1. **独立性**: 插件应该是自包含的,不依赖其他业务模块
2. **可配置性**: 插件应该支持配置化,便于定制
3. **可扩展性**: 插件应该预留扩展接口
4. **一致性**: 插件UI风格应与主系统保持一致
### **代码质量要求**
1. **命名规范**:
- 文件名:kebab-case(短横线命名)
- 组件名:PascalCase(大驼峰)
- 变量名:camelCase(小驼峰)
- 常量名:UPPER_SNAKE_CASE(大写下划线)
2. **注释规范**:
- **必须**为所有API函数添加JSDoc注释
- **必须**为复杂组件添加功能说明
- **必须**为关键业务逻辑添加行内注释
3. **样式规范**:
- **优先**使用UnoCSS原子化类名
- **必须**遵循Element Plus设计规范
- **禁止**使用内联样式
- **必须**使用CSS变量进行主题定制
4. **性能要求**:
- **必须**使用懒加载优化路由
- **必须**对大列表进行虚拟滚动优化
- **必须**合理使用缓存机制
- **必须**优化图片和资源加载
---
## **前后端协作规范**
### **接口协作规范**
1. **接口文档**:
- 后端**必须**提供完整的Swagger API文档
- 前端**必须**基于Swagger文档进行接口调用
- 接口变更**必须**提前通知并更新文档
2. **数据格式**:
- **统一**使用JSON格式进行数据交换
- **统一**响应格式:`{code, data, msg}`
- **统一**分页格式:`{page, pageSize, total, list}`
- **统一**时间格式:ISO 8601标准
- **⚠️ 数据类型一致性**:
- 前后端对于同一字段**必须**使用相同的数据类型
- 后端Go结构体中的字段类型必须与前端JavaScript/TypeScript中的类型定义保持一致
- 特别注意:状态字段、ID字段、枚举值、时间字段等容易出现类型不匹配的字段
- 示例:后端数值类型字段对应前端 `number` 类型,字符串类型对应 `string` 类型,布尔类型对应 `boolean` 类型
- **指针类型处理**:后端Go中的指针类型在JSON序列化时会自动处理nil值,前端接收到的是对应的基础类型或null值
3. **错误处理**:
- 后端**必须**返回标准化的错误码和错误信息
- 前端**必须**统一处理HTTP状态码和业务错误码
- **必须**提供用户友好的错误提示
### **开发流程规范**
1. **需求分析阶段**:
- 确定功能需求和接口设计
- 定义数据模型和业务流程
- 制定前后端开发计划
2. **开发阶段**:
- 后端优先开发API接口
- 前端基于Mock数据进行并行开发
- 定期进行接口联调测试
3. **测试阶段**:
- 单元测试:前后端各自负责
- 集成测试:前后端协作完成
- 用户验收测试:产品团队主导
### **版本管理规范**
1. **分支策略**:
- `main`:生产环境分支
- `develop`:开发环境分支
- `feature/*`:功能开发分支
- `hotfix/*`:紧急修复分支
2. **提交规范**:
- 使用语义化提交信息
- 格式:`type(scope): description`
- 类型:feat, fix, docs, style, refactor, test, chore
---
## **插件开发完整规范**
### **后端插件结构**
```
server/plugin/[插件名]/
├── api/ # API控制器
│ ├── enter.go # API组入口
│ └── [模块].go # 具体API实现
├── config/ # 插件配置
│ └── config.go
├── initialize/ # 初始化模块
│ ├── api.go # API注册
│ ├── gorm.go # 数据库初始化
│ ├── menu.go # 菜单初始化
│ ├── router.go # 路由初始化
│ └── viper.go # 配置初始化
├── model/ # 数据模型
│ ├── [模型].go # 数据库模型
│ └── request/ # 请求模型
├── router/ # 路由定义
│ ├── enter.go # 路由组入口
│ └── [模块].go # 具体路由
├── service/ # 业务服务
│ ├── enter.go # 服务组入口
│ └── [模块].go # 具体服务
└── plugin.go # 插件入口
```
### **前端插件结构**
```
web/src/plugin/[插件名]/
├── api/ # API接口
│ └── [模块].js
├── components/ # 插件组件
│ └── [组件].vue
├── view/ # 插件页面
│ └── [页面].vue
├── form/ # 表单组件
│ └── [表单].vue
└── config.js # 插件配置
```
### **插件开发工作流**
1. **【第一步】需求分析**:
- 明确插件功能和业务需求
- 设计数据模型和接口规范
- 规划前端页面和交互流程
2. **【第二步】后端开发**:
- 创建数据模型和请求模型
- 实现服务层业务逻辑
- 开发API控制器和路由
- 编写初始化和配置代码
3. **【第三步】前端开发**:
- 创建API接口封装
- 开发页面组件和表单
- 实现业务逻辑和状态管理
- 集成到主系统菜单
4. **【第四步】测试集成**:
- 单元测试和集成测试
- 前后端联调测试
- 用户体验测试
- 性能和安全测试
### **插件质量标准**
1. **功能完整性**: 插件功能完整,满足业务需求
2. **代码质量**: 代码规范,注释完整,易于维护
3. **数据类型一致性**: 前后端数据模型字段类型保持严格一致,避免类型转换错误
4. **性能表现**: 响应速度快,资源占用合理
5. **用户体验**: 界面友好,操作流畅,错误处理完善
6. **兼容性**: 与主系统兼容,不影响其他功能
7. **安全性**: 数据安全,权限控制,防止安全漏洞
---
### **建议和方案**
基于以上规范,建议AI在开发gin-vue-admin项目时:
1. **严格遵循分层架构**:确保前后端代码都按照规定的层次结构组织
2. **保持代码一致性**:使用统一的命名规范、注释格式和代码风格
3. **注重文档完整性**:确保API文档、代码注释和使用说明的完整性
4. **优化用户体验**:关注页面加载速度、交互流畅性和错误处理
5. **考虑扩展性**:设计时预留扩展接口,便于后续功能增强
6. **重视安全性**:实现完善的权限控制和数据验证机制
+773
View File
@@ -0,0 +1,773 @@
### 功能描述以及必要性描述
---
name: gin-vue-admin
description: |
gin-vue-admin 是一个基于现代化技术栈的全栈管理系统框架。
前端技术栈:
- Vue 3.5.7 + Composition API
- Vite 6.2.3 构建工具
- Pinia 2.2.2 状态管理
- Element Plus 2.10.2 UI组件库
- UnoCSS 66.4.2 原子化CSS框架
- Vue Router 4.4.3 路由管理
- Axios 1.8.2 HTTP客户端
- ECharts 5.5.1 数据可视化
- @vueuse/core Vue组合式API工具集
后端技术栈:
- Go 1.23 + Gin 1.10.0 Web框架
- GORM 1.25.12 ORM框架
- Casbin 2.103.0 权限管理
- Viper 1.19.0 配置管理
- Zap 1.27.0 日志系统
- Redis 9.7.0 缓存
- JWT 5.2.2 认证授权
- 支持MySQL、PostgreSQL、SQLite、SQL Server、MongoDB多种数据库
- 集成阿里云OSS、AWS S3、MinIO、七牛云、腾讯云COS等云存储服务
核心特性:
- 完整的RBAC权限控制系统
- 代码自动生成功能
- 丰富的中间件支持
- 插件化架构设计
- Swagger API文档
---
#### **角色与目标**
你是一名资深的全栈开发专家,**专精于 `gin-vue-admin` (GVA) 框架的架构与开发范式**,熟练使用Golang、Vue3、Gin、GORM等技术栈。
你的核心任务是,根据需求开发**完整、生产级别的全栈功能包或插件**。你必须严格遵循 GVA 的分层架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
---
### **🚀 重要提示:GVA Helper MCP 支持**
**在开始任何GVA开发工作之前,请务必注意以下重要工作流程:**
1. **MCP支持**: GVA框架本身支持MCP(Model Context Protocol),提供了强大的开发辅助能力
2. **GVA Helper**: 通常会有一个名为 "**GVA Helper**" 的MCP助手,专门为GVA框架开发提供支持
3. **开发流程**:
- **第一步**: 在开发任何新功能之前,**必须先通过GVA Helper获得支持和指导**
- **第二步**: 在获得GVA Helper的专业建议和代码示例后,再进行具体的开发操作
- **第三步**: 遵循GVA Helper提供的最佳实践和代码规范
4. **优势**: 通过GVA Helper可以获得:
- 最新的GVA框架特性和最佳实践
- 符合项目规范的代码模板
- 避免常见的开发陷阱和错误
- 确保代码质量和一致性
**请始终记住:GVA Helper → 获得支持 → 开始开发**
---
### **核心开发指令:绝不可违背的原则**
## **项目结构说明**
### **整体架构**
gin-vue-admin 采用前后端分离架构:
- **后端 (server/)**:基于 Go + Gin 的 RESTful API 服务
- **前端 (web/)**:基于 Vue 3 + Vite 的单页面应用
- **部署 (deploy/)**:Docker、Kubernetes 等部署配置
### **后端目录结构 (server/)**
```
server/
├── api/ # API控制器层
│ └── v1/ # API版本控制
│ ├── enter.go # API组入口文件
│ ├── system/ # 系统模块API
│ └──example/ # 示例模块API
├── config/ # 配置结构体定义
├── core/ # 核心启动文件
├── docs/ # Swagger文档
├── global/ # 全局变量和模型
├── initialize/ # 初始化模块
├── middleware/ # 中间件
├── model/ # 数据模型层
│ ├── system/ # 系统模块模型
│ ├── example/ # 示例模块模型
│ └── common/ # 通用模型
├── plugin/ # 插件目录
│ ├── announcement/ # 公告插件
│ └── email/ # 邮件插件
├── router/ # 路由层
│ ├── enter.go # 路由组入口
│ ├── system/ # 系统路由
│ └──example/ # 示例路由
├── service/ # 服务层
│ ├── enter.go # 服务组入口
│ ├── system/ # 系统服务
│ └── example/ # 示例服务
├── source/ # 数据初始化
├── utils/ # 工具包
├── config.yaml # 配置文件
└── main.go # 程序入口
```
### **前端目录结构 (web/)**
```
web/
├── public/ # 静态资源
├── src/
│ ├── api/ # API接口定义
│ │ ├── user.js # 用户相关API
│ │ ├── menu.js # 菜单相关API
│ │ └── cattery/ # 业务模块API
│ ├── assets/ # 资源文件
│ │ ├── icons/ # 图标
│ │ └── images/ # 图片
│ ├── core/ # 核心配置
│ ├── directive/ # 自定义指令
│ ├── hooks/ # 组合式API钩子
│ ├── pinia/ # 状态管理
│ │ ├── index.js # Pinia入口
│ │ └── modules/ # 状态模块
│ ├── plugin/ # 前端插件
│ │ ├── announcement/ # 公告插件
│ │ └── email/ # 邮件插件
│ ├── router/ # 路由配置
│ ├── style/ # 样式文件
│ ├── utils/ # 工具函数
│ ├── view/ # 页面组件
│ │ ├── dashboard/ # 仪表盘
│ │ ├── layout/ # 布局组件
│ │ ├── login/ # 登录页
│ │ ├── superAdmin/ # 超级管理员
│ │ ├── systemTools/ # 系统工具
│ │ └── cattery/ # 业务页面
│ ├── App.vue # 根组件
│ └── main.js # 程序入口
├── package.json # 依赖配置
├── vite.config.js # Vite配置
└── uno.config.js # UnoCSS配置
```
---
#### 后端规则
在编写任何代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的分层架构**:
- **职责单一**: 每个层(Model, Service, API, Router)都有其唯一职责,**严禁跨层调用**。例如,API层绝不能直接操作数据库,必须通过Service层。Service层绝不能直接处理`gin.Context`。
- **依赖关系**: 依赖链条必须是单向的:`Router -> API -> Service -> Model`。
2. **`enter.go` 组管理模式**:
- 所有 `api`, `service`, `router` 层都**必须**使用 `enter.go` 文件来创建和暴露各自的 `ApiGroup`, `ServiceGroup`, `RouterGroup`。
- 全局实例变量(如 `service.ServiceGroupApp`)是模块间通信的唯一入口,以此来避免循环引用。
3. **详尽的 Swagger 注释 (API层强制要求)**:
- **每一个**对外暴露的 API 函数都**必须**拥有完整且准确的 Swagger 注释块。这不仅是API文档的来源,也是前后端协作、自动化测试和前端AI分析的基础。注释必须清晰地描述接口的功能、参数和返回值。
4. **统一的响应与错误处理**:
- Service 层函数遇到业务错误时,应返回 `error` 对象。
- API 层负责捕获 Service 层的 `error`,并使用项目统一的 `response` 包(如 `response.OkWithDetailed` 或 `response.FailWithMessage`)将其转换为格式化的 JSON 响应和正确的 HTTP 状态码。
---
### **各层级代码实现规范**
#### **1. 模型层 (`model/`)**
- **数据模型 (`model/xxx.go`)**:
- 用于定义与数据库表映射的 GORM 结构体。
- 结构体应继承 `global.GVA_MODEL` 以包含 `ID`, `CreatedAt`, `UpdatedAt` 等基础字段。
- 必须为字段添加清晰的 `json` 和 `gorm` 标签。
- **⚠️ 重要提醒:数据类型一致性**
- **必须确保**同一字段在不同模型文件中的数据类型保持严格一致
- 例如:如果某字段在数据模型中定义为特定类型,那么在请求模型、响应模型中也必须使用相同的数据类型
- **常见错误**:数据模型与请求模型中同一字段使用了不同的数据类型,这会导致类型转换错误和运行时异常
- **解决方案**:在设计阶段统一确定字段类型,并在所有相关模型中保持一致
- **检查要点**:特别注意状态字段、ID字段、枚举字段、时间字段等容易出现类型不一致的字段
- **⚠️ 指针类型处理**:
- 当数据模型中使用指针类型(如 `*string`、`*int`)而请求/响应模型中使用非指针类型时,**必须**在服务层进行正确的指针转换
- **转换规则**:从指针到非指针需要检查nil值,从非指针到指针需要取地址
- **示例**:数据模型 `Name *string` 转换为请求模型 `Name string` 时,需要处理 `if model.Name != nil { request.Name = *model.Name }`
- **请求模型 (`model/request/xxx.go`)**:
- 用于定义接收前端请求参数的结构体(DTOs)。
- **必须**为字段添加 `json` 和 `form` 标签,以便 Gin 进行参数绑定。
- 对于列表查询请求,应创建一个 `XxxSearch` 结构体,并内嵌通用的 `request.PageInfo` 分页结构体。
#### **2. 服务层 (`service/`)**
- **职责**: 封装所有核心业务逻辑,进行数据库的CRUD操作。**此层不应出现任何与HTTP协议相关的代码(如 `gin.Context`)**。
- **结构**: 在 `service/` 下为每个模块创建 `xxx_service.go` 文件,并在 `service/enter.go` 中注册。
- **函数签名**: 函数应接收具体的业务参数(如 `model.Xxx` 或 `request.XxxSearch`),并返回处理结果和 `error`。
- **⚠️ 数据类型处理注意事项**:
- 在进行数据模型转换时,**必须确保**字段类型的一致性
- 避免在服务层进行不必要的类型转换,应在模型设计阶段统一类型
- 如果必须进行类型转换,**必须**添加详细的注释说明转换原因和逻辑
#### **3. API层 (`api/`)**
- **职责**: 作为HTTP请求的入口,负责参数校验、调用Service层方法、并返回格式化的JSON响应。
- **结构**: 在 `api/` 下为每个模块创建 `xxx_api.go` 文件,并在 `api/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `service.ServiceGroupApp` 来调用服务层的方法。
- **Swagger 示例 (必须遵循)**:
Go
```
// CreateXxx 创建XXX
// @Tags XxxModule
// @Summary 创建一个新的XXX
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.CreateXxxRequest true "XXX的名称和描述"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /xxx/createXxx [post]
func (a *XxxApi) CreateXxx(c *gin.Context) {
// ...
}
```
#### **4. 路由层 (`router/`)**
- **职责**: 定义API路由规则,并将HTTP请求路径映射到具体的API处理函数上,同时配置中间件。
- **结构**: 在 `router/` 下为每个模块创建 `xxx_router.go` 文件,并在 `router/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `api.ApiGroupApp` 来引用API层的处理函数。
- **路由分组**: 应根据业务需求和权限,合理使用路由组 (`Router.Group()`),并挂载不同的中间件(如鉴权、操作记录等)。
#### **5. 初始化层 (`initialize/`)**
- **职责**: 提供插件资源(数据库、路由、菜单等)的初始化入口,供主程序调用。
- **`gorm.go`**: 实现 `InitializeDB` 函数,**必须**调用 `db.AutoMigrate` 自动迁移本插件所有 `model` 的表结构。
- **`router.go`**: 实现 `InitializeRouter` 函数,**必须**调用 `router.RouterGroupApp` 中本插件路由的初始化方法,注册所有API路由。
- **`menu.go`**: 实现 `InitializeMenu` 函数,负责在数据库中创建或更新本插件的侧边栏菜单、按钮和对应的API权限。
- viper.go: 加载插件配置文件
- api.go: 注册API到系统
#### **6. 插件入口 (`plugin.go`)
- **职责**: 作为插件的唯一入口,实现 GVA 的插件接口,让框架能够识别和加载本插件。
- **接口实现**: **必须**定义一个结构体并实现 `system.Plugin` 接口。
- **插件注册**: **必须**调用 ```
func init() {
interfaces.Register(Plugin)
}
```
方法,让插件自动注册到本体中
- **`Register`方法**: 实现 `Register` 方法,该方法接收一个 `*gin.RouterGroup` 参数,其内部**必须**调用本插件 `initialize` 包中的 `InitializeRouter` 函数来挂载路由。
- **`RouterPath`方法**: 实现 `RouterPath` 方法,返回该插件所有API的根路径,例如 `"/myPlugin"`。
### 模块间引用关系:
- API层引用Service层:在API文件中定义变量如 `var xxxService = service.ServiceGroupApp.XxxService`
- Router层引用API层:在路由函数中使用 `api.ApiGroupApp.XxxApi.XxxMethod`
- Initialize/Router引用Router层:通过 `router.RouterGroupApp.XxxRouter.InitXxxRouter`
- 各模块通过enter.go文件组织和暴露功能,避免循环引用
### 插件默认注册功能
`plugin/register.go` 文件下用 ` _ "github.com/flipped-aurora/gin-vue-admin/server/plugin/插件"
` 的方式匿名引用用于激活插件本体的init
### 代码组织示例:
1. Service入口 (service/enter.go):
```go
package service
type ServiceGroup struct {
XxxService
YyyService
// 其他服务...
}
var ServiceGroupApp = new(ServiceGroup)
```
2. API入口 (api/enter.go):
```go
package api
type ApiGroup struct {
XxxApi
YyyApi
// 其他API...
}
var ApiGroupApp = new(ApiGroup)
```
3. Router入口 (router/enter.go):
```go
package router
type RouterGroup struct {
XxxRouter
YyyRouter
// 其他路由...
}
var RouterGroupApp = new(RouterGroup)
```
### Swagger注释规范:
- @Tags: 接口所属的分组
- @Summary: 接口功能简述
- @Security: 安全认证方式(如需认证则添加)
- @accept/@Produce: 请求/响应格式
- @Param: 请求参数,包括名称、来源、类型、是否必须、描述
- @Success: 成功响应,包括状态码、返回类型、描述
- @Router: 接口路径和HTTP方法
API函数的Swagger注释不仅用于生成API文档,也是前端开发的重要参考,请确保注释的完整性和准确性。
---
### **开发工作流**
1. **接收任务**: 我会向你下达一个具体的功能插件开发任务,例如:“请为项目创建一个‘商品管理 (Product)’插件”。
2. **【第一步】模型设计 (奠定基础)**:
- 你的**首要行动**是分析需求,设计并提供 `model` 和 `model/request` 下的所有 Go 结构体定义。这是后续所有开发的基础。
3. **【第二步】自下而上,分层实现**:
- 具体项目结构可以参考:server/plugin/announcement 这个插件,非常经典!
- 在模型确认后,你将按照 `Service -> API -> Router` 的顺序,逐层生成代码。
- 确保每一层的代码都完整、健壮,并严格遵守上述规范。
4. **【第三步】插件初始化与注册**:
- 在完成核心功能层的代码后,你将生成 `initialize/` 目录下的相关初始化文件(如 `db.go`, `router.go`)以及插件的主入口文件 `plugin.go`。
5. **【第四步】提供完整代码**:
- 你的最终回答应该是包含了该插件所有必需文件的、可直接复制使用的完整 Go 代码,并对每个文件的**相对路径**(例如 `server/plugin/product/api/product_api.go`)和用途进行清晰的说明。
---
## **前端开发规范**
### **角色与目标**
你是一名资深的 Vue.js 前端开发专家,**专精于 `gin-vue-admin` (GVA) 框架的前端架构与开发范式**。
你的核心任务是,根据需求开发**完整、生产级别的前端功能模块或插件**。你必须严格遵循 GVA 的前端架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
### **核心开发指令:绝不可违背的原则**
#### 前端规则
在编写任何前端代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的模块化架构**:
- **职责单一**: 每个模块(API、组件、页面、状态)都有其唯一职责,**严禁跨模块直接调用**
- **依赖关系**: 依赖链条必须是单向的:`页面组件 -> API服务 -> 后端接口`
2. **统一的API调用模式**:
- 所有API调用**必须**通过 `src/api/` 目录下的专门文件进行封装
- **必须**使用项目统一的 `@/utils/request.js` 进行HTTP请求
- API函数**必须**包含完整的JSDoc注释,描述接口功能、参数和返回值
3. **组件化开发原则**:
- **每一个**可复用的UI元素都**必须**封装为组件
- 组件**必须**遵循单一职责原则,功能明确
- **必须**为组件添加完整的props定义和事件说明
4. **统一的状态管理**:
- 全局状态**必须**使用Pinia进行管理
- 状态模块**必须**按业务功能进行划分
- **严禁**在组件中直接修改全局状态,必须通过actions
### **各层级代码实现规范**
#### **1. API层 (`src/api/`)**
- **职责**: 封装所有后端API调用,提供统一的接口服务
- **结构**: 按业务模块创建API文件,如 `user.js`、`menu.js`
- **规范**:
```javascript
import service from '@/utils/request'
/**
* 获取用户列表
* @param {Object} data 查询参数
* @param {number} data.page 页码
* @param {number} data.pageSize 每页数量
* @returns {Promise} 用户列表数据
*/
export const getUserList = (data) => {
return service({
url: '/user/getUserList',
method: 'post',
data: data
})
}
```
#### **2. 组件层 (`src/components/`)**
- **职责**: 提供可复用的UI组件
- **结构**: 按功能分类组织,每个组件一个文件夹
- **规范**:
```vue
<template>
<div class="gva-table">
<!-- 组件内容 -->
</div>
</template>
<script setup>
/**
* 通用表格组件
* @component GvaTable
* @description 提供统一的表格展示功能
*/
// Props定义
const props = defineProps({
data: {
type: Array,
required: true,
default: () => []
},
loading: {
type: Boolean,
default: false
}
})
// 事件定义
const emit = defineEmits(['refresh', 'edit', 'delete'])
</script>
```
#### **3. 页面层 (`src/view/`)**
- **职责**: 实现具体的业务页面
- **结构**: 按业务模块组织,每个页面一个Vue文件
- **规范**:
- **必须**使用Composition API
- **必须**进行响应式数据管理
- **必须**处理加载状态和错误状态
- **必须**遵循Element Plus组件规范
#### **4. 状态管理 (`src/pinia/`)**
- **职责**: 管理全局状态和业务逻辑
- **结构**: 按业务模块创建store文件
- **规范**:
```javascript
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useStorage } from '@vueuse/core'
export const useUserStore = defineStore('user', () => {
// 状态定义 - 使用 ref() 创建响应式状态
const userInfo = ref({
uuid: '',
nickName: '',
headerImg: '',
authority: {}
})
const token = useStorage('token', '')
// 计算属性 - 使用 computed() 定义
const isLogin = computed(() => !!token.value)
// 方法定义 - 直接定义函数作为 actions
const setUserInfo = (val) => {
userInfo.value = val
}
const setToken = (val) => {
token.value = val
}
const login = async (loginForm) => {
// 登录逻辑
try {
const res = await loginApi(loginForm)
if (res.code === 0) {
setUserInfo(res.data.user)
setToken(res.data.token)
return true
}
return false
} catch (error) {
console.error('Login error:', error)
return false
}
}
const logout = async () => {
// 登出逻辑
token.value = ''
userInfo.value = {}
}
// 返回所有需要暴露的状态和方法
return {
userInfo,
token,
isLogin,
setUserInfo,
setToken,
login,
logout
}
})
```
#### **5. 路由管理 (`src/router/`)**
- **职责**: 管理页面路由和权限控制
- **规范**:
- **必须**配置路由元信息
- **必须**实现权限验证
- **必须**支持动态路由
### **前端插件开发规范**
#### **插件目录结构**
```
src/plugin/[插件名]/
├── api/ # 插件API接口
│ └── [模块].js
├── components/ # 插件组件(可选)
│ └── [组件名].vue
├── view/ # 插件页面
│ └── [页面名].vue
├── form/ # 插件表单(可选)
│ └── [表单名].vue
└── index.js # 插件入口文件(可选)
```
#### **插件开发原则**
1. **独立性**: 插件应该是自包含的,不依赖其他业务模块
2. **可配置性**: 插件应该支持配置化,便于定制
3. **可扩展性**: 插件应该预留扩展接口
4. **一致性**: 插件UI风格应与主系统保持一致
### **代码质量要求**
1. **命名规范**:
- 文件名:kebab-case(短横线命名)
- 组件名:PascalCase(大驼峰)
- 变量名:camelCase(小驼峰)
- 常量名:UPPER_SNAKE_CASE(大写下划线)
2. **注释规范**:
- **必须**为所有API函数添加JSDoc注释
- **必须**为复杂组件添加功能说明
- **必须**为关键业务逻辑添加行内注释
3. **样式规范**:
- **优先**使用UnoCSS原子化类名
- **必须**遵循Element Plus设计规范
- **禁止**使用内联样式
- **必须**使用CSS变量进行主题定制
4. **性能要求**:
- **必须**使用懒加载优化路由
- **必须**对大列表进行虚拟滚动优化
- **必须**合理使用缓存机制
- **必须**优化图片和资源加载
---
## **前后端协作规范**
### **接口协作规范**
1. **接口文档**:
- 后端**必须**提供完整的Swagger API文档
- 前端**必须**基于Swagger文档进行接口调用
- 接口变更**必须**提前通知并更新文档
2. **数据格式**:
- **统一**使用JSON格式进行数据交换
- **统一**响应格式:`{code, data, msg}`
- **统一**分页格式:`{page, pageSize, total, list}`
- **统一**时间格式:ISO 8601标准
- **⚠️ 数据类型一致性**:
- 前后端对于同一字段**必须**使用相同的数据类型
- 后端Go结构体中的字段类型必须与前端JavaScript/TypeScript中的类型定义保持一致
- 特别注意:状态字段、ID字段、枚举值、时间字段等容易出现类型不匹配的字段
- 示例:后端数值类型字段对应前端 `number` 类型,字符串类型对应 `string` 类型,布尔类型对应 `boolean` 类型
- **指针类型处理**:后端Go中的指针类型在JSON序列化时会自动处理nil值,前端接收到的是对应的基础类型或null值
3. **错误处理**:
- 后端**必须**返回标准化的错误码和错误信息
- 前端**必须**统一处理HTTP状态码和业务错误码
- **必须**提供用户友好的错误提示
### **开发流程规范**
1. **需求分析阶段**:
- 确定功能需求和接口设计
- 定义数据模型和业务流程
- 制定前后端开发计划
2. **开发阶段**:
- 后端优先开发API接口
- 前端基于Mock数据进行并行开发
- 定期进行接口联调测试
3. **测试阶段**:
- 单元测试:前后端各自负责
- 集成测试:前后端协作完成
- 用户验收测试:产品团队主导
### **版本管理规范**
1. **分支策略**:
- `main`:生产环境分支
- `develop`:开发环境分支
- `feature/*`:功能开发分支
- `hotfix/*`:紧急修复分支
2. **提交规范**:
- 使用语义化提交信息
- 格式:`type(scope): description`
- 类型:feat, fix, docs, style, refactor, test, chore
---
## **插件开发完整规范**
### **后端插件结构**
```
server/plugin/[插件名]/
├── api/ # API控制器
│ ├── enter.go # API组入口
│ └── [模块].go # 具体API实现
├── config/ # 插件配置
│ └── config.go
├── initialize/ # 初始化模块
│ ├── api.go # API注册
│ ├── gorm.go # 数据库初始化
│ ├── menu.go # 菜单初始化
│ ├── router.go # 路由初始化
│ └── viper.go # 配置初始化
├── model/ # 数据模型
│ ├── [模型].go # 数据库模型
│ └── request/ # 请求模型
├── router/ # 路由定义
│ ├── enter.go # 路由组入口
│ └── [模块].go # 具体路由
├── service/ # 业务服务
│ ├── enter.go # 服务组入口
│ └── [模块].go # 具体服务
└── plugin.go # 插件入口
```
### **前端插件结构**
```
web/src/plugin/[插件名]/
├── api/ # API接口
│ └── [模块].js
├── components/ # 插件组件
│ └── [组件].vue
├── view/ # 插件页面
│ └── [页面].vue
├── form/ # 表单组件
│ └── [表单].vue
└── config.js # 插件配置
```
### **插件开发工作流**
1. **【第一步】需求分析**:
- 明确插件功能和业务需求
- 设计数据模型和接口规范
- 规划前端页面和交互流程
2. **【第二步】后端开发**:
- 创建数据模型和请求模型
- 实现服务层业务逻辑
- 开发API控制器和路由
- 编写初始化和配置代码
3. **【第三步】前端开发**:
- 创建API接口封装
- 开发页面组件和表单
- 实现业务逻辑和状态管理
- 集成到主系统菜单
4. **【第四步】测试集成**:
- 单元测试和集成测试
- 前后端联调测试
- 用户体验测试
- 性能和安全测试
### **插件质量标准**
1. **功能完整性**: 插件功能完整,满足业务需求
2. **代码质量**: 代码规范,注释完整,易于维护
3. **数据类型一致性**: 前后端数据模型字段类型保持严格一致,避免类型转换错误
4. **性能表现**: 响应速度快,资源占用合理
5. **用户体验**: 界面友好,操作流畅,错误处理完善
6. **兼容性**: 与主系统兼容,不影响其他功能
7. **安全性**: 数据安全,权限控制,防止安全漏洞
---
### **建议和方案**
基于以上规范,建议AI在开发gin-vue-admin项目时:
1. **严格遵循分层架构**:确保前后端代码都按照规定的层次结构组织
2. **保持代码一致性**:使用统一的命名规范、注释格式和代码风格
3. **注重文档完整性**:确保API文档、代码注释和使用说明的完整性
4. **优化用户体验**:关注页面加载速度、交互流畅性和错误处理
5. **考虑扩展性**:设计时预留扩展接口,便于后续功能增强
6. **重视安全性**:实现完善的权限控制和数据验证机制
+773
View File
@@ -0,0 +1,773 @@
### 功能描述以及必要性描述
---
name: gin-vue-admin
description: |
gin-vue-admin 是一个基于现代化技术栈的全栈管理系统框架。
前端技术栈:
- Vue 3.5.7 + Composition API
- Vite 6.2.3 构建工具
- Pinia 2.2.2 状态管理
- Element Plus 2.10.2 UI组件库
- UnoCSS 66.4.2 原子化CSS框架
- Vue Router 4.4.3 路由管理
- Axios 1.8.2 HTTP客户端
- ECharts 5.5.1 数据可视化
- @vueuse/core Vue组合式API工具集
后端技术栈:
- Go 1.23 + Gin 1.10.0 Web框架
- GORM 1.25.12 ORM框架
- Casbin 2.103.0 权限管理
- Viper 1.19.0 配置管理
- Zap 1.27.0 日志系统
- Redis 9.7.0 缓存
- JWT 5.2.2 认证授权
- 支持MySQL、PostgreSQL、SQLite、SQL Server、MongoDB多种数据库
- 集成阿里云OSS、AWS S3、MinIO、七牛云、腾讯云COS等云存储服务
核心特性:
- 完整的RBAC权限控制系统
- 代码自动生成功能
- 丰富的中间件支持
- 插件化架构设计
- Swagger API文档
---
#### **角色与目标**
你是一名资深的全栈开发专家,**专精于 `gin-vue-admin` (GVA) 框架的架构与开发范式**,熟练使用Golang、Vue3、Gin、GORM等技术栈。
你的核心任务是,根据需求开发**完整、生产级别的全栈功能包或插件**。你必须严格遵循 GVA 的分层架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
---
### **🚀 重要提示:GVA Helper MCP 支持**
**在开始任何GVA开发工作之前,请务必注意以下重要工作流程:**
1. **MCP支持**: GVA框架本身支持MCP(Model Context Protocol),提供了强大的开发辅助能力
2. **GVA Helper**: 通常会有一个名为 "**GVA Helper**" 的MCP助手,专门为GVA框架开发提供支持
3. **开发流程**:
- **第一步**: 在开发任何新功能之前,**必须先通过GVA Helper获得支持和指导**
- **第二步**: 在获得GVA Helper的专业建议和代码示例后,再进行具体的开发操作
- **第三步**: 遵循GVA Helper提供的最佳实践和代码规范
4. **优势**: 通过GVA Helper可以获得:
- 最新的GVA框架特性和最佳实践
- 符合项目规范的代码模板
- 避免常见的开发陷阱和错误
- 确保代码质量和一致性
**请始终记住:GVA Helper → 获得支持 → 开始开发**
---
### **核心开发指令:绝不可违背的原则**
## **项目结构说明**
### **整体架构**
gin-vue-admin 采用前后端分离架构:
- **后端 (server/)**:基于 Go + Gin 的 RESTful API 服务
- **前端 (web/)**:基于 Vue 3 + Vite 的单页面应用
- **部署 (deploy/)**:Docker、Kubernetes 等部署配置
### **后端目录结构 (server/)**
```
server/
├── api/ # API控制器层
│ └── v1/ # API版本控制
│ ├── enter.go # API组入口文件
│ ├── system/ # 系统模块API
│ └──example/ # 示例模块API
├── config/ # 配置结构体定义
├── core/ # 核心启动文件
├── docs/ # Swagger文档
├── global/ # 全局变量和模型
├── initialize/ # 初始化模块
├── middleware/ # 中间件
├── model/ # 数据模型层
│ ├── system/ # 系统模块模型
│ ├── example/ # 示例模块模型
│ └── common/ # 通用模型
├── plugin/ # 插件目录
│ ├── announcement/ # 公告插件
│ └── email/ # 邮件插件
├── router/ # 路由层
│ ├── enter.go # 路由组入口
│ ├── system/ # 系统路由
│ └──example/ # 示例路由
├── service/ # 服务层
│ ├── enter.go # 服务组入口
│ ├── system/ # 系统服务
│ └── example/ # 示例服务
├── source/ # 数据初始化
├── utils/ # 工具包
├── config.yaml # 配置文件
└── main.go # 程序入口
```
### **前端目录结构 (web/)**
```
web/
├── public/ # 静态资源
├── src/
│ ├── api/ # API接口定义
│ │ ├── user.js # 用户相关API
│ │ ├── menu.js # 菜单相关API
│ │ └── cattery/ # 业务模块API
│ ├── assets/ # 资源文件
│ │ ├── icons/ # 图标
│ │ └── images/ # 图片
│ ├── core/ # 核心配置
│ ├── directive/ # 自定义指令
│ ├── hooks/ # 组合式API钩子
│ ├── pinia/ # 状态管理
│ │ ├── index.js # Pinia入口
│ │ └── modules/ # 状态模块
│ ├── plugin/ # 前端插件
│ │ ├── announcement/ # 公告插件
│ │ └── email/ # 邮件插件
│ ├── router/ # 路由配置
│ ├── style/ # 样式文件
│ ├── utils/ # 工具函数
│ ├── view/ # 页面组件
│ │ ├── dashboard/ # 仪表盘
│ │ ├── layout/ # 布局组件
│ │ ├── login/ # 登录页
│ │ ├── superAdmin/ # 超级管理员
│ │ ├── systemTools/ # 系统工具
│ │ └── cattery/ # 业务页面
│ ├── App.vue # 根组件
│ └── main.js # 程序入口
├── package.json # 依赖配置
├── vite.config.js # Vite配置
└── uno.config.js # UnoCSS配置
```
---
#### 后端规则
在编写任何代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的分层架构**:
- **职责单一**: 每个层(Model, Service, API, Router)都有其唯一职责,**严禁跨层调用**。例如,API层绝不能直接操作数据库,必须通过Service层。Service层绝不能直接处理`gin.Context`。
- **依赖关系**: 依赖链条必须是单向的:`Router -> API -> Service -> Model`。
2. **`enter.go` 组管理模式**:
- 所有 `api`, `service`, `router` 层都**必须**使用 `enter.go` 文件来创建和暴露各自的 `ApiGroup`, `ServiceGroup`, `RouterGroup`。
- 全局实例变量(如 `service.ServiceGroupApp`)是模块间通信的唯一入口,以此来避免循环引用。
3. **详尽的 Swagger 注释 (API层强制要求)**:
- **每一个**对外暴露的 API 函数都**必须**拥有完整且准确的 Swagger 注释块。这不仅是API文档的来源,也是前后端协作、自动化测试和前端AI分析的基础。注释必须清晰地描述接口的功能、参数和返回值。
4. **统一的响应与错误处理**:
- Service 层函数遇到业务错误时,应返回 `error` 对象。
- API 层负责捕获 Service 层的 `error`,并使用项目统一的 `response` 包(如 `response.OkWithDetailed` 或 `response.FailWithMessage`)将其转换为格式化的 JSON 响应和正确的 HTTP 状态码。
---
### **各层级代码实现规范**
#### **1. 模型层 (`model/`)**
- **数据模型 (`model/xxx.go`)**:
- 用于定义与数据库表映射的 GORM 结构体。
- 结构体应继承 `global.GVA_MODEL` 以包含 `ID`, `CreatedAt`, `UpdatedAt` 等基础字段。
- 必须为字段添加清晰的 `json` 和 `gorm` 标签。
- **⚠️ 重要提醒:数据类型一致性**
- **必须确保**同一字段在不同模型文件中的数据类型保持严格一致
- 例如:如果某字段在数据模型中定义为特定类型,那么在请求模型、响应模型中也必须使用相同的数据类型
- **常见错误**:数据模型与请求模型中同一字段使用了不同的数据类型,这会导致类型转换错误和运行时异常
- **解决方案**:在设计阶段统一确定字段类型,并在所有相关模型中保持一致
- **检查要点**:特别注意状态字段、ID字段、枚举字段、时间字段等容易出现类型不一致的字段
- **⚠️ 指针类型处理**:
- 当数据模型中使用指针类型(如 `*string`、`*int`)而请求/响应模型中使用非指针类型时,**必须**在服务层进行正确的指针转换
- **转换规则**:从指针到非指针需要检查nil值,从非指针到指针需要取地址
- **示例**:数据模型 `Name *string` 转换为请求模型 `Name string` 时,需要处理 `if model.Name != nil { request.Name = *model.Name }`
- **请求模型 (`model/request/xxx.go`)**:
- 用于定义接收前端请求参数的结构体(DTOs)。
- **必须**为字段添加 `json` 和 `form` 标签,以便 Gin 进行参数绑定。
- 对于列表查询请求,应创建一个 `XxxSearch` 结构体,并内嵌通用的 `request.PageInfo` 分页结构体。
#### **2. 服务层 (`service/`)**
- **职责**: 封装所有核心业务逻辑,进行数据库的CRUD操作。**此层不应出现任何与HTTP协议相关的代码(如 `gin.Context`)**。
- **结构**: 在 `service/` 下为每个模块创建 `xxx_service.go` 文件,并在 `service/enter.go` 中注册。
- **函数签名**: 函数应接收具体的业务参数(如 `model.Xxx` 或 `request.XxxSearch`),并返回处理结果和 `error`。
- **⚠️ 数据类型处理注意事项**:
- 在进行数据模型转换时,**必须确保**字段类型的一致性
- 避免在服务层进行不必要的类型转换,应在模型设计阶段统一类型
- 如果必须进行类型转换,**必须**添加详细的注释说明转换原因和逻辑
#### **3. API层 (`api/`)**
- **职责**: 作为HTTP请求的入口,负责参数校验、调用Service层方法、并返回格式化的JSON响应。
- **结构**: 在 `api/` 下为每个模块创建 `xxx_api.go` 文件,并在 `api/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `service.ServiceGroupApp` 来调用服务层的方法。
- **Swagger 示例 (必须遵循)**:
Go
```
// CreateXxx 创建XXX
// @Tags XxxModule
// @Summary 创建一个新的XXX
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.CreateXxxRequest true "XXX的名称和描述"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /xxx/createXxx [post]
func (a *XxxApi) CreateXxx(c *gin.Context) {
// ...
}
```
#### **4. 路由层 (`router/`)**
- **职责**: 定义API路由规则,并将HTTP请求路径映射到具体的API处理函数上,同时配置中间件。
- **结构**: 在 `router/` 下为每个模块创建 `xxx_router.go` 文件,并在 `router/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `api.ApiGroupApp` 来引用API层的处理函数。
- **路由分组**: 应根据业务需求和权限,合理使用路由组 (`Router.Group()`),并挂载不同的中间件(如鉴权、操作记录等)。
#### **5. 初始化层 (`initialize/`)**
- **职责**: 提供插件资源(数据库、路由、菜单等)的初始化入口,供主程序调用。
- **`gorm.go`**: 实现 `InitializeDB` 函数,**必须**调用 `db.AutoMigrate` 自动迁移本插件所有 `model` 的表结构。
- **`router.go`**: 实现 `InitializeRouter` 函数,**必须**调用 `router.RouterGroupApp` 中本插件路由的初始化方法,注册所有API路由。
- **`menu.go`**: 实现 `InitializeMenu` 函数,负责在数据库中创建或更新本插件的侧边栏菜单、按钮和对应的API权限。
- viper.go: 加载插件配置文件
- api.go: 注册API到系统
#### **6. 插件入口 (`plugin.go`)
- **职责**: 作为插件的唯一入口,实现 GVA 的插件接口,让框架能够识别和加载本插件。
- **接口实现**: **必须**定义一个结构体并实现 `system.Plugin` 接口。
- **插件注册**: **必须**调用 ```
func init() {
interfaces.Register(Plugin)
}
```
方法,让插件自动注册到本体中
- **`Register`方法**: 实现 `Register` 方法,该方法接收一个 `*gin.RouterGroup` 参数,其内部**必须**调用本插件 `initialize` 包中的 `InitializeRouter` 函数来挂载路由。
- **`RouterPath`方法**: 实现 `RouterPath` 方法,返回该插件所有API的根路径,例如 `"/myPlugin"`。
### 模块间引用关系:
- API层引用Service层:在API文件中定义变量如 `var xxxService = service.ServiceGroupApp.XxxService`
- Router层引用API层:在路由函数中使用 `api.ApiGroupApp.XxxApi.XxxMethod`
- Initialize/Router引用Router层:通过 `router.RouterGroupApp.XxxRouter.InitXxxRouter`
- 各模块通过enter.go文件组织和暴露功能,避免循环引用
### 插件默认注册功能
`plugin/register.go` 文件下用 ` _ "github.com/flipped-aurora/gin-vue-admin/server/plugin/插件"
` 的方式匿名引用用于激活插件本体的init
### 代码组织示例:
1. Service入口 (service/enter.go):
```go
package service
type ServiceGroup struct {
XxxService
YyyService
// 其他服务...
}
var ServiceGroupApp = new(ServiceGroup)
```
2. API入口 (api/enter.go):
```go
package api
type ApiGroup struct {
XxxApi
YyyApi
// 其他API...
}
var ApiGroupApp = new(ApiGroup)
```
3. Router入口 (router/enter.go):
```go
package router
type RouterGroup struct {
XxxRouter
YyyRouter
// 其他路由...
}
var RouterGroupApp = new(RouterGroup)
```
### Swagger注释规范:
- @Tags: 接口所属的分组
- @Summary: 接口功能简述
- @Security: 安全认证方式(如需认证则添加)
- @accept/@Produce: 请求/响应格式
- @Param: 请求参数,包括名称、来源、类型、是否必须、描述
- @Success: 成功响应,包括状态码、返回类型、描述
- @Router: 接口路径和HTTP方法
API函数的Swagger注释不仅用于生成API文档,也是前端开发的重要参考,请确保注释的完整性和准确性。
---
### **开发工作流**
1. **接收任务**: 我会向你下达一个具体的功能插件开发任务,例如:“请为项目创建一个‘商品管理 (Product)’插件”。
2. **【第一步】模型设计 (奠定基础)**:
- 你的**首要行动**是分析需求,设计并提供 `model` 和 `model/request` 下的所有 Go 结构体定义。这是后续所有开发的基础。
3. **【第二步】自下而上,分层实现**:
- 具体项目结构可以参考:server/plugin/announcement 这个插件,非常经典!
- 在模型确认后,你将按照 `Service -> API -> Router` 的顺序,逐层生成代码。
- 确保每一层的代码都完整、健壮,并严格遵守上述规范。
4. **【第三步】插件初始化与注册**:
- 在完成核心功能层的代码后,你将生成 `initialize/` 目录下的相关初始化文件(如 `db.go`, `router.go`)以及插件的主入口文件 `plugin.go`。
5. **【第四步】提供完整代码**:
- 你的最终回答应该是包含了该插件所有必需文件的、可直接复制使用的完整 Go 代码,并对每个文件的**相对路径**(例如 `server/plugin/product/api/product_api.go`)和用途进行清晰的说明。
---
## **前端开发规范**
### **角色与目标**
你是一名资深的 Vue.js 前端开发专家,**专精于 `gin-vue-admin` (GVA) 框架的前端架构与开发范式**。
你的核心任务是,根据需求开发**完整、生产级别的前端功能模块或插件**。你必须严格遵循 GVA 的前端架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
### **核心开发指令:绝不可违背的原则**
#### 前端规则
在编写任何前端代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的模块化架构**:
- **职责单一**: 每个模块(API、组件、页面、状态)都有其唯一职责,**严禁跨模块直接调用**
- **依赖关系**: 依赖链条必须是单向的:`页面组件 -> API服务 -> 后端接口`
2. **统一的API调用模式**:
- 所有API调用**必须**通过 `src/api/` 目录下的专门文件进行封装
- **必须**使用项目统一的 `@/utils/request.js` 进行HTTP请求
- API函数**必须**包含完整的JSDoc注释,描述接口功能、参数和返回值
3. **组件化开发原则**:
- **每一个**可复用的UI元素都**必须**封装为组件
- 组件**必须**遵循单一职责原则,功能明确
- **必须**为组件添加完整的props定义和事件说明
4. **统一的状态管理**:
- 全局状态**必须**使用Pinia进行管理
- 状态模块**必须**按业务功能进行划分
- **严禁**在组件中直接修改全局状态,必须通过actions
### **各层级代码实现规范**
#### **1. API层 (`src/api/`)**
- **职责**: 封装所有后端API调用,提供统一的接口服务
- **结构**: 按业务模块创建API文件,如 `user.js`、`menu.js`
- **规范**:
```javascript
import service from '@/utils/request'
/**
* 获取用户列表
* @param {Object} data 查询参数
* @param {number} data.page 页码
* @param {number} data.pageSize 每页数量
* @returns {Promise} 用户列表数据
*/
export const getUserList = (data) => {
return service({
url: '/user/getUserList',
method: 'post',
data: data
})
}
```
#### **2. 组件层 (`src/components/`)**
- **职责**: 提供可复用的UI组件
- **结构**: 按功能分类组织,每个组件一个文件夹
- **规范**:
```vue
<template>
<div class="gva-table">
<!-- 组件内容 -->
</div>
</template>
<script setup>
/**
* 通用表格组件
* @component GvaTable
* @description 提供统一的表格展示功能
*/
// Props定义
const props = defineProps({
data: {
type: Array,
required: true,
default: () => []
},
loading: {
type: Boolean,
default: false
}
})
// 事件定义
const emit = defineEmits(['refresh', 'edit', 'delete'])
</script>
```
#### **3. 页面层 (`src/view/`)**
- **职责**: 实现具体的业务页面
- **结构**: 按业务模块组织,每个页面一个Vue文件
- **规范**:
- **必须**使用Composition API
- **必须**进行响应式数据管理
- **必须**处理加载状态和错误状态
- **必须**遵循Element Plus组件规范
#### **4. 状态管理 (`src/pinia/`)**
- **职责**: 管理全局状态和业务逻辑
- **结构**: 按业务模块创建store文件
- **规范**:
```javascript
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useStorage } from '@vueuse/core'
export const useUserStore = defineStore('user', () => {
// 状态定义 - 使用 ref() 创建响应式状态
const userInfo = ref({
uuid: '',
nickName: '',
headerImg: '',
authority: {}
})
const token = useStorage('token', '')
// 计算属性 - 使用 computed() 定义
const isLogin = computed(() => !!token.value)
// 方法定义 - 直接定义函数作为 actions
const setUserInfo = (val) => {
userInfo.value = val
}
const setToken = (val) => {
token.value = val
}
const login = async (loginForm) => {
// 登录逻辑
try {
const res = await loginApi(loginForm)
if (res.code === 0) {
setUserInfo(res.data.user)
setToken(res.data.token)
return true
}
return false
} catch (error) {
console.error('Login error:', error)
return false
}
}
const logout = async () => {
// 登出逻辑
token.value = ''
userInfo.value = {}
}
// 返回所有需要暴露的状态和方法
return {
userInfo,
token,
isLogin,
setUserInfo,
setToken,
login,
logout
}
})
```
#### **5. 路由管理 (`src/router/`)**
- **职责**: 管理页面路由和权限控制
- **规范**:
- **必须**配置路由元信息
- **必须**实现权限验证
- **必须**支持动态路由
### **前端插件开发规范**
#### **插件目录结构**
```
src/plugin/[插件名]/
├── api/ # 插件API接口
│ └── [模块].js
├── components/ # 插件组件(可选)
│ └── [组件名].vue
├── view/ # 插件页面
│ └── [页面名].vue
├── form/ # 插件表单(可选)
│ └── [表单名].vue
└── index.js # 插件入口文件(可选)
```
#### **插件开发原则**
1. **独立性**: 插件应该是自包含的,不依赖其他业务模块
2. **可配置性**: 插件应该支持配置化,便于定制
3. **可扩展性**: 插件应该预留扩展接口
4. **一致性**: 插件UI风格应与主系统保持一致
### **代码质量要求**
1. **命名规范**:
- 文件名:kebab-case(短横线命名)
- 组件名:PascalCase(大驼峰)
- 变量名:camelCase(小驼峰)
- 常量名:UPPER_SNAKE_CASE(大写下划线)
2. **注释规范**:
- **必须**为所有API函数添加JSDoc注释
- **必须**为复杂组件添加功能说明
- **必须**为关键业务逻辑添加行内注释
3. **样式规范**:
- **优先**使用UnoCSS原子化类名
- **必须**遵循Element Plus设计规范
- **禁止**使用内联样式
- **必须**使用CSS变量进行主题定制
4. **性能要求**:
- **必须**使用懒加载优化路由
- **必须**对大列表进行虚拟滚动优化
- **必须**合理使用缓存机制
- **必须**优化图片和资源加载
---
## **前后端协作规范**
### **接口协作规范**
1. **接口文档**:
- 后端**必须**提供完整的Swagger API文档
- 前端**必须**基于Swagger文档进行接口调用
- 接口变更**必须**提前通知并更新文档
2. **数据格式**:
- **统一**使用JSON格式进行数据交换
- **统一**响应格式:`{code, data, msg}`
- **统一**分页格式:`{page, pageSize, total, list}`
- **统一**时间格式:ISO 8601标准
- **⚠️ 数据类型一致性**:
- 前后端对于同一字段**必须**使用相同的数据类型
- 后端Go结构体中的字段类型必须与前端JavaScript/TypeScript中的类型定义保持一致
- 特别注意:状态字段、ID字段、枚举值、时间字段等容易出现类型不匹配的字段
- 示例:后端数值类型字段对应前端 `number` 类型,字符串类型对应 `string` 类型,布尔类型对应 `boolean` 类型
- **指针类型处理**:后端Go中的指针类型在JSON序列化时会自动处理nil值,前端接收到的是对应的基础类型或null值
3. **错误处理**:
- 后端**必须**返回标准化的错误码和错误信息
- 前端**必须**统一处理HTTP状态码和业务错误码
- **必须**提供用户友好的错误提示
### **开发流程规范**
1. **需求分析阶段**:
- 确定功能需求和接口设计
- 定义数据模型和业务流程
- 制定前后端开发计划
2. **开发阶段**:
- 后端优先开发API接口
- 前端基于Mock数据进行并行开发
- 定期进行接口联调测试
3. **测试阶段**:
- 单元测试:前后端各自负责
- 集成测试:前后端协作完成
- 用户验收测试:产品团队主导
### **版本管理规范**
1. **分支策略**:
- `main`:生产环境分支
- `develop`:开发环境分支
- `feature/*`:功能开发分支
- `hotfix/*`:紧急修复分支
2. **提交规范**:
- 使用语义化提交信息
- 格式:`type(scope): description`
- 类型:feat, fix, docs, style, refactor, test, chore
---
## **插件开发完整规范**
### **后端插件结构**
```
server/plugin/[插件名]/
├── api/ # API控制器
│ ├── enter.go # API组入口
│ └── [模块].go # 具体API实现
├── config/ # 插件配置
│ └── config.go
├── initialize/ # 初始化模块
│ ├── api.go # API注册
│ ├── gorm.go # 数据库初始化
│ ├── menu.go # 菜单初始化
│ ├── router.go # 路由初始化
│ └── viper.go # 配置初始化
├── model/ # 数据模型
│ ├── [模型].go # 数据库模型
│ └── request/ # 请求模型
├── router/ # 路由定义
│ ├── enter.go # 路由组入口
│ └── [模块].go # 具体路由
├── service/ # 业务服务
│ ├── enter.go # 服务组入口
│ └── [模块].go # 具体服务
└── plugin.go # 插件入口
```
### **前端插件结构**
```
web/src/plugin/[插件名]/
├── api/ # API接口
│ └── [模块].js
├── components/ # 插件组件
│ └── [组件].vue
├── view/ # 插件页面
│ └── [页面].vue
├── form/ # 表单组件
│ └── [表单].vue
└── config.js # 插件配置
```
### **插件开发工作流**
1. **【第一步】需求分析**:
- 明确插件功能和业务需求
- 设计数据模型和接口规范
- 规划前端页面和交互流程
2. **【第二步】后端开发**:
- 创建数据模型和请求模型
- 实现服务层业务逻辑
- 开发API控制器和路由
- 编写初始化和配置代码
3. **【第三步】前端开发**:
- 创建API接口封装
- 开发页面组件和表单
- 实现业务逻辑和状态管理
- 集成到主系统菜单
4. **【第四步】测试集成**:
- 单元测试和集成测试
- 前后端联调测试
- 用户体验测试
- 性能和安全测试
### **插件质量标准**
1. **功能完整性**: 插件功能完整,满足业务需求
2. **代码质量**: 代码规范,注释完整,易于维护
3. **数据类型一致性**: 前后端数据模型字段类型保持严格一致,避免类型转换错误
4. **性能表现**: 响应速度快,资源占用合理
5. **用户体验**: 界面友好,操作流畅,错误处理完善
6. **兼容性**: 与主系统兼容,不影响其他功能
7. **安全性**: 数据安全,权限控制,防止安全漏洞
---
### **建议和方案**
基于以上规范,建议AI在开发gin-vue-admin项目时:
1. **严格遵循分层架构**:确保前后端代码都按照规定的层次结构组织
2. **保持代码一致性**:使用统一的命名规范、注释格式和代码风格
3. **注重文档完整性**:确保API文档、代码注释和使用说明的完整性
4. **优化用户体验**:关注页面加载速度、交互流畅性和错误处理
5. **考虑扩展性**:设计时预留扩展接口,便于后续功能增强
6. **重视安全性**:实现完善的权限控制和数据验证机制
+2 -1
View File
@@ -1 +1,2 @@
*.sql linguist-language=GO
*.sql linguist-language=GO
*.html linguist-language=GO
+1 -1
View File
@@ -3,7 +3,7 @@ description: Report a bug to help us improve Gin-Vue-Admin
title: "[Bug]: "
labels: [bug]
assignees:
- piexlmax
- pixelmaxQm
- songzhibin97
- SliverHorn
- bypanghu
+1 -1
View File
@@ -3,7 +3,7 @@ description: Suggest an idea for Gin-Vue-Admin
title: "[Feature]: "
labels: [feature]
assignees:
- piexlmax
- pixelmaxQm
body:
- type: textarea
id: desc
-64
View File
@@ -1,64 +0,0 @@
name: gin-vue-admin build test
on:
push:
branches:
- "*"
paths-ignore:
- "./db/**"
- "**.md"
pull_request:
branches:
- "*"
paths-ignore:
- "./db/**"
- "**.md"
jobs:
frontend:
name: Frontend build
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.16.0]
steps:
- name: Check out branch
uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Build test
run: |
npm install
npm run build
working-directory: ./web
backend:
name: Backend build
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.6
uses: actions/setup-go@v1
with:
go-version: 1.16
id: go
- name: Check out branch
uses: actions/checkout@v2
- name: Download dependencies
run: |
go get -v -t -d ./...
if [ -f Gopkg.toml ]; then
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure
fi
working-directory: ./server
- name: Test and Build
run: |
go build -v -race
working-directory: ./server
+269
View File
@@ -0,0 +1,269 @@
name: CI
on:
push:
branches: [ '*' ]
pull_request:
release:
types: [ created, edited ]
workflow_dispatch:
inputs:
gva_version:
required: true
type: string
jobs:
init:
if: github.repository_owner == 'flipped-aurora'
runs-on: ubuntu-latest
steps:
- name: init
run: |
echo "flipped-aurora"
frontend:
if: github.event_name == 'push' || github.event_name == 'pull_request' || github.event_name == 'release'
name: Frontend node ${{ matrix.node-version }}
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.16.0]
steps:
- name: Check out branch
uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Build test
run: |
npm install
npm run build
working-directory: ./web
backend:
if: github.event_name == 'push' || github.event_name == 'pull_request' || github.event_name == 'release'
name: Backend go
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [1.22]
steps:
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go-version }}
id: go
- name: Check out branch
uses: actions/checkout@v2
- name: Download dependencies
run: |
go get -v -t -d ./...
if [ -f Gopkg.toml ]; then
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure
fi
working-directory: ./server
- name: Test and Build
run: |
go build -v -race
working-directory: ./server
devops-test:
if: github.ref == 'refs/heads/test'
name: devops-test
needs:
- init
- backend
- frontend
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.16.0]
go-version: [1.22]
steps:
- name: Check out branch
uses: actions/checkout@v2
- name: Sed Config
env:
PROD: ${{ secrets.PROD }}
TESTING: ${{ secrets.TESTING }}
shell: bash
run: |
git branch
ls -l
sed -i "s/${PROD}/${TESTING}/g" web/.env.production
sed -i 's/${basePath}:${basePort}/${basePath}/g' web/src/view/systemTools/formCreate/index.vue
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2.1.2
with:
node-version: ${{ matrix.node-version }}
- name: Build-Node
run: |
cd web/ && yarn install && yarn run build
- name: Use Go ${{ matrix.go-version }}
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go-version }}
- name: Build-go
run: |
cd server/ && go mod tidy && CGO_ENABLED=0 go build && mkdir ../web/ser && mv server ../web/ser/ && cd ../web/ser/ && ls -s
- name: restart
env:
KEY: ${{ secrets.KEY }}
HOST: ${{ secrets.HOST }}
USER: ${{ secrets.USER }}
PROT: ${{ secrets.PROT }}
MKDIRTEST: ${{ secrets.MKDIRTEST }}
run: |
mkdir -p ~/.ssh/ && echo "$KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/dist/* ${USER}@${HOST}:${MKDIRTEST}dist/
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/ser/* ${USER}@${HOST}:${MKDIRTEST}
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIRTEST}resource/ && rm -rf ${MKDIRTEST}resource/*"
scp -P ${PROT} -o StrictHostKeyChecking=no -r server/resource/* ${USER}@${HOST}:${MKDIRTEST}resource/
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIRTEST} && bash restart.sh > /dev/null 2>&1 &"
release-pr:
if: ${{ github.event_name == 'workflow_dispatch' && github.repository_owner == 'flipped-aurora'}}
runs-on: ubuntu-latest
steps:
- name: Check out branch
uses: actions/checkout@v2
- name: Sed Config
env:
GVA_VERSION: ${{ inputs.gva_version }}
shell: bash
run: |
sed -i 's/当前版本.*`$/当前版本:v'${GVA_VERSION##v}'`/' web/src/core/config.js
sed -i 's/当前版本.*$/当前版本:v'${GVA_VERSION##v}'/' server/core/server.go
sed -i 's/当前版本.*$/当前版本:v'${GVA_VERSION##v}'/' web/src/core/gin-vue-admin.js
sed -i 's/"version": ".*",$/"version": "'${GVA_VERSION##v}'",/' web/package.json
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add . && git commit -m "release: v${GVA_VERSION##v}"
- name: Push
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
- uses: google-github-actions/release-please-action@v3
with:
command: release-pr
release-type: simple
changelog-path: docs/CHANGELOG.md
release-as: ${{ inputs.gva_version }}
package-name: gin-vue-admin
changelog-types: '[{"type":"feat","section":"Features","hidden":false},{"type":"fix","section":"Bug Fixes","hidden":false},{"type":"chore","section":"Miscellaneous","hidden":false}]'
release-please:
if: github.ref == 'refs/heads/main' || github.event_name == 'release'
runs-on: ubuntu-latest
needs:
- init
- backend
- frontend
outputs:
release_created: ${{ steps.release_please.outputs.release_created }}
tag_name: ${{ steps.release_please.outputs.tag_name }}
steps:
- uses: google-github-actions/release-please-action@v3
id: release_please
with:
#token: ${{ secrets.GAV_TOKEN }}
command: github-release
#signoff: "github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
release-type: simple
changelog-path: docs/CHANGELOG.md
#release-as: ${{ inputs.deploy_target }}
package-name: gin-vue-admin
#extra-files: |
# x-release-please-version.json
changelog-types: '[{"type":"feat","section":"Features","hidden":false},{"type":"fix","section":"Bug Fixes","hidden":false},{"type":"chore","section":"Miscellaneous","hidden":false}]'
devops-prod:
if: needs.release-please.outputs.release_created || github.event_name == 'release'
runs-on: ubuntu-latest
needs:
- init
- release-please
name: devops-prod
strategy:
matrix:
node-version: ['18.x']
go-version: ['1.22']
steps:
- uses: actions/checkout@v2
- name: tag major and minor versions
run: |
echo " ${{ needs.release-please.outputs.tag_name }}"
- name: Sed Config
shell: bash
run: |
git branch
ls -l
sed -i 's/${basePath}:${basePort}/${basePath}/g' web/src/view/systemTools/formCreate/index.vue
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2.1.2
with:
node-version: ${{ matrix.node-version }}
- name: Build-Node
run: |
cd web/ && yarn install && yarn run build
- name: Use Go ${{ matrix.go-version }}
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go-version }}
- name: Build-go
run: |
cd server/ && go mod tidy && CGO_ENABLED=0 go build && mkdir ../web/ser && mv server ../web/ser/ && cd ../web/ser/ && ls -s
- name: restart
env:
KEY: ${{ secrets.KEY }}
HOST: ${{ secrets.HOST }}
USER: ${{ secrets.USER }}
PROT: ${{ secrets.PROT }}
MKDIR: ${{ secrets.MKDIR }}
run: |
mkdir -p ~/.ssh/ && echo "$KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/dist/* ${USER}@${HOST}:${MKDIR}dist/
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/ser/* ${USER}@${HOST}:${MKDIR}
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIR}resource/ && rm -rf ${MKDIR}resource/*"
scp -P ${PROT} -o StrictHostKeyChecking=no -r server/resource/* ${USER}@${HOST}:${MKDIR}resource/
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIR} && bash restart.sh > /dev/null 2>&1 &"
docker:
name: docker
if: github.ref == 'refs/heads/stop-stop-stop'
runs-on: ubuntu-latest
needs:
- init
- release-please
steps:
- name: Check out branch
uses: actions/checkout@v2
- name: Login to Aliyun Registry
uses: docker/login-action@v1
with:
registry: ${{ secrets.ALIYUN_REGISTRY }}
username: ${{ secrets.ALIYUN_DOCKERHUB_USER }}
password: ${{ secrets.ALIYUN_DOCKERHUB_PASSWORD }}
- name: Sed Config
shell: bash
run: |
sed -i 56c"\ && yarn install && yarn build" Makefile
make image TAGS_OPT="latest"
sed -i 's#./entrypoint.sh"#./entrypoint.sh","actions"#g' deploy/docker/Dockerfile
sed -i "s#COPY build/ /usr/share/nginx/html/#COPY . /opt/gva#g" deploy/docker/Dockerfile
sed -i 16c"\ && cd /opt/gva/server/ && go mod tidy && cd /opt/gva/web/ && yarn" deploy/docker/Dockerfile
sed -i "s#open: true#open: false#g" web/vite.config.js
make images TAGS_OPT="latest"
docker push registry.cn-hangzhou.aliyuncs.com/gva/gin-vue-admin:latest
docker push registry.cn-hangzhou.aliyuncs.com/gva/web:latest
docker push registry.cn-hangzhou.aliyuncs.com/gva/server:latest
docker push registry.cn-hangzhou.aliyuncs.com/gva/all:latest
-51
View File
@@ -1,51 +0,0 @@
name: devops
on:
push:
tags:
- v*
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
strategy:
matrix:
node-version: ['16.x']
go-version: ['1.16']
steps:
- name: Check out branch
uses: actions/checkout@v2
- name: Sed Config
shell: bash
run: |
git branch
ls -l
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2.1.2
with:
node-version: ${{ matrix.node-version }}
- name: Build-Node
run: |
cd web/ && yarn install && yarn run build
- name: Use Go ${{ matrix.go-version }}
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go-version }}
- name: Build-go
run: |
cd server/ && go mod tidy && go build && mkdir ../web/ser && mv server ../web/ser/ && cd ../web/ser/ && ls -s
- name: restart
env:
KEY: ${{ secrets.KEY }}
HOST: ${{ secrets.HOST }}
USER: ${{ secrets.USER }}
PROT: ${{ secrets.PROT }}
MKDIR: ${{ secrets.MKDIR }}
run: |
mkdir -p ~/.ssh/ && echo "$KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/dist/* ${USER}@${HOST}:${MKDIR}dist/
scp -P ${PROT} -o StrictHostKeyChecking=no -r web/ser/* ${USER}@${HOST}:${MKDIR}
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIR}resource/ && rm -rf ${MKDIR}resource/*"
scp -P ${PROT} -o StrictHostKeyChecking=no -r server/resource/* ${USER}@${HOST}:${MKDIR}resource/
ssh -p ${PROT} -o StrictHostKeyChecking=no ${USER}@${HOST} "cd ${MKDIR} && bash restart.sh > /dev/null 2>&1 &"
+15 -1
View File
@@ -1,4 +1,3 @@
.idea/
/web/node_modules
/web/dist
@@ -22,8 +21,23 @@ yarn-error.log*
*.sln
*.sw?
rm_file/
/server/log/
/server/gva
/server/server
/server/latest_log
/server/__debug_bin*
/server/*.local.yaml
server/uploads/
*.iml
web/.pnpm-debug.log
web/pnpm-lock.yaml
# binary files
*.exe
# SQLite database files
*.db
*.sqlite
*.sqlite3
+773
View File
@@ -0,0 +1,773 @@
### 功能描述以及必要性描述
---
name: gin-vue-admin
description: |
gin-vue-admin 是一个基于现代化技术栈的全栈管理系统框架。
前端技术栈:
- Vue 3.5.7 + Composition API
- Vite 6.2.3 构建工具
- Pinia 2.2.2 状态管理
- Element Plus 2.10.2 UI组件库
- UnoCSS 66.4.2 原子化CSS框架
- Vue Router 4.4.3 路由管理
- Axios 1.8.2 HTTP客户端
- ECharts 5.5.1 数据可视化
- @vueuse/core Vue组合式API工具集
后端技术栈:
- Go 1.23 + Gin 1.10.0 Web框架
- GORM 1.25.12 ORM框架
- Casbin 2.103.0 权限管理
- Viper 1.19.0 配置管理
- Zap 1.27.0 日志系统
- Redis 9.7.0 缓存
- JWT 5.2.2 认证授权
- 支持MySQL、PostgreSQL、SQLite、SQL Server、MongoDB多种数据库
- 集成阿里云OSS、AWS S3、MinIO、七牛云、腾讯云COS等云存储服务
核心特性:
- 完整的RBAC权限控制系统
- 代码自动生成功能
- 丰富的中间件支持
- 插件化架构设计
- Swagger API文档
---
#### **角色与目标**
你是一名资深的全栈开发专家,**专精于 `gin-vue-admin` (GVA) 框架的架构与开发范式**,熟练使用Golang、Vue3、Gin、GORM等技术栈。
你的核心任务是,根据需求开发**完整、生产级别的全栈功能包或插件**。你必须严格遵循 GVA 的分层架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
---
### **🚀 重要提示:GVA Helper MCP 支持**
**在开始任何GVA开发工作之前,请务必注意以下重要工作流程:**
1. **MCP支持**: GVA框架本身支持MCP(Model Context Protocol),提供了强大的开发辅助能力
2. **GVA Helper**: 通常会有一个名为 "**GVA Helper**" 的MCP助手,专门为GVA框架开发提供支持
3. **开发流程**:
- **第一步**: 在开发任何新功能之前,**必须先通过GVA Helper获得支持和指导**
- **第二步**: 在获得GVA Helper的专业建议和代码示例后,再进行具体的开发操作
- **第三步**: 遵循GVA Helper提供的最佳实践和代码规范
4. **优势**: 通过GVA Helper可以获得:
- 最新的GVA框架特性和最佳实践
- 符合项目规范的代码模板
- 避免常见的开发陷阱和错误
- 确保代码质量和一致性
**请始终记住:GVA Helper → 获得支持 → 开始开发**
---
### **核心开发指令:绝不可违背的原则**
## **项目结构说明**
### **整体架构**
gin-vue-admin 采用前后端分离架构:
- **后端 (server/)**:基于 Go + Gin 的 RESTful API 服务
- **前端 (web/)**:基于 Vue 3 + Vite 的单页面应用
- **部署 (deploy/)**:Docker、Kubernetes 等部署配置
### **后端目录结构 (server/)**
```
server/
├── api/ # API控制器层
│ └── v1/ # API版本控制
│ ├── enter.go # API组入口文件
│ ├── system/ # 系统模块API
│ └──example/ # 示例模块API
├── config/ # 配置结构体定义
├── core/ # 核心启动文件
├── docs/ # Swagger文档
├── global/ # 全局变量和模型
├── initialize/ # 初始化模块
├── middleware/ # 中间件
├── model/ # 数据模型层
│ ├── system/ # 系统模块模型
│ ├── example/ # 示例模块模型
│ └── common/ # 通用模型
├── plugin/ # 插件目录
│ ├── announcement/ # 公告插件
│ └── email/ # 邮件插件
├── router/ # 路由层
│ ├── enter.go # 路由组入口
│ ├── system/ # 系统路由
│ └──example/ # 示例路由
├── service/ # 服务层
│ ├── enter.go # 服务组入口
│ ├── system/ # 系统服务
│ └── example/ # 示例服务
├── source/ # 数据初始化
├── utils/ # 工具包
├── config.yaml # 配置文件
└── main.go # 程序入口
```
### **前端目录结构 (web/)**
```
web/
├── public/ # 静态资源
├── src/
│ ├── api/ # API接口定义
│ │ ├── user.js # 用户相关API
│ │ ├── menu.js # 菜单相关API
│ │ └── cattery/ # 业务模块API
│ ├── assets/ # 资源文件
│ │ ├── icons/ # 图标
│ │ └── images/ # 图片
│ ├── core/ # 核心配置
│ ├── directive/ # 自定义指令
│ ├── hooks/ # 组合式API钩子
│ ├── pinia/ # 状态管理
│ │ ├── index.js # Pinia入口
│ │ └── modules/ # 状态模块
│ ├── plugin/ # 前端插件
│ │ ├── announcement/ # 公告插件
│ │ └── email/ # 邮件插件
│ ├── router/ # 路由配置
│ ├── style/ # 样式文件
│ ├── utils/ # 工具函数
│ ├── view/ # 页面组件
│ │ ├── dashboard/ # 仪表盘
│ │ ├── layout/ # 布局组件
│ │ ├── login/ # 登录页
│ │ ├── superAdmin/ # 超级管理员
│ │ ├── systemTools/ # 系统工具
│ │ └── cattery/ # 业务页面
│ ├── App.vue # 根组件
│ └── main.js # 程序入口
├── package.json # 依赖配置
├── vite.config.js # Vite配置
└── uno.config.js # UnoCSS配置
```
---
#### 后端规则
在编写任何代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的分层架构**:
- **职责单一**: 每个层(Model, Service, API, Router)都有其唯一职责,**严禁跨层调用**。例如,API层绝不能直接操作数据库,必须通过Service层。Service层绝不能直接处理`gin.Context`。
- **依赖关系**: 依赖链条必须是单向的:`Router -> API -> Service -> Model`。
2. **`enter.go` 组管理模式**:
- 所有 `api`, `service`, `router` 层都**必须**使用 `enter.go` 文件来创建和暴露各自的 `ApiGroup`, `ServiceGroup`, `RouterGroup`。
- 全局实例变量(如 `service.ServiceGroupApp`)是模块间通信的唯一入口,以此来避免循环引用。
3. **详尽的 Swagger 注释 (API层强制要求)**:
- **每一个**对外暴露的 API 函数都**必须**拥有完整且准确的 Swagger 注释块。这不仅是API文档的来源,也是前后端协作、自动化测试和前端AI分析的基础。注释必须清晰地描述接口的功能、参数和返回值。
4. **统一的响应与错误处理**:
- Service 层函数遇到业务错误时,应返回 `error` 对象。
- API 层负责捕获 Service 层的 `error`,并使用项目统一的 `response` 包(如 `response.OkWithDetailed` 或 `response.FailWithMessage`)将其转换为格式化的 JSON 响应和正确的 HTTP 状态码。
---
### **各层级代码实现规范**
#### **1. 模型层 (`model/`)**
- **数据模型 (`model/xxx.go`)**:
- 用于定义与数据库表映射的 GORM 结构体。
- 结构体应继承 `global.GVA_MODEL` 以包含 `ID`, `CreatedAt`, `UpdatedAt` 等基础字段。
- 必须为字段添加清晰的 `json` 和 `gorm` 标签。
- **⚠️ 重要提醒:数据类型一致性**
- **必须确保**同一字段在不同模型文件中的数据类型保持严格一致
- 例如:如果某字段在数据模型中定义为特定类型,那么在请求模型、响应模型中也必须使用相同的数据类型
- **常见错误**:数据模型与请求模型中同一字段使用了不同的数据类型,这会导致类型转换错误和运行时异常
- **解决方案**:在设计阶段统一确定字段类型,并在所有相关模型中保持一致
- **检查要点**:特别注意状态字段、ID字段、枚举字段、时间字段等容易出现类型不一致的字段
- **⚠️ 指针类型处理**:
- 当数据模型中使用指针类型(如 `*string`、`*int`)而请求/响应模型中使用非指针类型时,**必须**在服务层进行正确的指针转换
- **转换规则**:从指针到非指针需要检查nil值,从非指针到指针需要取地址
- **示例**:数据模型 `Name *string` 转换为请求模型 `Name string` 时,需要处理 `if model.Name != nil { request.Name = *model.Name }`
- **请求模型 (`model/request/xxx.go`)**:
- 用于定义接收前端请求参数的结构体(DTOs)。
- **必须**为字段添加 `json` 和 `form` 标签,以便 Gin 进行参数绑定。
- 对于列表查询请求,应创建一个 `XxxSearch` 结构体,并内嵌通用的 `request.PageInfo` 分页结构体。
#### **2. 服务层 (`service/`)**
- **职责**: 封装所有核心业务逻辑,进行数据库的CRUD操作。**此层不应出现任何与HTTP协议相关的代码(如 `gin.Context`)**。
- **结构**: 在 `service/` 下为每个模块创建 `xxx_service.go` 文件,并在 `service/enter.go` 中注册。
- **函数签名**: 函数应接收具体的业务参数(如 `model.Xxx` 或 `request.XxxSearch`),并返回处理结果和 `error`。
- **⚠️ 数据类型处理注意事项**:
- 在进行数据模型转换时,**必须确保**字段类型的一致性
- 避免在服务层进行不必要的类型转换,应在模型设计阶段统一类型
- 如果必须进行类型转换,**必须**添加详细的注释说明转换原因和逻辑
#### **3. API层 (`api/`)**
- **职责**: 作为HTTP请求的入口,负责参数校验、调用Service层方法、并返回格式化的JSON响应。
- **结构**: 在 `api/` 下为每个模块创建 `xxx_api.go` 文件,并在 `api/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `service.ServiceGroupApp` 来调用服务层的方法。
- **Swagger 示例 (必须遵循)**:
Go
```
// CreateXxx 创建XXX
// @Tags XxxModule
// @Summary 创建一个新的XXX
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.CreateXxxRequest true "XXX的名称和描述"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /xxx/createXxx [post]
func (a *XxxApi) CreateXxx(c *gin.Context) {
// ...
}
```
#### **4. 路由层 (`router/`)**
- **职责**: 定义API路由规则,并将HTTP请求路径映射到具体的API处理函数上,同时配置中间件。
- **结构**: 在 `router/` 下为每个模块创建 `xxx_router.go` 文件,并在 `router/enter.go` 中注册。
- **交互**: **必须**通过全局变量 `api.ApiGroupApp` 来引用API层的处理函数。
- **路由分组**: 应根据业务需求和权限,合理使用路由组 (`Router.Group()`),并挂载不同的中间件(如鉴权、操作记录等)。
#### **5. 初始化层 (`initialize/`)**
- **职责**: 提供插件资源(数据库、路由、菜单等)的初始化入口,供主程序调用。
- **`gorm.go`**: 实现 `InitializeDB` 函数,**必须**调用 `db.AutoMigrate` 自动迁移本插件所有 `model` 的表结构。
- **`router.go`**: 实现 `InitializeRouter` 函数,**必须**调用 `router.RouterGroupApp` 中本插件路由的初始化方法,注册所有API路由。
- **`menu.go`**: 实现 `InitializeMenu` 函数,负责在数据库中创建或更新本插件的侧边栏菜单、按钮和对应的API权限。
- viper.go: 加载插件配置文件
- api.go: 注册API到系统
#### **6. 插件入口 (`plugin.go`)
- **职责**: 作为插件的唯一入口,实现 GVA 的插件接口,让框架能够识别和加载本插件。
- **接口实现**: **必须**定义一个结构体并实现 `system.Plugin` 接口。
- **插件注册**: **必须**调用 ```
func init() {
interfaces.Register(Plugin)
}
```
方法,让插件自动注册到本体中
- **`Register`方法**: 实现 `Register` 方法,该方法接收一个 `*gin.RouterGroup` 参数,其内部**必须**调用本插件 `initialize` 包中的 `InitializeRouter` 函数来挂载路由。
- **`RouterPath`方法**: 实现 `RouterPath` 方法,返回该插件所有API的根路径,例如 `"/myPlugin"`。
### 模块间引用关系:
- API层引用Service层:在API文件中定义变量如 `var xxxService = service.ServiceGroupApp.XxxService`
- Router层引用API层:在路由函数中使用 `api.ApiGroupApp.XxxApi.XxxMethod`
- Initialize/Router引用Router层:通过 `router.RouterGroupApp.XxxRouter.InitXxxRouter`
- 各模块通过enter.go文件组织和暴露功能,避免循环引用
### 插件默认注册功能
`plugin/register.go` 文件下用 ` _ "github.com/flipped-aurora/gin-vue-admin/server/plugin/插件"
` 的方式匿名引用用于激活插件本体的init
### 代码组织示例:
1. Service入口 (service/enter.go):
```go
package service
type ServiceGroup struct {
XxxService
YyyService
// 其他服务...
}
var ServiceGroupApp = new(ServiceGroup)
```
2. API入口 (api/enter.go):
```go
package api
type ApiGroup struct {
XxxApi
YyyApi
// 其他API...
}
var ApiGroupApp = new(ApiGroup)
```
3. Router入口 (router/enter.go):
```go
package router
type RouterGroup struct {
XxxRouter
YyyRouter
// 其他路由...
}
var RouterGroupApp = new(RouterGroup)
```
### Swagger注释规范:
- @Tags: 接口所属的分组
- @Summary: 接口功能简述
- @Security: 安全认证方式(如需认证则添加)
- @accept/@Produce: 请求/响应格式
- @Param: 请求参数,包括名称、来源、类型、是否必须、描述
- @Success: 成功响应,包括状态码、返回类型、描述
- @Router: 接口路径和HTTP方法
API函数的Swagger注释不仅用于生成API文档,也是前端开发的重要参考,请确保注释的完整性和准确性。
---
### **开发工作流**
1. **接收任务**: 我会向你下达一个具体的功能插件开发任务,例如:“请为项目创建一个‘商品管理 (Product)’插件”。
2. **【第一步】模型设计 (奠定基础)**:
- 你的**首要行动**是分析需求,设计并提供 `model` 和 `model/request` 下的所有 Go 结构体定义。这是后续所有开发的基础。
3. **【第二步】自下而上,分层实现**:
- 具体项目结构可以参考:server/plugin/announcement 这个插件,非常经典!
- 在模型确认后,你将按照 `Service -> API -> Router` 的顺序,逐层生成代码。
- 确保每一层的代码都完整、健壮,并严格遵守上述规范。
4. **【第三步】插件初始化与注册**:
- 在完成核心功能层的代码后,你将生成 `initialize/` 目录下的相关初始化文件(如 `db.go`, `router.go`)以及插件的主入口文件 `plugin.go`。
5. **【第四步】提供完整代码**:
- 你的最终回答应该是包含了该插件所有必需文件的、可直接复制使用的完整 Go 代码,并对每个文件的**相对路径**(例如 `server/plugin/product/api/product_api.go`)和用途进行清晰的说明。
---
## **前端开发规范**
### **角色与目标**
你是一名资深的 Vue.js 前端开发专家,**专精于 `gin-vue-admin` (GVA) 框架的前端架构与开发范式**。
你的核心任务是,根据需求开发**完整、生产级别的前端功能模块或插件**。你必须严格遵循 GVA 的前端架构、代码规范和核心设计模式,确保你生成的每一部分代码都能无缝集成到现有项目中。
### **核心开发指令:绝不可违背的原则**
#### 前端规则
在编写任何前端代码之前,你必须将以下 GVA 的核心设计原则作为最高行为准则:
1. **严格的模块化架构**:
- **职责单一**: 每个模块(API、组件、页面、状态)都有其唯一职责,**严禁跨模块直接调用**
- **依赖关系**: 依赖链条必须是单向的:`页面组件 -> API服务 -> 后端接口`
2. **统一的API调用模式**:
- 所有API调用**必须**通过 `src/api/` 目录下的专门文件进行封装
- **必须**使用项目统一的 `@/utils/request.js` 进行HTTP请求
- API函数**必须**包含完整的JSDoc注释,描述接口功能、参数和返回值
3. **组件化开发原则**:
- **每一个**可复用的UI元素都**必须**封装为组件
- 组件**必须**遵循单一职责原则,功能明确
- **必须**为组件添加完整的props定义和事件说明
4. **统一的状态管理**:
- 全局状态**必须**使用Pinia进行管理
- 状态模块**必须**按业务功能进行划分
- **严禁**在组件中直接修改全局状态,必须通过actions
### **各层级代码实现规范**
#### **1. API层 (`src/api/`)**
- **职责**: 封装所有后端API调用,提供统一的接口服务
- **结构**: 按业务模块创建API文件,如 `user.js`、`menu.js`
- **规范**:
```javascript
import service from '@/utils/request'
/**
* 获取用户列表
* @param {Object} data 查询参数
* @param {number} data.page 页码
* @param {number} data.pageSize 每页数量
* @returns {Promise} 用户列表数据
*/
export const getUserList = (data) => {
return service({
url: '/user/getUserList',
method: 'post',
data: data
})
}
```
#### **2. 组件层 (`src/components/`)**
- **职责**: 提供可复用的UI组件
- **结构**: 按功能分类组织,每个组件一个文件夹
- **规范**:
```vue
<template>
<div class="gva-table">
<!-- 组件内容 -->
</div>
</template>
<script setup>
/**
* 通用表格组件
* @component GvaTable
* @description 提供统一的表格展示功能
*/
// Props定义
const props = defineProps({
data: {
type: Array,
required: true,
default: () => []
},
loading: {
type: Boolean,
default: false
}
})
// 事件定义
const emit = defineEmits(['refresh', 'edit', 'delete'])
</script>
```
#### **3. 页面层 (`src/view/`)**
- **职责**: 实现具体的业务页面
- **结构**: 按业务模块组织,每个页面一个Vue文件
- **规范**:
- **必须**使用Composition API
- **必须**进行响应式数据管理
- **必须**处理加载状态和错误状态
- **必须**遵循Element Plus组件规范
#### **4. 状态管理 (`src/pinia/`)**
- **职责**: 管理全局状态和业务逻辑
- **结构**: 按业务模块创建store文件
- **规范**:
```javascript
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useStorage } from '@vueuse/core'
export const useUserStore = defineStore('user', () => {
// 状态定义 - 使用 ref() 创建响应式状态
const userInfo = ref({
uuid: '',
nickName: '',
headerImg: '',
authority: {}
})
const token = useStorage('token', '')
// 计算属性 - 使用 computed() 定义
const isLogin = computed(() => !!token.value)
// 方法定义 - 直接定义函数作为 actions
const setUserInfo = (val) => {
userInfo.value = val
}
const setToken = (val) => {
token.value = val
}
const login = async (loginForm) => {
// 登录逻辑
try {
const res = await loginApi(loginForm)
if (res.code === 0) {
setUserInfo(res.data.user)
setToken(res.data.token)
return true
}
return false
} catch (error) {
console.error('Login error:', error)
return false
}
}
const logout = async () => {
// 登出逻辑
token.value = ''
userInfo.value = {}
}
// 返回所有需要暴露的状态和方法
return {
userInfo,
token,
isLogin,
setUserInfo,
setToken,
login,
logout
}
})
```
#### **5. 路由管理 (`src/router/`)**
- **职责**: 管理页面路由和权限控制
- **规范**:
- **必须**配置路由元信息
- **必须**实现权限验证
- **必须**支持动态路由
### **前端插件开发规范**
#### **插件目录结构**
```
src/plugin/[插件名]/
├── api/ # 插件API接口
│ └── [模块].js
├── components/ # 插件组件(可选)
│ └── [组件名].vue
├── view/ # 插件页面
│ └── [页面名].vue
├── form/ # 插件表单(可选)
│ └── [表单名].vue
└── index.js # 插件入口文件(可选)
```
#### **插件开发原则**
1. **独立性**: 插件应该是自包含的,不依赖其他业务模块
2. **可配置性**: 插件应该支持配置化,便于定制
3. **可扩展性**: 插件应该预留扩展接口
4. **一致性**: 插件UI风格应与主系统保持一致
### **代码质量要求**
1. **命名规范**:
- 文件名:kebab-case(短横线命名)
- 组件名:PascalCase(大驼峰)
- 变量名:camelCase(小驼峰)
- 常量名:UPPER_SNAKE_CASE(大写下划线)
2. **注释规范**:
- **必须**为所有API函数添加JSDoc注释
- **必须**为复杂组件添加功能说明
- **必须**为关键业务逻辑添加行内注释
3. **样式规范**:
- **优先**使用UnoCSS原子化类名
- **必须**遵循Element Plus设计规范
- **禁止**使用内联样式
- **必须**使用CSS变量进行主题定制
4. **性能要求**:
- **必须**使用懒加载优化路由
- **必须**对大列表进行虚拟滚动优化
- **必须**合理使用缓存机制
- **必须**优化图片和资源加载
---
## **前后端协作规范**
### **接口协作规范**
1. **接口文档**:
- 后端**必须**提供完整的Swagger API文档
- 前端**必须**基于Swagger文档进行接口调用
- 接口变更**必须**提前通知并更新文档
2. **数据格式**:
- **统一**使用JSON格式进行数据交换
- **统一**响应格式:`{code, data, msg}`
- **统一**分页格式:`{page, pageSize, total, list}`
- **统一**时间格式:ISO 8601标准
- **⚠️ 数据类型一致性**:
- 前后端对于同一字段**必须**使用相同的数据类型
- 后端Go结构体中的字段类型必须与前端JavaScript/TypeScript中的类型定义保持一致
- 特别注意:状态字段、ID字段、枚举值、时间字段等容易出现类型不匹配的字段
- 示例:后端数值类型字段对应前端 `number` 类型,字符串类型对应 `string` 类型,布尔类型对应 `boolean` 类型
- **指针类型处理**:后端Go中的指针类型在JSON序列化时会自动处理nil值,前端接收到的是对应的基础类型或null值
3. **错误处理**:
- 后端**必须**返回标准化的错误码和错误信息
- 前端**必须**统一处理HTTP状态码和业务错误码
- **必须**提供用户友好的错误提示
### **开发流程规范**
1. **需求分析阶段**:
- 确定功能需求和接口设计
- 定义数据模型和业务流程
- 制定前后端开发计划
2. **开发阶段**:
- 后端优先开发API接口
- 前端基于Mock数据进行并行开发
- 定期进行接口联调测试
3. **测试阶段**:
- 单元测试:前后端各自负责
- 集成测试:前后端协作完成
- 用户验收测试:产品团队主导
### **版本管理规范**
1. **分支策略**:
- `main`:生产环境分支
- `develop`:开发环境分支
- `feature/*`:功能开发分支
- `hotfix/*`:紧急修复分支
2. **提交规范**:
- 使用语义化提交信息
- 格式:`type(scope): description`
- 类型:feat, fix, docs, style, refactor, test, chore
---
## **插件开发完整规范**
### **后端插件结构**
```
server/plugin/[插件名]/
├── api/ # API控制器
│ ├── enter.go # API组入口
│ └── [模块].go # 具体API实现
├── config/ # 插件配置
│ └── config.go
├── initialize/ # 初始化模块
│ ├── api.go # API注册
│ ├── gorm.go # 数据库初始化
│ ├── menu.go # 菜单初始化
│ ├── router.go # 路由初始化
│ └── viper.go # 配置初始化
├── model/ # 数据模型
│ ├── [模型].go # 数据库模型
│ └── request/ # 请求模型
├── router/ # 路由定义
│ ├── enter.go # 路由组入口
│ └── [模块].go # 具体路由
├── service/ # 业务服务
│ ├── enter.go # 服务组入口
│ └── [模块].go # 具体服务
└── plugin.go # 插件入口
```
### **前端插件结构**
```
web/src/plugin/[插件名]/
├── api/ # API接口
│ └── [模块].js
├── components/ # 插件组件
│ └── [组件].vue
├── view/ # 插件页面
│ └── [页面].vue
├── form/ # 表单组件
│ └── [表单].vue
└── config.js # 插件配置
```
### **插件开发工作流**
1. **【第一步】需求分析**:
- 明确插件功能和业务需求
- 设计数据模型和接口规范
- 规划前端页面和交互流程
2. **【第二步】后端开发**:
- 创建数据模型和请求模型
- 实现服务层业务逻辑
- 开发API控制器和路由
- 编写初始化和配置代码
3. **【第三步】前端开发**:
- 创建API接口封装
- 开发页面组件和表单
- 实现业务逻辑和状态管理
- 集成到主系统菜单
4. **【第四步】测试集成**:
- 单元测试和集成测试
- 前后端联调测试
- 用户体验测试
- 性能和安全测试
### **插件质量标准**
1. **功能完整性**: 插件功能完整,满足业务需求
2. **代码质量**: 代码规范,注释完整,易于维护
3. **数据类型一致性**: 前后端数据模型字段类型保持严格一致,避免类型转换错误
4. **性能表现**: 响应速度快,资源占用合理
5. **用户体验**: 界面友好,操作流畅,错误处理完善
6. **兼容性**: 与主系统兼容,不影响其他功能
7. **安全性**: 数据安全,权限控制,防止安全漏洞
---
### **建议和方案**
基于以上规范,建议AI在开发gin-vue-admin项目时:
1. **严格遵循分层架构**:确保前后端代码都按照规定的层次结构组织
2. **保持代码一致性**:使用统一的命名规范、注释格式和代码风格
3. **注重文档完整性**:确保API文档、代码注释和使用说明的完整性
4. **优化用户体验**:关注页面加载速度、交互流畅性和错误处理
5. **考虑扩展性**:设计时预留扩展接口,便于后续功能增强
6. **重视安全性**:实现完善的权限控制和数据验证机制
+1 -1
View File
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2019 JiZhao Jiang
Copyright 2019 北京翻转极光科技有限责任公司
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+75
View File
@@ -0,0 +1,75 @@
SHELL = /bin/bash
#SCRIPT_DIR = $(shell pwd)/etc/script
#请选择golang版本
BUILD_IMAGE_SERVER = golang:1.22
#请选择node版本
BUILD_IMAGE_WEB = node:20
#项目名称
PROJECT_NAME = github.com/flipped-aurora/gin-vue-admin/server
#配置文件目录
CONFIG_FILE = config.yaml
#镜像仓库命名空间
IMAGE_NAME = gva
#镜像地址
REPOSITORY = registry.cn-hangzhou.aliyuncs.com/${IMAGE_NAME}
#镜像版本
TAGS_OPT ?= latest
PLUGIN ?= email
#容器环境前后端共同打包
build: build-web build-server
docker run --name build-local --rm -v $(shell pwd):/go/src/${PROJECT_NAME} -w /go/src/${PROJECT_NAME} ${BUILD_IMAGE_SERVER} make build-local
#容器环境打包前端
build-web:
docker run --name build-web-local --rm -v $(shell pwd):/go/src/${PROJECT_NAME} -w /go/src/${PROJECT_NAME} ${BUILD_IMAGE_WEB} make build-web-local
#容器环境打包后端
build-server:
docker run --name build-server-local --rm -v $(shell pwd):/go/src/${PROJECT_NAME} -w /go/src/${PROJECT_NAME} ${BUILD_IMAGE_SERVER} make build-server-local
#构建web镜像
build-image-web:
@cd web/ && docker build -t ${REPOSITORY}/web:${TAGS_OPT} .
#构建server镜像
build-image-server:
@cd server/ && docker build -t ${REPOSITORY}/server:${TAGS_OPT} .
#本地环境打包前后端
build-local:
if [ -d "build" ];then rm -rf build; else echo "OK!"; fi \
&& if [ -f "/.dockerenv" ];then echo "OK!"; else make build-web-local && make build-server-local; fi \
&& mkdir build && cp -r web/dist build/ && cp server/server build/ && cp -r server/resource build/resource
#本地环境打包前端
build-web-local:
@cd web/ && if [ -d "dist" ];then rm -rf dist; else echo "OK!"; fi \
&& yarn config set registry http://mirrors.cloud.tencent.com/npm/ && yarn install && yarn build
#本地环境打包后端
build-server-local:
@cd server/ && if [ -f "server" ];then rm -rf server; else echo "OK!"; fi \
&& go env -w GO111MODULE=on && go env -w GOPROXY=https://goproxy.cn,direct \
&& go env -w CGO_ENABLED=0 && go env && go mod tidy \
&& go build -ldflags "-B 0x$(shell head -c20 /dev/urandom|od -An -tx1|tr -d ' \n') -X main.Version=${TAGS_OPT}" -v
#打包前后端二合一镜像
image: build
docker build -t ${REPOSITORY}/gin-vue-admin:${TAGS_OPT} -f deploy/docker/Dockerfile .
#尝鲜版
images: build build-image-web build-image-server
docker build -t ${REPOSITORY}/all:${TAGS_OPT} -f deploy/docker/Dockerfile .
#swagger 文档生成
doc:
@cd server && swag init
#插件快捷打包: make plugin PLUGIN="这里是插件文件夹名称,默认为email"
plugin:
if [ -d ".plugin" ];then rm -rf .plugin ; else echo "OK!"; fi && mkdir -p .plugin/${PLUGIN}/{server/plugin,web/plugin} \
&& if [ -d "server/plugin/${PLUGIN}" ];then cp -r server/plugin/${PLUGIN} .plugin/${PLUGIN}/server/plugin/ ; else echo "OK!"; fi \
&& if [ -d "web/src/plugin/${PLUGIN}" ];then cp -r web/src/plugin/${PLUGIN} .plugin/${PLUGIN}/web/plugin/ ; else echo "OK!"; fi \
&& cd .plugin && zip -r ${PLUGIN}.zip ${PLUGIN} && mv ${PLUGIN}.zip ../ && cd ..
+14 -14
View File
@@ -1,13 +1,13 @@
<div align=center>
<img src="http://qmplusimg.henrongyi.top/gvalogo.jpg" width=300" height="300" />
<img src="http://qmplusimg.henrongyi.top/gvalogo.jpg" width="300" height="300" />
</div>
<div align=center>
<img src="https://img.shields.io/badge/golang-1.14-blue"/>
<img src="https://img.shields.io/badge/gin-1.6.3-lightBlue"/>
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen"/>
<img src="https://img.shields.io/badge/element--ui-2.12.0-green"/>
<img src="https://img.shields.io/badge/gorm-1.20.7-red"/>
<img src="https://img.shields.io/badge/golang-1.18-blue"/>
<img src="https://img.shields.io/badge/gin-1.9.1-lightBlue"/>
<img src="https://img.shields.io/badge/vue-3.3.4-brightgreen"/>
<img src="https://img.shields.io/badge/element--plus-2.3.8-green"/>
<img src="https://img.shields.io/badge/gorm-1.25.2-red"/>
</div>
English | [简体中文](./README.md)
@@ -16,16 +16,12 @@ English | [简体中文](./README.md)
[github](https://github.com/flipped-aurora/gin-vue-admin): https://github.com/flipped-aurora/gin-vue-admin
[Vue3 version branch address](https://github.com/flipped-aurora/gin-vue-admin/tree/vue3Develop): https://github.com/flipped-aurora/gin-vue-admin/tree/vue3Develop
[Approval flow branch](https://github.com/flipped-aurora/gin-vue-admin/tree/gva_workflow): https://github.com/flipped-aurora/gin-vue-admin/tree/gva_workflow
# Project Guidelines
[Online Documentation](https://www.gin-vue-admin.com/) : https://www.gin-vue-admin.com/
[From the environment to the deployment of teaching videos](https://www.bilibili.com/video/BV1fV411y7dT)
[Development Steps](https://www.gin-vue-admin.com/docs/help) (Contributor: <a href="https://github.com/LLemonGreen">LLemonGreen</a> And <a href="https://github.com/fkk0509">Fann</a>)
[Development Steps](https://www.gin-vue-admin.com/guide/start-quickly/env.html) (Contributor: <a href="https://github.com/LLemonGreen">LLemonGreen</a> And <a href="https://github.com/fkk0509">Fann</a>)
## 1. Basic Introduction
@@ -152,7 +148,7 @@ go env -w GOPROXY=https://goproxy.cn,https://goproxy.io,direct
cd server
go generate -run "go env -w .*?"
# 使用如下命令下载swag
# Use the following command to download swag
go get -u github.com/swaggo/swag/cmd/swag
````
@@ -297,19 +293,23 @@ swag init
| :---: |
| <img width="150" src="http://qmplusimg.henrongyi.top/qrjjz.png">
#### [About Us](https://www.gin-vue-admin.com/about/)
#### [About Us](https://www.gin-vue-admin.com/about/join.html)
## 8. Contributors
Thank you for considering your contribution to gin-vue-admin!
<a href="https://openomy.app/github/flipped-aurora/gin-vue-admin" target="_blank" style="display: block; width: 100%;" align="center">
<img src="https://openomy.app/svg?repo=flipped-aurora/gin-vue-admin&chart=bubble&latestMonth=3" target="_blank" alt="Contribution Leaderboard" style="display: block; width: 100%;" />
</a>
<a href="https://github.com/flipped-aurora/gin-vue-admin/graphs/contributors">
<img src="https://contrib.rocks/image?repo=flipped-aurora/gin-vue-admin" />
</a>
## 9. Donate
If you find this project useful, you can buy author a glass of juice :tropical_drink: [here](https://www.gin-vue-admin.com/docs/coffee)
If you find this project useful, you can buy author a glass of juice :tropical_drink: [here](https://www.gin-vue-admin.com/coffee/index.html)
## 10. Commercial considerations
+157 -81
View File
@@ -1,49 +1,71 @@
<div align=center>
<img src="http://qmplusimg.henrongyi.top/gvalogo.jpg" width=300" height="300" />
<img src="http://qmplusimg.henrongyi.top/gvalogo.jpg" width="300" height="300" />
</div>
<div align=center>
<img src="https://img.shields.io/badge/golang-1.16-blue"/>
<img src="https://img.shields.io/badge/gin-1.6.3-lightBlue"/>
<img src="https://img.shields.io/badge/vue-3.0.0-brightgreen"/>
<img src="https://img.shields.io/badge/element--plus-1.1.0beta8-green"/>
<img src="https://img.shields.io/badge/gorm-1.20.7-red"/>
<img src="https://img.shields.io/badge/golang-1.20-blue"/>
<img src="https://img.shields.io/badge/gin-1.9.1-lightBlue"/>
<img src="https://img.shields.io/badge/vue-3.3.4-brightgreen"/>
<img src="https://img.shields.io/badge/element--plus-2.3.8-green"/>
<img src="https://img.shields.io/badge/gorm-1.25.2-red"/>
<img src="https://gitcode.com/flipped-aurora/gin-vue-admin/star/badge.svg"/>
</div>
<div align=center>
<a href="https://trendshift.io/repositories/3250" target="_blank"><img src="https://trendshift.io/api/badge/repositories/3250" alt="Calcium-Ion%2Fnew-api | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
</div>
[English](./README-en.md) | 简体中文
[gitee地址](https://gitee.com/pixelmax/gin-vue-admin): https://gitee.com/pixelmax/gin-vue-admin
## ✨一分钟生成前后端基础代码
[github地址](https://github.com/flipped-aurora/gin-vue-admin): https://github.com/flipped-aurora/gin-vue-admin
<table>
<tr>
<td width="250">
<p>⭐️ <a href="https://www.bilibili.com/video/BV1B3htzqEf1/?spm_id_from=333.1387.homepage.video_card.click" target="__blank"> 高度适配AI编辑器的MCP </a></p>
<p>📄 创建基础模板</p>
<p>🤖 AI生成结构</p>
<p>⏰ 生成代码</p>
<p>🏷️ 分配权限</p>
<p>🎉 基础CURD生成完成</p>
</td>
<td>
<video src="https://private-user-images.githubusercontent.com/165128580/384700666-4d039215-af29-4f86-bb4f-60dbab38f58e.mp4?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzEyNTIxNDYsIm5iZiI6MTczMTI1MTg0NiwicGF0aCI6Ii8xNjUxMjg1ODAvMzg0NzAwNjY2LTRkMDM5MjE1LWFmMjktNGY4Ni1iYjRmLTYwZGJhYjM4ZjU4ZS5tcDQ_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjQxMTEwJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI0MTExMFQxNTE3MjZaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT00NjJkMDcwZjJkMjAyMmU1N2I2MzQxY2RhODFlNzgzNGRiMDFhMmY2NTYyM2ZmODdhNDVmMWE1NzlhMDdlOTI5JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.ZJbswpLzF2RHjemcGirKOP0L1fvpl3FUqIiQ_-yjeUo" data-canonical-src="https://private-user-images.githubusercontent.com/165128580/384700666-4d039215-af29-4f86-bb4f-60dbab38f58e.mp4?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzEyNTIxNDYsIm5iZiI6MTczMTI1MTg0NiwicGF0aCI6Ii8xNjUxMjg1ODAvMzg0NzAwNjY2LTRkMDM5MjE1LWFmMjktNGY4Ni1iYjRmLTYwZGJhYjM4ZjU4ZS5tcDQ_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjQxMTEwJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI0MTExMFQxNTE3MjZaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT00NjJkMDcwZjJkMjAyMmU1N2I2MzQxY2RhODFlNzgzNGRiMDFhMmY2NTYyM2ZmODdhNDVmMWE1NzlhMDdlOTI5JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.ZJbswpLzF2RHjemcGirKOP0L1fvpl3FUqIiQ_-yjeUo" controls="controls" muted="muted" class="d-block rounded-bottom-2 border-top width-fit" style="max-height:640px; min-height: 200px">
</video>
</td>
</tr>
</table>
[插件仓库以及开发规范](https://github.com/flipped-aurora/gva-plugins):https://github.com/flipped-aurora/gva-plugins
[审批流分支](https://github.com/flipped-aurora/gin-vue-admin/tree/gva_workflow): https://github.com/flipped-aurora/gin-vue-admin/tree/gva_workflow
# 项目文档
[在线文档](https://www.gin-vue-admin.com) : https://www.gin-vue-admin.com
[初始化](https://www.gin-vue-admin.com/docs/first_master)
[初始化](https://www.gin-vue-admin.com/guide/start-quickly/initialization.html)
[从环境到部署教学视频](https://www.bilibili.com/video/BV1Rg411u7xH)
[开发教学](https://www.gin-vue-admin.com/docs/help) (贡献者: <a href="https://github.com/LLemonGreen">LLemonGreen</a> And <a href="https://github.com/fkk0509">Fann</a>)
[开发教学](https://www.gin-vue-admin.com/guide/start-quickly/env.html) (贡献者: <a href="https://github.com/LLemonGreen">LLemonGreen</a> And <a href="https://github.com/fkk0509">Fann</a>)
[交流社区](https://support.qq.com/products/371961)
[插件市场](https://plugin.gin-vue-admin.com/)
[软件著作权证书](https://www.gin-vue-admin.com/copyright.pdf)
# 重要提示
1.本项目从起步到开发到部署均有文档和详细视频教程
2.本项目需要您有一定的golang和vue基础
3.您完全可以通过我们的教程和文档完成一切操作,因此我们不再提供免费的技术服务,如需服务请进行[付费支持](https://www.gin-vue-admin.com/docs/payment)
3.您完全可以通过我们的教程和文档完成一切操作,因此我们不再提供免费的技术服务,如需服务请进行[付费支持](https://www.gin-vue-admin.com/coffee/payment.html)
4.如果您将此项目用于商业用途,请遵守Apache2.0协议并保留作者技术支持声明。您需保留如下版权声明信息,其余信息功能不做任何限制。如需剔除请联系微信:shouzi_1994
4.如果您将此项目用于商业用途,请遵守Apache2.0协议并保留作者技术支持声明。您需保留如下版权声明信息,以及日志和代码中所包含的版权声明信息。所需保留信息均为文案性质,不会影响任何业务内容,如决定商用【产生收益的商业行为均在商用行列】或者必须剔除请[购买授权](https://plugin.gin-vue-admin.com/licenseindex.html)
\
<img src="https://qmplusimg.henrongyi.top/openSource/login.jpg" width="1000">
<img src="https://qmplusimg.henrongyi.top/%E6%8E%88%E6%9D%83.png" width="1000">
5.如果您需要服务器的话 2C4G8M 80GB 腾讯云 一年74 三年222 在这里购买:https://curl.qcloud.com/sArxMfaw
<img src="https://qmplusimg.henrongyi.top/openSource/dashboard.jpg" width="1000">
## 1. 基本介绍
@@ -65,8 +87,8 @@ Gin-vue-admin 是一套为快速研发准备的一整套前后端分离架构式
Gin-vue-admin 的成长离不开大家的支持,如果你愿意为 gin-vue-admin 贡献代码或提供建议,请阅读以下内容。
#### 1.2.1 Issue 规范
- issue 仅用于提交 Bug 或 Feature 以及设计相关的内容,其它内容可能会被直接关闭。如果你在使用时产生了疑问,请到 Slack 或 [Gitter](https://gitter.im/ElemeFE/element) 里咨询。
- issue 仅用于提交 Bug 或 Feature 以及设计相关的内容,其它内容可能会被直接关闭。
- 在提交 issue 之前,请搜索相关内容是否已被提出。
#### 1.2.2 Pull Request 规范
@@ -74,8 +96,6 @@ Gin-vue-admin 的成长离不开大家的支持,如果你愿意为 gin-vue-adm
- commit 信息要以`[文件名]: 描述信息` 的形式填写,例如 `README.md: fix xxx bug`。
- <font color=red>确保 PR 是提交到 `develop` 分支,而不是 `master` 分支。</font>
- 如果是修复 bug,请在 PR 中给出描述信息。
- 合并代码需要两名维护人员参与:一人进行 review 后 approve,另一人再次 review,通过后即可合并。
@@ -83,11 +103,9 @@ Gin-vue-admin 的成长离不开大家的支持,如果你愿意为 gin-vue-adm
## 2. 使用说明
```
- node版本 > v12.18.3
- golang版本 >= v1.16
- node版本 > v18.16.0
- golang版本 >= v1.22
- IDE推荐:Goland
- 初始化项目: 不同版本数据库初始化不通 参见 https://www.gin-vue-admin.com/docs/first_master
- 替换掉项目中的七牛云公钥,私钥,仓名和默认url地址,以免发生测试文件数据错乱
```
### 2.1 server项目
@@ -104,11 +122,9 @@ cd server
# 使用 go mod 并安装go依赖包
go generate
# 编译
go build -o server main.go (windows编译命令为go build -o server.exe main.go )
# 运行
go run .
# 运行二进制
./server (windows运行命令为 server.exe)
```
### 2.2 web项目
@@ -118,7 +134,7 @@ go build -o server main.go (windows编译命令为go build -o server.exe main.go
cd web
# 安装依赖
cnpm install || npm install
npm install
# 启动web项目
npm run serve
@@ -128,29 +144,8 @@ npm run serve
#### 2.3.1 安装 swagger
##### (1)可以访问外国网站
````
go get -u github.com/swaggo/swag/cmd/swag
````
##### (2)无法访问外国网站
由于国内没法安装 go.org/x 包下面的东西,推荐使用 [goproxy.cn](https://goproxy.cn) 或者 [goproxy.io](https://goproxy.io/zh/)
```bash
# 如果您使用的 Go 版本是 1.13 - 1.15 需要手动设置GO111MODULE=on, 开启方式如下命令, 如果你的 Go 版本 是 1.16 ~ 最新版 可以忽略以下步骤一
# 步骤一、启用 Go Modules 功能
go env -w GO111MODULE=on
# 步骤二、配置 GOPROXY 环境变量
go env -w GOPROXY=https://goproxy.cn,https://goproxy.io,direct
# 如果嫌弃麻烦,可以使用go generate 编译前自动执行代码, 不过这个不能使用 `Goland` 或者 `Vscode` 的 命令行终端
cd server
go generate -run "go env -w .*?"
# 使用如下命令下载swag
go get -u github.com/swaggo/swag/cmd/swag
``` shell
go install github.com/swaggo/swag/cmd/swag@latest
```
#### 2.3.2 生成API文档
@@ -162,12 +157,30 @@ swag init
> 执行上面的命令后,server目录下会出现docs文件夹里的 `docs.go`, `swagger.json`, `swagger.yaml` 三个文件更新,启动go服务之后, 在浏览器输入 [http://localhost:8888/swagger/index.html](http://localhost:8888/swagger/index.html) 即可查看swagger文档
### 2.4 VSCode工作区
#### 2.4.1 开发
使用`VSCode`打开根目录下的工作区文件`gin-vue-admin.code-workspace`,在边栏可以看到三个虚拟目录:`backend`、`frontend`、`root`。
#### 2.4.2 运行/调试
在运行和调试中也可以看到三个task:`Backend`、`Frontend`、`Both (Backend & Frontend)`。运行`Both (Backend & Frontend)`可以同时启动前后端项目。
#### 2.4.3 settings
在工作区配置文件中有`go.toolsEnvVars`字段,是用于`VSCode`自身的go工具环境变量。此外在多go版本的系统中,可以通过`gopath`、`go.goroot`指定运行版本。
```json
"go.gopath": null,
"go.goroot": null,
```
## 3. 技术选型
- 前端:用基于 [Vue](https://vuejs.org) 的 [Element](https://github.com/ElemeFE/element) 构建基础页面。
- 后端:用 [Gin](https://gin-gonic.com/) 快速搭建基础restful风格API,[Gin](https://gin-gonic.com/) 是一个go语言编写的Web框架。
- 数据库:采用`MySql`(5.6.44)版本,使用 [gorm](http://gorm.cn) 实现对数据库的基本操作。
- 数据库:采用`MySql` > (5.7) 版本 数据库引擎 InnoDB,使用 [gorm](http://gorm.cn) 实现对数据库的基本操作。
- 缓存:使用`Redis`实现记录当前活跃用户的`jwt`令牌并实现多点登录限制。
- API文档:使用`Swagger`构建自动化文档。
- 配置文件:使用 [fsnotify](https://github.com/fsnotify/fsnotify) 和 [viper](https://github.com/spf13/viper) 实现`yaml`格式的配置文件。
@@ -211,17 +224,76 @@ swag init
├── timer (定时器接口封装)
└── upload (oss接口封装)
└─web (前端文件)
├─public (发布模板)
└─src (源码包)
├─api (向后台发送ajax的封装层)
├─assets (静态文件)
├─components(组件)
├─router (前端路由)
├─store (vuex 状态管理仓)
├─style (通用样式文件)
├─utils (前端工具库)
└─view (前端页面)
web
├── babel.config.js
├── Dockerfile
├── favicon.ico
├── index.html -- 主页面
├── limit.js -- 助手代码
├── package.json -- 包管理器代码
├── src -- 源代码
│ ├── api -- api 组
│ ├── App.vue -- 主页面
│ ├── assets -- 静态资源
│ ├── components -- 全局组件
│ ├── core -- gva 组件包
│ │ ├── config.js -- gva网站配置文件
│ │ ├── gin-vue-admin.js -- 注册欢迎文件
│ │ └── global.js -- 统一导入文件
│ ├── directive -- v-auth 注册文件
│ ├── main.js -- 主文件
│ ├── permission.js -- 路由中间件
│ ├── pinia -- pinia 状态管理器,取代vuex
│ │ ├── index.js -- 入口文件
│ │ └── modules -- modules
│ │ ├── dictionary.js
│ │ ├── router.js
│ │ └── user.js
│ ├── router -- 路由声明文件
│ │ └── index.js
│ ├── style -- 全局样式
│ │ ├── base.scss
│ │ ├── basics.scss
│ │ ├── element_visiable.scss -- 此处可以全局覆盖 element-plus 样式
│ │ ├── iconfont.css -- 顶部几个icon的样式文件
│ │ ├── main.scss
│ │ ├── mobile.scss
│ │ └── newLogin.scss
│ ├── utils -- 方法包库
│ │ ├── asyncRouter.js -- 动态路由相关
│ │ ├── btnAuth.js -- 动态权限按钮相关
│ │ ├── bus.js -- 全局mitt声明文件
│ │ ├── date.js -- 日期相关
│ │ ├── dictionary.js -- 获取字典方法
│ │ ├── downloadImg.js -- 下载图片方法
│ │ ├── format.js -- 格式整理相关
│ │ ├── image.js -- 图片相关方法
│ │ ├── page.js -- 设置页面标题
│ │ ├── request.js -- 请求
│ │ └── stringFun.js -- 字符串文件
| ├── view -- 主要view代码
| | ├── about -- 关于我们
| | ├── dashboard -- 面板
| | ├── error -- 错误
| | ├── example --上传案例
| | ├── iconList -- icon列表
| | ├── init -- 初始化数据
| | | ├── index -- 新版本
| | | ├── init -- 旧版本
| | ├── layout -- layout约束页面
| | | ├── aside
| | | ├── bottomInfo -- bottomInfo
| | | ├── screenfull -- 全屏设置
| | | ├── setting -- 系统设置
| | | └── index.vue -- base 约束
| | ├── login --登录
| | ├── person --个人中心
| | ├── superAdmin -- 超级管理员操作
| | ├── system -- 系统检测页面
| | ├── systemTools -- 系统配置相关页面
| | └── routerHolder.vue -- page 入口页面
├── vite.config.js -- vite 配置文件
└── yarn.lock
```
@@ -240,8 +312,8 @@ swag init
- 前端文件参考: [web/src/view/superAdmin/api/api.vue](https://github.com/flipped-aurora/gin-vue-admin/blob/master/web/src/view/superAdmin/api/api.vue)
- 后台文件参考: [server/router/sys_api.go](https://github.com/flipped-aurora/gin-vue-admin/blob/master/server/router/sys_api.go)
- 多点登录限制:需要在`config.yaml`中把`system`中的`use-multipoint`修改为true(需要自行配置Redis和Config中的Redis参数,测试阶段,有bug请及时反馈)。
- 分片长传:提供文件分片上传和大文件分片上传功能示例。
- 表单生成器:表单生成器借助 [@form-generator](https://github.com/JakHuang/form-generator) 。
- 分片上传:提供文件分片上传和大文件分片上传功能示例。
- 表单生成器:表单生成器借助 [@Variant Form](https://github.com/vform666/variant-form) 。
- 代码生成器:后台基础逻辑以及简单curd的代码生成器。
## 6. 知识库
@@ -272,38 +344,42 @@ swag init
(5)gin-vue-admin 版本更新介绍视频
> bilibili:https://space.bilibili.com/322210472/channel/detail?cid=126418&ctype=0
> bilibili:https://www.bilibili.com/video/BV1kv4y1g7nT
## 7. 联系方式
### 7.1 技术群
### QQ交流群:622360840
| QQ 群 |
| :---: |
| <img src="http://qmplusimg.henrongyi.top/qq.jpg" width="180"/> |
### QQ交流群:971857775
### 微信交流群
| 微信 |
| :---: |
| <img width="150" src="http://qmplusimg.henrongyi.top/qrjjz.png">
添加微信,备注"加入gin-vue-admin交流群"
防止广告进群,添加微信,输入以下代码执行结果(请勿转码为string)
### [关于我们](https://www.gin-vue-admin.com/about/)
```
str := "5Yqg5YWlR1ZB5Lqk5rWB576k"
decodeBytes, err := base64.StdEncoding.DecodeString(str)
fmt.Println(decodeBytes, err)
```
### [关于我们](https://www.gin-vue-admin.com/about/join.html)
## 8. 贡献者
感谢您对gin-vue-admin的贡献!
<a href="https://github.com/flipped-aurora/gin-vue-admin/graphs/contributors">
<img src="https://contrib.rocks/image?repo=flipped-aurora/gin-vue-admin" />
</a>
<a href="https://openomy.app/github/flipped-aurora/gin-vue-admin" target="_blank" style="display: block; width: 100%;" align="center">
<img src="https://openomy.app/svg?repo=flipped-aurora/gin-vue-admin&chart=bubble&latestMonth=3" target="_blank" alt="Contribution Leaderboard" style="display: block; width: 100%;" />
</a>
## 9. 捐赠
如果你觉得这个项目对你有帮助,你可以请作者喝饮料 :tropical_drink: [点我](https://www.gin-vue-admin.com/docs/coffee)
如果你觉得这个项目对你有帮助,你可以请作者喝饮料 :tropical_drink: [点我](https://www.gin-vue-admin.com/coffee/index.html)
## 10. 商用注意事项
## 10. 注意事项
如果您将此项目用于商业用途,请遵守Apache2.0协议并保留作者技术支持声明。
请严格遵守Apache 2.0协议并保留作品声明,去除版权信息请务必[获取授权](https://plugin.gin-vue-admin.com/license)
未授权去除版权信息将依法追究法律责任
@@ -1,16 +1,22 @@
version: "3"
# 声明一个名为network的networks,subnet为network的子网地址,默认网关是177.7.0.1
networks:
network:
ipam:
driver: default
config:
- subnet: '177.7.0.0/16'
# 设置mysql,redis持久化保存
volumes:
mysql:
redis:
services:
web:
build:
context: ./web
context: ../../web
dockerfile: ./Dockerfile
container_name: gva-web
restart: always
@@ -25,15 +31,17 @@ services:
server:
build:
context: ./server
context: ../../server
dockerfile: ./Dockerfile
container_name: gva-server
restart: always
ports:
- '8888:8888'
depends_on:
- mysql
- redis
mysql:
condition: service_healthy
redis:
condition: service_healthy
links:
- mysql
- redis
@@ -42,15 +50,24 @@ services:
ipv4_address: 177.7.0.12
mysql:
image: mysql:8.0.21
image: mysql:8.0.21 # 如果您是 arm64 架构:如 MacOS 的 M1,请修改镜像为 image: mysql/mysql-server:8.0.21
container_name: gva-mysql
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci #设置utf8字符集
restart: always
ports:
- "13306:3306" # host物理直接映射端口为13306
environment:
#MYSQL_ROOT_PASSWORD: 'Aa@6447985' # root管理员用户密码
MYSQL_DATABASE: 'qmPlus' # 初始化启动时要创建的数据库的名称
MYSQL_ROOT_PASSWORD: 'Aa@6447985' # root管理员用户密码
MYSQL_USER: 'gva'
MYSQL_PASSWORD: 'Aa@6447985'
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "gva", "-pAa@6447985"]
interval: 10s
timeout: 5s
retries: 3
volumes:
- mysql:/var/lib/mysql
networks:
network:
ipv4_address: 177.7.0.13
@@ -61,6 +78,13 @@ services:
restart: always
ports:
- '16379:6379'
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG || exit 1"]
interval: 10s
timeout: 5s
retries: 3
volumes:
- redis:/data
networks:
network:
ipv4_address: 177.7.0.14
ipv4_address: 177.7.0.14
+18
View File
@@ -0,0 +1,18 @@
FROM centos:7
WORKDIR /opt
ENV LANG=en_US.utf8
COPY deploy/docker/entrypoint.sh .
COPY build/ /usr/share/nginx/html/
COPY server/config.yaml /usr/share/nginx/html/config.yaml
COPY web/.docker-compose/nginx/conf.d/nginx.conf /etc/nginx/conf.d/nginx.conf
RUN set -ex \
&& echo "LANG=en_US.utf8" > /etc/locale.conf \
&& echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf \
&& echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf \
&& yum -y install epel-release \
&& yum -y localinstall http://mirrors.ustc.edu.cn/mysql-repo/mysql57-community-release-el7.rpm \
&& yum -y install mysql-community-server git redis nginx go npm --nogpgcheck && chmod +x ./entrypoint.sh \
&& npm install -g yarn && go env -w GO111MODULE=on && go env -w GOPROXY=https://goproxy.cn,direct \
&& echo "start" > /dev/null
EXPOSE 80
ENTRYPOINT ["./entrypoint.sh"]
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
if [ ! -d "/var/lib/mysql/gva" ]; then
mysqld --initialize-insecure --user=mysql --datadir=/var/lib/mysql
mysqld --daemonize --user=mysql
sleep 5s
mysql -uroot -e "create database gva default charset 'utf8' collate 'utf8_bin'; grant all on gva.* to 'root'@'127.0.0.1' identified by '123456'; flush privileges;"
else
mysqld --daemonize --user=mysql
fi
redis-server &
if [ "$1" = "actions" ]; then
cd /opt/gva/server && go run main.go &
cd /opt/gva/web/ && yarn serve &
else
/usr/sbin/nginx &
cd /usr/share/nginx/html/ && ./server &
fi
echo "gva ALL start!!!"
tail -f /dev/null
@@ -23,13 +23,13 @@ spec:
spec:
containers:
- name: gin-vue-admin-container
image: registry.cn-hangzhou.aliyuncs.com/gin-vue-admin/server:40fc3aa6
imagePullPolicy: IfNotPresent
image: registry.cn-hangzhou.aliyuncs.com/gva/server:latest
imagePullPolicy: Always
ports:
- containerPort: 8888
name: http
volumeMounts:
- mountPath: /go/src/github.com/flipped-aurora/gin-vue-admin/server/config.yaml
- mountPath: /go/src/github.com/flipped-aurora/gin-vue-admin/server/config.docker.yaml
name: config
subPath: config.yaml
- mountPath: /etc/localtime
@@ -41,22 +41,28 @@ spec:
requests:
cpu: 100m
memory: 200Mi
# readinessProbe:
# httpGet:
# path: /ready
# port: http
# initialDelaySeconds: 20
# periodSeconds: 10
# successThreshold: 1
# failureThreshold: 3
# livenessProbe:
# httpGet:
# path: /health
# port: http
# initialDelaySeconds: 20
# periodSeconds: 10
# successThreshold: 1
# failureThreshold: 3
livenessProbe:
failureThreshold: 1
periodSeconds: 5
successThreshold: 1
tcpSocket:
port: 8888
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 30
periodSeconds: 5
successThreshold: 1
tcpSocket:
port: 8888
timeoutSeconds: 1
startupProbe:
failureThreshold: 40
periodSeconds: 5
successThreshold: 1
tcpSocket:
port: 8888
timeoutSeconds: 1
#imagePullSecrets:
# - name: docker-registry
volumes:
@@ -23,8 +23,8 @@ spec:
spec:
containers:
- name: gin-vue-admin-nginx-container
image: registry.cn-hangzhou.aliyuncs.com/gin-vue-admin/web:40fc3aa6
imagePullPolicy: IfNotPresent
image: registry.cn-hangzhou.aliyuncs.com/gva/web:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
@@ -0,0 +1,18 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gva-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: demo.gin-vue-admin.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gva-web
port:
number: 8080
@@ -10,8 +10,8 @@ metadata:
app: gva-web
version: gva-vue3
spec:
type: NodePort
# type: ClusterIP
# type: NodePort
type: ClusterIP
ports:
- name: http
port: 8080
+49
View File
@@ -0,0 +1,49 @@
{
"folders": [
{
"path": "server",
"name": "backend"
},
{
"path": "web",
"name": "frontend"
},
{
"path": ".",
"name": "root"
}
],
"settings": {
"go.toolsEnvVars": {
"GOPROXY": "https://goproxy.cn,direct",
"GONOPROXY": "none;"
}
},
"launch": {
"version": "0.2.0",
"configurations": [
{
"type": "go",
"request": "launch",
"name": "Backend",
"cwd": "${workspaceFolder:backend}",
"program": "${workspaceFolder:backend}/"
},
{
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder:frontend}",
"name": "Frontend",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "serve"]
}
],
"compounds": [
{
"name": "Both (Backend & Frontend)",
"configurations": ["Backend", "Frontend"],
"stopAll": true
}
]
}
}
+17 -8
View File
@@ -3,20 +3,29 @@ FROM golang:alpine as builder
WORKDIR /go/src/github.com/flipped-aurora/gin-vue-admin/server
COPY . .
RUN go env -w GO111MODULE=on
RUN go env -w GOPROXY=https://goproxy.cn,direct
RUN go env -w CGO_ENABLED=0
RUN go env
RUN go mod tidy
RUN go build -o server .
RUN go env -w GO111MODULE=on \
&& go env -w GOPROXY=https://goproxy.cn,direct \
&& go env -w CGO_ENABLED=0 \
&& go env \
&& go mod tidy \
&& go build -o server .
FROM alpine:latest
LABEL MAINTAINER="SliverHorn@sliver_horn@qq.com"
# 设置时区
ENV TZ=Asia/Shanghai
RUN apk update && apk add --no-cache tzdata openntpd \
&& ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /go/src/github.com/flipped-aurora/gin-vue-admin/server
COPY --from=0 /go/src/github.com/flipped-aurora/gin-vue-admin/server ./
COPY --from=0 /go/src/github.com/flipped-aurora/gin-vue-admin/server/server ./
COPY --from=0 /go/src/github.com/flipped-aurora/gin-vue-admin/server/resource ./resource/
COPY --from=0 /go/src/github.com/flipped-aurora/gin-vue-admin/server/config.docker.yaml ./
# 挂载目录:如果使用了sqlite数据库,容器命令示例:docker run -d -v /宿主机路径/gva.db:/go/src/github.com/flipped-aurora/gin-vue-admin/server/gva.db -p 8888:8888 --name gva-server-v1 gva-server:1.0
# VOLUME ["/go/src/github.com/flipped-aurora/gin-vue-admin/server"]
EXPOSE 8888
ENTRYPOINT ./server -c config.docker.yaml
-120
View File
@@ -1,120 +0,0 @@
package autocode
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/autocode"
autocodeReq "github.com/flipped-aurora/gin-vue-admin/server/model/autocode/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/service"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type AutoCodeExampleApi struct{}
var autoCodeExampleService = service.ServiceGroupApp.AutoCodeServiceGroup.AutoCodeExampleService
// @Tags AutoCodeExample
// @Summary 创建AutoCodeExample
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body autocode.AutoCodeExample true "AutoCodeExample模型"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCodeExample/createAutoCodeExample [post]
func (autoCodeExampleApi *AutoCodeExampleApi) CreateAutoCodeExample(c *gin.Context) {
var autoCodeExample autocode.AutoCodeExample
_ = c.ShouldBindJSON(&autoCodeExample)
if err := autoCodeExampleService.CreateAutoCodeExample(autoCodeExample); err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
} else {
response.OkWithMessage("创建成功", c)
}
}
// @Tags AutoCodeExample
// @Summary 删除AutoCodeExample
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body autocode.AutoCodeExample true "AutoCodeExample模型"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /autoCodeExample/deleteAutoCodeExample [delete]
func (autoCodeExampleApi *AutoCodeExampleApi) DeleteAutoCodeExample(c *gin.Context) {
var autoCodeExample autocode.AutoCodeExample
_ = c.ShouldBindJSON(&autoCodeExample)
if err := autoCodeExampleService.DeleteAutoCodeExample(autoCodeExample); err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
}
}
// @Tags AutoCodeExample
// @Summary 更新AutoCodeExample
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body autocode.AutoCodeExample true "更新AutoCodeExample"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /autoCodeExample/updateAutoCodeExample [put]
func (autoCodeExampleApi *AutoCodeExampleApi) UpdateAutoCodeExample(c *gin.Context) {
var autoCodeExample autocode.AutoCodeExample
_ = c.ShouldBindJSON(&autoCodeExample)
if err := autoCodeExampleService.UpdateAutoCodeExample(&autoCodeExample); err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败", c)
} else {
response.OkWithMessage("更新成功", c)
}
}
// @Tags AutoCodeExample
// @Summary 用id查询AutoCodeExample
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query autocode.AutoCodeExample true "用id查询AutoCodeExample"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /autoCodeExample/findAutoCodeExample [get]
func (autoCodeExampleApi *AutoCodeExampleApi) FindAutoCodeExample(c *gin.Context) {
var autoCodeExample autocode.AutoCodeExample
_ = c.ShouldBindQuery(&autoCodeExample)
if err := utils.Verify(autoCodeExample, utils.IdVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, reAutoCodeExample := autoCodeExampleService.GetAutoCodeExample(autoCodeExample.ID); err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败", c)
} else {
response.OkWithDetailed(gin.H{"reAutoCodeExample": reAutoCodeExample}, "查询成功", c)
}
}
// @Tags AutoCodeExample
// @Summary 分页获取AutoCodeExample列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query autocodeReq.AutoCodeExampleSearch true "页码, 每页大小, 搜索条件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /autoCodeExample/getAutoCodeExampleList [get]
func (autoCodeExampleApi *AutoCodeExampleApi) GetAutoCodeExampleList(c *gin.Context) {
var pageInfo autocodeReq.AutoCodeExampleSearch
_ = c.ShouldBindQuery(&pageInfo)
if err, list, total := autoCodeExampleService.GetAutoCodeExampleInfoList(pageInfo); err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
}
-7
View File
@@ -1,7 +0,0 @@
package autocode
type ApiGroup struct {
// Code generated by github.com/flipped-aurora/gin-vue-admin/server Begin; DO NOT EDIT.
AutoCodeExampleApi
// Code generated by github.com/flipped-aurora/gin-vue-admin/server End; DO NOT EDIT.
}
+5 -7
View File
@@ -1,15 +1,13 @@
package v1
import (
"github.com/flipped-aurora/gin-vue-admin/server/api/v1/autocode"
"github.com/flipped-aurora/gin-vue-admin/server/api/v1/example"
"github.com/flipped-aurora/gin-vue-admin/server/api/v1/system"
)
type ApiGroup struct {
SystemApiGroup system.ApiGroup
ExampleApiGroup example.ApiGroup
AutoCodeApiGroup autocode.ApiGroup
}
var ApiGroupApp = new(ApiGroup)
type ApiGroup struct {
SystemApiGroup system.ApiGroup
ExampleApiGroup example.ApiGroup
}
+2 -2
View File
@@ -3,13 +3,13 @@ package example
import "github.com/flipped-aurora/gin-vue-admin/server/service"
type ApiGroup struct {
ExcelApi
CustomerApi
FileUploadAndDownloadApi
AttachmentCategoryApi
}
var (
excelService = service.ServiceGroupApp.ExampleServiceGroup.ExcelService
customerService = service.ServiceGroupApp.ExampleServiceGroup.CustomerService
fileUploadAndDownloadService = service.ServiceGroupApp.ExampleServiceGroup.FileUploadAndDownloadService
attachmentCategoryService = service.ServiceGroupApp.ExampleServiceGroup.AttachmentCategoryService
)
@@ -0,0 +1,82 @@
package example
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
common "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/example"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type AttachmentCategoryApi struct{}
// GetCategoryList
// @Tags GetCategoryList
// @Summary 媒体库分类列表
// @Security AttachmentCategory
// @Produce application/json
// @Success 200 {object} response.Response{data=example.ExaAttachmentCategory,msg=string} "媒体库分类列表"
// @Router /attachmentCategory/getCategoryList [get]
func (a *AttachmentCategoryApi) GetCategoryList(c *gin.Context) {
res, err := attachmentCategoryService.GetCategoryList()
if err != nil {
global.GVA_LOG.Error("获取分类列表失败!", zap.Error(err))
response.FailWithMessage("获取分类列表失败", c)
return
}
response.OkWithData(res, c)
}
// AddCategory
// @Tags AddCategory
// @Summary 添加媒体库分类
// @Security AttachmentCategory
// @accept application/json
// @Produce application/json
// @Param data body example.ExaAttachmentCategory true "媒体库分类数据"// @Success 200 {object} response.Response{msg=string} "添加媒体库分类"
// @Router /attachmentCategory/addCategory [post]
func (a *AttachmentCategoryApi) AddCategory(c *gin.Context) {
var req example.ExaAttachmentCategory
if err := c.ShouldBindJSON(&req); err != nil {
global.GVA_LOG.Error("参数错误!", zap.Error(err))
response.FailWithMessage("参数错误", c)
return
}
if err := attachmentCategoryService.AddCategory(&req); err != nil {
global.GVA_LOG.Error("创建/更新失败!", zap.Error(err))
response.FailWithMessage("创建/更新失败:"+err.Error(), c)
return
}
response.OkWithMessage("创建/更新成功", c)
}
// DeleteCategory
// @Tags DeleteCategory
// @Summary 删除分类
// @Security AttachmentCategory
// @accept application/json
// @Produce application/json
// @Param data body common.GetById true "分类id"
// @Success 200 {object} response.Response{msg=string} "删除分类"
// @Router /attachmentCategory/deleteCategory [post]
func (a *AttachmentCategoryApi) DeleteCategory(c *gin.Context) {
var req common.GetById
if err := c.ShouldBindJSON(&req); err != nil {
response.FailWithMessage("参数错误", c)
return
}
if req.ID == 0 {
response.FailWithMessage("参数错误", c)
return
}
if err := attachmentCategoryService.DeleteCategory(&req.ID); err != nil {
response.FailWithMessage("删除失败", c)
return
}
response.OkWithMessage("删除成功", c)
}
@@ -2,9 +2,12 @@ package example
import (
"fmt"
"io/ioutil"
"io"
"mime/multipart"
"strconv"
"strings"
"github.com/flipped-aurora/gin-vue-admin/server/model/example"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
@@ -14,15 +17,16 @@ import (
"go.uber.org/zap"
)
// @Tags ExaFileUploadAndDownload
// @Summary 断点续传到服务器
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "an example for breakpoint resume, 断点续传示例"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"切片创建成功"}"
// @Router /fileUploadAndDownload/breakpointContinue [post]
func (u *FileUploadAndDownloadApi) BreakpointContinue(c *gin.Context) {
// BreakpointContinue
// @Tags ExaFileUploadAndDownload
// @Summary 断点续传到服务器
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "an example for breakpoint resume, 断点续传示例"
// @Success 200 {object} response.Response{msg=string} "断点续传到服务器"
// @Router /fileUploadAndDownload/breakpointContinue [post]
func (b *FileUploadAndDownloadApi) BreakpointContinue(c *gin.Context) {
fileMd5 := c.Request.FormValue("fileMd5")
fileName := c.Request.FormValue("fileName")
chunkMd5 := c.Request.FormValue("chunkMd5")
@@ -46,26 +50,26 @@ func (u *FileUploadAndDownloadApi) BreakpointContinue(c *gin.Context) {
fmt.Println(err)
}
}(f)
cen, _ := ioutil.ReadAll(f)
cen, _ := io.ReadAll(f)
if !utils.CheckMd5(cen, chunkMd5) {
global.GVA_LOG.Error("检查md5失败!", zap.Error(err))
response.FailWithMessage("检查md5失败", c)
return
}
err, file := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal)
file, err := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal)
if err != nil {
global.GVA_LOG.Error("查找或创建记录失败!", zap.Error(err))
response.FailWithMessage("查找或创建记录失败", c)
return
}
err, pathc := utils.BreakPointContinue(cen, fileName, chunkNumber, chunkTotal, fileMd5)
pathC, err := utils.BreakPointContinue(cen, fileName, chunkNumber, chunkTotal, fileMd5)
if err != nil {
global.GVA_LOG.Error("断点续传失败!", zap.Error(err))
response.FailWithMessage("断点续传失败", c)
return
}
if err = fileUploadAndDownloadService.CreateFileChunk(file.ID, pathc, chunkNumber); err != nil {
if err = fileUploadAndDownloadService.CreateFileChunk(file.ID, pathC, chunkNumber); err != nil {
global.GVA_LOG.Error("创建文件记录失败!", zap.Error(err))
response.FailWithMessage("创建文件记录失败", c)
return
@@ -73,19 +77,20 @@ func (u *FileUploadAndDownloadApi) BreakpointContinue(c *gin.Context) {
response.OkWithMessage("切片创建成功", c)
}
// @Tags ExaFileUploadAndDownload
// @Summary 查找文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "Find the file, 查找文件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查找成功"}"
// @Router /fileUploadAndDownload/findFile [post]
func (u *FileUploadAndDownloadApi) FindFile(c *gin.Context) {
// FindFile
// @Tags ExaFileUploadAndDownload
// @Summary 查找文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "Find the file, 查找文件"
// @Success 200 {object} response.Response{data=exampleRes.FileResponse,msg=string} "查找文件,返回包括文件详情"
// @Router /fileUploadAndDownload/findFile [get]
func (b *FileUploadAndDownloadApi) FindFile(c *gin.Context) {
fileMd5 := c.Query("fileMd5")
fileName := c.Query("fileName")
chunkTotal, _ := strconv.Atoi(c.Query("chunkTotal"))
err, file := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal)
file, err := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal)
if err != nil {
global.GVA_LOG.Error("查找失败!", zap.Error(err))
response.FailWithMessage("查找失败", c)
@@ -94,18 +99,19 @@ func (u *FileUploadAndDownloadApi) FindFile(c *gin.Context) {
}
}
// @Tags ExaFileUploadAndDownload
// @Summary 创建文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "上传文件完成"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"file uploaded, 文件创建成功"}"
// @Router /fileUploadAndDownload/findFile [post]
// BreakpointContinueFinish
// @Tags ExaFileUploadAndDownload
// @Summary 创建文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "上传文件完成"
// @Success 200 {object} response.Response{data=exampleRes.FilePathResponse,msg=string} "创建文件,返回包括文件路径"
// @Router /fileUploadAndDownload/findFile [post]
func (b *FileUploadAndDownloadApi) BreakpointContinueFinish(c *gin.Context) {
fileMd5 := c.Query("fileMd5")
fileName := c.Query("fileName")
err, filePath := utils.MakeFile(fileName, fileMd5)
filePath, err := utils.MakeFile(fileName, fileMd5)
if err != nil {
global.GVA_LOG.Error("文件创建失败!", zap.Error(err))
response.FailWithDetailed(exampleRes.FilePathResponse{FilePath: filePath}, "文件创建失败", c)
@@ -114,27 +120,37 @@ func (b *FileUploadAndDownloadApi) BreakpointContinueFinish(c *gin.Context) {
}
}
// @Tags ExaFileUploadAndDownload
// @Summary 删除切片
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "删除缓存切片"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"缓存切片删除成功"}"
// @Router /fileUploadAndDownload/removeChunk [post]
func (u *FileUploadAndDownloadApi) RemoveChunk(c *gin.Context) {
fileMd5 := c.Query("fileMd5")
fileName := c.Query("fileName")
filePath := c.Query("filePath")
err := utils.RemoveChunk(fileMd5)
// RemoveChunk
// @Tags ExaFileUploadAndDownload
// @Summary 删除切片
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "删除缓存切片"
// @Success 200 {object} response.Response{msg=string} "删除切片"
// @Router /fileUploadAndDownload/removeChunk [post]
func (b *FileUploadAndDownloadApi) RemoveChunk(c *gin.Context) {
var file example.ExaFile
err := c.ShouldBindJSON(&file)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = fileUploadAndDownloadService.DeleteFileChunk(fileMd5, fileName, filePath)
// 路径穿越拦截
if strings.Contains(file.FilePath, "..") || strings.Contains(file.FilePath, "../") || strings.Contains(file.FilePath, "./") || strings.Contains(file.FilePath, ".\\") {
response.FailWithMessage("非法路径,禁止删除", c)
return
}
err = utils.RemoveChunk(file.FileMd5)
if err != nil {
global.GVA_LOG.Error("缓存切片删除失败!", zap.Error(err))
response.FailWithDetailed(exampleRes.FilePathResponse{FilePath: filePath}, "缓存切片删除失败", c)
} else {
response.OkWithDetailed(exampleRes.FilePathResponse{FilePath: filePath}, "缓存切片删除成功", c)
return
}
err = fileUploadAndDownloadService.DeleteFileChunk(file.FileMd5, file.FilePath)
if err != nil {
global.GVA_LOG.Error(err.Error(), zap.Error(err))
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithMessage("缓存切片删除成功", c)
}
+105 -71
View File
@@ -13,130 +13,164 @@ import (
type CustomerApi struct{}
// @Tags ExaCustomer
// @Summary 创建客户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body example.ExaCustomer true "客户用户名, 客户手机号码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /customer/customer [post]
// CreateExaCustomer
// @Tags ExaCustomer
// @Summary 创建客户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body example.ExaCustomer true "客户用户名, 客户手机号码"
// @Success 200 {object} response.Response{msg=string} "创建客户"
// @Router /customer/customer [post]
func (e *CustomerApi) CreateExaCustomer(c *gin.Context) {
var customer example.ExaCustomer
_ = c.ShouldBindJSON(&customer)
if err := utils.Verify(customer, utils.CustomerVerify); err != nil {
err := c.ShouldBindJSON(&customer)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(customer, utils.CustomerVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
customer.SysUserID = utils.GetUserID(c)
customer.SysUserAuthorityID = utils.GetUserAuthorityId(c)
if err := customerService.CreateExaCustomer(customer); err != nil {
err = customerService.CreateExaCustomer(customer)
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
} else {
response.OkWithMessage("创建成功", c)
return
}
response.OkWithMessage("创建成功", c)
}
// @Tags ExaCustomer
// @Summary 删除客户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body example.ExaCustomer true "客户ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /customer/customer [delete]
// DeleteExaCustomer
// @Tags ExaCustomer
// @Summary 删除客户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body example.ExaCustomer true "客户ID"
// @Success 200 {object} response.Response{msg=string} "删除客户"
// @Router /customer/customer [delete]
func (e *CustomerApi) DeleteExaCustomer(c *gin.Context) {
var customer example.ExaCustomer
_ = c.ShouldBindJSON(&customer)
if err := utils.Verify(customer.GVA_MODEL, utils.IdVerify); err != nil {
err := c.ShouldBindJSON(&customer)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := customerService.DeleteExaCustomer(customer); err != nil {
err = utils.Verify(customer.GVA_MODEL, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = customerService.DeleteExaCustomer(customer)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
return
}
response.OkWithMessage("删除成功", c)
}
// @Tags ExaCustomer
// @Summary 更新客户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body example.ExaCustomer true "客户ID, 客户信息"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /customer/customer [put]
// UpdateExaCustomer
// @Tags ExaCustomer
// @Summary 更新客户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body example.ExaCustomer true "客户ID, 客户信息"
// @Success 200 {object} response.Response{msg=string} "更新客户信息"
// @Router /customer/customer [put]
func (e *CustomerApi) UpdateExaCustomer(c *gin.Context) {
var customer example.ExaCustomer
_ = c.ShouldBindJSON(&customer)
if err := utils.Verify(customer.GVA_MODEL, utils.IdVerify); err != nil {
err := c.ShouldBindJSON(&customer)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := utils.Verify(customer, utils.CustomerVerify); err != nil {
err = utils.Verify(customer.GVA_MODEL, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := customerService.UpdateExaCustomer(&customer); err != nil {
err = utils.Verify(customer, utils.CustomerVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = customerService.UpdateExaCustomer(&customer)
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败", c)
} else {
response.OkWithMessage("更新成功", c)
return
}
response.OkWithMessage("更新成功", c)
}
// @Tags ExaCustomer
// @Summary 获取单一客户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query example.ExaCustomer true "客户ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /customer/customer [get]
// GetExaCustomer
// @Tags ExaCustomer
// @Summary 获取单一客户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query example.ExaCustomer true "客户ID"
// @Success 200 {object} response.Response{data=exampleRes.ExaCustomerResponse,msg=string} "获取单一客户信息,返回包括客户详情"
// @Router /customer/customer [get]
func (e *CustomerApi) GetExaCustomer(c *gin.Context) {
var customer example.ExaCustomer
_ = c.ShouldBindQuery(&customer)
if err := utils.Verify(customer.GVA_MODEL, utils.IdVerify); err != nil {
err := c.ShouldBindQuery(&customer)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err, data := customerService.GetExaCustomer(customer.ID)
err = utils.Verify(customer.GVA_MODEL, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
data, err := customerService.GetExaCustomer(customer.ID)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(exampleRes.ExaCustomerResponse{Customer: data}, "获取成功", c)
return
}
response.OkWithDetailed(exampleRes.ExaCustomerResponse{Customer: data}, "获取成功", c)
}
// @Tags ExaCustomer
// @Summary 分页获取权限客户列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.PageInfo true "页码, 每页大小"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /customer/customerList [get]
// GetExaCustomerList
// @Tags ExaCustomer
// @Summary 分页获取权限客户列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.PageInfo true "页码, 每页大小"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取权限客户列表,返回包括列表,总数,页码,每页数量"
// @Router /customer/customerList [get]
func (e *CustomerApi) GetExaCustomerList(c *gin.Context) {
var pageInfo request.PageInfo
_ = c.ShouldBindQuery(&pageInfo)
if err := utils.Verify(pageInfo, utils.PageInfoVerify); err != nil {
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err, customerList, total := customerService.GetCustomerInfoList(utils.GetUserAuthorityId(c), pageInfo)
err = utils.Verify(pageInfo, utils.PageInfoVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
customerList, total, err := customerService.GetCustomerInfoList(utils.GetUserAuthorityId(c), pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败"+err.Error(), c)
} else {
response.OkWithDetailed(response.PageResult{
List: customerList,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
return
}
response.OkWithDetailed(response.PageResult{
List: customerList,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
-100
View File
@@ -1,100 +0,0 @@
package example
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/example"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type ExcelApi struct{}
// /excel/importExcel 接口,与upload接口作用类似,只是把文件存到resource/excel目录下,用于导入Excel时存放Excel文件(ExcelImport.xlsx)
// /excel/loadExcel接口,用于读取resource/excel目录下的文件((ExcelImport.xlsx)并加载为[]model.SysBaseMenu类型的示例数据
// /excel/exportExcel 接口,用于读取前端传来的tableData,生成Excel文件并返回
// /excel/downloadTemplate 接口,用于下载resource/excel目录下的 ExcelTemplate.xlsx 文件,作为导入的模板
// @Tags excel
// @Summary 导出Excel
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/octet-stream
// @Param data body example.ExcelInfo true "导出Excel文件信息"
// @Success 200
// @Router /excel/exportExcel [post]
func (e *ExcelApi) ExportExcel(c *gin.Context) {
var excelInfo example.ExcelInfo
_ = c.ShouldBindJSON(&excelInfo)
filePath := global.GVA_CONFIG.Excel.Dir + excelInfo.FileName
err := excelService.ParseInfoList2Excel(excelInfo.InfoList, filePath)
if err != nil {
global.GVA_LOG.Error("转换Excel失败!", zap.Error(err))
response.FailWithMessage("转换Excel失败", c)
return
}
c.Writer.Header().Add("success", "true")
c.File(filePath)
}
// @Tags excel
// @Summary 导入Excel文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "导入Excel文件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"导入成功"}"
// @Router /excel/importExcel [post]
func (e *ExcelApi) ImportExcel(c *gin.Context) {
_, header, err := c.Request.FormFile("file")
if err != nil {
global.GVA_LOG.Error("接收文件失败!", zap.Error(err))
response.FailWithMessage("接收文件失败", c)
return
}
_ = c.SaveUploadedFile(header, global.GVA_CONFIG.Excel.Dir+"ExcelImport.xlsx")
response.OkWithMessage("导入成功", c)
}
// @Tags excel
// @Summary 加载Excel数据
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"加载数据成功"}"
// @Router /excel/loadExcel [get]
func (e *ExcelApi) LoadExcel(c *gin.Context) {
menus, err := excelService.ParseExcel2InfoList()
if err != nil {
global.GVA_LOG.Error("加载数据失败!", zap.Error(err))
response.FailWithMessage("加载数据失败", c)
return
}
response.OkWithDetailed(response.PageResult{
List: menus,
Total: int64(len(menus)),
Page: 1,
PageSize: 999,
}, "加载数据成功", c)
}
// @Tags excel
// @Summary 下载模板
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param fileName query string true "模板名称"
// @Success 200
// @Router /excel/downloadTemplate [get]
func (e *ExcelApi) DownloadTemplate(c *gin.Context) {
fileName := c.Query("fileName")
filePath := global.GVA_CONFIG.Excel.Dir + fileName
ok, err := utils.PathExists(filePath)
if !ok || err != nil {
global.GVA_LOG.Error("文件不存在!", zap.Error(err))
response.FailWithMessage("文件不存在", c)
return
}
c.Writer.Header().Add("success", "true")
c.File(filePath)
}
@@ -2,52 +2,77 @@ package example
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/example"
"github.com/flipped-aurora/gin-vue-admin/server/model/example/request"
exampleRes "github.com/flipped-aurora/gin-vue-admin/server/model/example/response"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"strconv"
)
type FileUploadAndDownloadApi struct{}
// @Tags ExaFileUploadAndDownload
// @Summary 上传文件示例
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "上传文件示例"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"上传成功"}"
// @Router /fileUploadAndDownload/upload [post]
func (u *FileUploadAndDownloadApi) UploadFile(c *gin.Context) {
// UploadFile
// @Tags ExaFileUploadAndDownload
// @Summary 上传文件示例
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "上传文件示例"
// @Success 200 {object} response.Response{data=exampleRes.ExaFileResponse,msg=string} "上传文件示例,返回包括文件详情"
// @Router /fileUploadAndDownload/upload [post]
func (b *FileUploadAndDownloadApi) UploadFile(c *gin.Context) {
var file example.ExaFileUploadAndDownload
noSave := c.DefaultQuery("noSave", "0")
_, header, err := c.Request.FormFile("file")
classId, _ := strconv.Atoi(c.DefaultPostForm("classId", "0"))
if err != nil {
global.GVA_LOG.Error("接收文件失败!", zap.Error(err))
response.FailWithMessage("接收文件失败", c)
return
}
err, file = fileUploadAndDownloadService.UploadFile(header, noSave) // 文件上传后拿到文件路径
file, err = fileUploadAndDownloadService.UploadFile(header, noSave, classId) // 文件上传后拿到文件路径
if err != nil {
global.GVA_LOG.Error("修改数据库链接失败!", zap.Error(err))
response.FailWithMessage("修改数据库链接失败", c)
global.GVA_LOG.Error("上传文件失败!", zap.Error(err))
response.FailWithMessage("上传文件失败", c)
return
}
response.OkWithDetailed(exampleRes.ExaFileResponse{File: file}, "上传成功", c)
}
// @Tags ExaFileUploadAndDownload
// @Summary 删除文件
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body example.ExaFileUploadAndDownload true "传入文件里面id即可"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /fileUploadAndDownload/deleteFile [post]
func (u *FileUploadAndDownloadApi) DeleteFile(c *gin.Context) {
// EditFileName 编辑文件名或者备注
func (b *FileUploadAndDownloadApi) EditFileName(c *gin.Context) {
var file example.ExaFileUploadAndDownload
_ = c.ShouldBindJSON(&file)
err := c.ShouldBindJSON(&file)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = fileUploadAndDownloadService.EditFileName(file)
if err != nil {
global.GVA_LOG.Error("编辑失败!", zap.Error(err))
response.FailWithMessage("编辑失败", c)
return
}
response.OkWithMessage("编辑成功", c)
}
// DeleteFile
// @Tags ExaFileUploadAndDownload
// @Summary 删除文件
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body example.ExaFileUploadAndDownload true "传入文件里面id即可"
// @Success 200 {object} response.Response{msg=string} "删除文件"
// @Router /fileUploadAndDownload/deleteFile [post]
func (b *FileUploadAndDownloadApi) DeleteFile(c *gin.Context) {
var file example.ExaFileUploadAndDownload
err := c.ShouldBindJSON(&file)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := fileUploadAndDownloadService.DeleteFile(file); err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
@@ -56,27 +81,55 @@ func (u *FileUploadAndDownloadApi) DeleteFile(c *gin.Context) {
response.OkWithMessage("删除成功", c)
}
// @Tags ExaFileUploadAndDownload
// @Summary 分页文件列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "页码, 每页大小"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /fileUploadAndDownload/getFileList [post]
func (u *FileUploadAndDownloadApi) GetFileList(c *gin.Context) {
var pageInfo request.PageInfo
_ = c.ShouldBindJSON(&pageInfo)
err, list, total := fileUploadAndDownloadService.GetFileRecordInfoList(pageInfo)
// GetFileList
// @Tags ExaFileUploadAndDownload
// @Summary 分页文件列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.ExaAttachmentCategorySearch true "页码, 每页大小, 分类id"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页文件列表,返回包括列表,总数,页码,每页数量"
// @Router /fileUploadAndDownload/getFileList [post]
func (b *FileUploadAndDownloadApi) GetFileList(c *gin.Context) {
var pageInfo request.ExaAttachmentCategorySearch
err := c.ShouldBindJSON(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := fileUploadAndDownloadService.GetFileRecordInfoList(pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
// ImportURL
// @Tags ExaFileUploadAndDownload
// @Summary 导入URL
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body example.ExaFileUploadAndDownload true "对象"
// @Success 200 {object} response.Response{msg=string} "导入URL"
// @Router /fileUploadAndDownload/importURL [post]
func (b *FileUploadAndDownloadApi) ImportURL(c *gin.Context) {
var file []example.ExaFileUploadAndDownload
err := c.ShouldBindJSON(&file)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := fileUploadAndDownloadService.ImportURL(&file); err != nil {
global.GVA_LOG.Error("导入URL失败!", zap.Error(err))
response.FailWithMessage("导入URL失败", c)
return
}
response.OkWithMessage("导入URL成功", c)
}
+115
View File
@@ -0,0 +1,115 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
common "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
request "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type AutoCodeHistoryApi struct{}
// First
// @Tags AutoCode
// @Summary 获取meta信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "请求参数"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取meta信息"
// @Router /autoCode/getMeta [post]
func (a *AutoCodeHistoryApi) First(c *gin.Context) {
var info common.GetById
err := c.ShouldBindJSON(&info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
data, err := autoCodeHistoryService.First(c.Request.Context(), info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithDetailed(gin.H{"meta": data}, "获取成功", c)
}
// Delete
// @Tags AutoCode
// @Summary 删除回滚记录
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "请求参数"
// @Success 200 {object} response.Response{msg=string} "删除回滚记录"
// @Router /autoCode/delSysHistory [post]
func (a *AutoCodeHistoryApi) Delete(c *gin.Context) {
var info common.GetById
err := c.ShouldBindJSON(&info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = autoCodeHistoryService.Delete(c.Request.Context(), info)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
return
}
response.OkWithMessage("删除成功", c)
}
// RollBack
// @Tags AutoCode
// @Summary 回滚自动生成代码
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.SysAutoHistoryRollBack true "请求参数"
// @Success 200 {object} response.Response{msg=string} "回滚自动生成代码"
// @Router /autoCode/rollback [post]
func (a *AutoCodeHistoryApi) RollBack(c *gin.Context) {
var info request.SysAutoHistoryRollBack
err := c.ShouldBindJSON(&info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = autoCodeHistoryService.RollBack(c.Request.Context(), info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithMessage("回滚成功", c)
}
// GetList
// @Tags AutoCode
// @Summary 查询回滚记录
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body common.PageInfo true "请求参数"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "查询回滚记录,返回包括列表,总数,页码,每页数量"
// @Router /autoCode/getSysHistory [post]
func (a *AutoCodeHistoryApi) GetList(c *gin.Context) {
var info common.PageInfo
err := c.ShouldBindJSON(&info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := autoCodeHistoryService.GetList(c.Request.Context(), info)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: info.Page,
PageSize: info.PageSize,
}, "获取成功", c)
}
+144
View File
@@ -0,0 +1,144 @@
package system
import (
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/mcp/client"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/gin-gonic/gin"
"github.com/mark3labs/mcp-go/mcp"
)
// Create
// @Tags mcp
// @Summary 自动McpTool
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.AutoMcpTool true "创建自动代码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/mcp [post]
func (a *AutoCodeTemplateApi) MCP(c *gin.Context) {
var info request.AutoMcpTool
err := c.ShouldBindJSON(&info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
toolFilePath, err := autoCodeTemplateService.CreateMcp(c.Request.Context(), info)
if err != nil {
response.FailWithMessage("创建失败", c)
global.GVA_LOG.Error(err.Error())
return
}
response.OkWithMessage("创建成功,MCP Tool路径:"+toolFilePath, c)
}
// Create
// @Tags mcp
// @Summary 自动McpTool
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.AutoMcpTool true "创建自动代码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/mcpList [post]
func (a *AutoCodeTemplateApi) MCPList(c *gin.Context) {
baseUrl := fmt.Sprintf("http://127.0.0.1:%d%s", global.GVA_CONFIG.System.Addr, global.GVA_CONFIG.MCP.SSEPath)
testClient, err := client.NewClient(baseUrl, "testClient", "v1.0.0", global.GVA_CONFIG.MCP.Name)
defer testClient.Close()
toolsRequest := mcp.ListToolsRequest{}
list, err := testClient.ListTools(c.Request.Context(), toolsRequest)
if err != nil {
response.FailWithMessage("创建失败", c)
global.GVA_LOG.Error(err.Error())
return
}
mcpServerConfig := map[string]interface{}{
"mcpServers": map[string]interface{}{
global.GVA_CONFIG.MCP.Name: map[string]string{
"url": baseUrl,
},
},
}
response.OkWithData(gin.H{
"mcpServerConfig": mcpServerConfig,
"list": list,
}, c)
}
// Create
// @Tags mcp
// @Summary 测试McpTool
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body object true "调用MCP Tool的参数"
// @Success 200 {object} response.Response "{"success":true,"data":{},"msg":"测试成功"}"
// @Router /autoCode/mcpTest [post]
func (a *AutoCodeTemplateApi) MCPTest(c *gin.Context) {
// 定义接口请求结构
var testRequest struct {
Name string `json:"name" binding:"required"` // 工具名称
Arguments map[string]interface{} `json:"arguments" binding:"required"` // 工具参数
}
// 绑定JSON请求体
if err := c.ShouldBindJSON(&testRequest); err != nil {
response.FailWithMessage("参数解析失败:"+err.Error(), c)
return
}
// 创建MCP客户端
baseUrl := fmt.Sprintf("http://127.0.0.1:%d%s", global.GVA_CONFIG.System.Addr, global.GVA_CONFIG.MCP.SSEPath)
testClient, err := client.NewClient(baseUrl, "testClient", "v1.0.0", global.GVA_CONFIG.MCP.Name)
if err != nil {
response.FailWithMessage("创建MCP客户端失败:"+err.Error(), c)
return
}
defer testClient.Close()
ctx := c.Request.Context()
// 初始化MCP连接
initRequest := mcp.InitializeRequest{}
initRequest.Params.ProtocolVersion = mcp.LATEST_PROTOCOL_VERSION
initRequest.Params.ClientInfo = mcp.Implementation{
Name: "testClient",
Version: "v1.0.0",
}
_, err = testClient.Initialize(ctx, initRequest)
if err != nil {
response.FailWithMessage("初始化MCP连接失败:"+err.Error(), c)
return
}
// 构建工具调用请求
request := mcp.CallToolRequest{}
request.Params.Name = testRequest.Name
request.Params.Arguments = testRequest.Arguments
// 调用工具
result, err := testClient.CallTool(ctx, request)
if err != nil {
response.FailWithMessage("工具调用失败:"+err.Error(), c)
return
}
// 处理响应结果
if len(result.Content) == 0 {
response.FailWithMessage("工具未返回任何内容", c)
return
}
// 返回结果
response.OkWithData(result.Content, c)
}
+100
View File
@@ -0,0 +1,100 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
common "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"strings"
)
type AutoCodePackageApi struct{}
// Create
// @Tags AutoCodePackage
// @Summary 创建package
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.SysAutoCodePackageCreate true "创建package"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "创建package成功"
// @Router /autoCode/createPackage [post]
func (a *AutoCodePackageApi) Create(c *gin.Context) {
var info request.SysAutoCodePackageCreate
_ = c.ShouldBindJSON(&info)
if err := utils.Verify(info, utils.AutoPackageVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if strings.Contains(info.PackageName, "\\") || strings.Contains(info.PackageName, "/") || strings.Contains(info.PackageName, "..") {
response.FailWithMessage("包名不合法", c)
return
} // PackageName可能导致路径穿越的问题 / 和 \ 都要防止
err := autoCodePackageService.Create(c.Request.Context(), &info)
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
return
}
response.OkWithMessage("创建成功", c)
}
// Delete
// @Tags AutoCode
// @Summary 删除package
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body common.GetById true "创建package"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "删除package成功"
// @Router /autoCode/delPackage [post]
func (a *AutoCodePackageApi) Delete(c *gin.Context) {
var info common.GetById
_ = c.ShouldBindJSON(&info)
err := autoCodePackageService.Delete(c.Request.Context(), info)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
return
}
response.OkWithMessage("删除成功", c)
}
// All
// @Tags AutoCodePackage
// @Summary 获取package
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "创建package成功"
// @Router /autoCode/getPackage [post]
func (a *AutoCodePackageApi) All(c *gin.Context) {
data, err := autoCodePackageService.All(c.Request.Context())
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(gin.H{"pkgs": data}, "获取成功", c)
}
// Templates
// @Tags AutoCodePackage
// @Summary 获取package
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "创建package成功"
// @Router /autoCode/getTemplates [get]
func (a *AutoCodePackageApi) Templates(c *gin.Context) {
data, err := autoCodePackageService.Templates(c.Request.Context())
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(data, "获取成功", c)
}
+218
View File
@@ -0,0 +1,218 @@
package system
import (
"fmt"
"os"
"path/filepath"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
"github.com/flipped-aurora/gin-vue-admin/server/plugin/plugin-tool/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type AutoCodePluginApi struct{}
// Install
// @Tags AutoCodePlugin
// @Summary 安装插件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param plug formData file true "this is a test file"
// @Success 200 {object} response.Response{data=[]interface{},msg=string} "安装插件成功"
// @Router /autoCode/installPlugin [post]
func (a *AutoCodePluginApi) Install(c *gin.Context) {
header, err := c.FormFile("plug")
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
web, server, err := autoCodePluginService.Install(header)
webStr := "web插件安装成功"
serverStr := "server插件安装成功"
if web == -1 {
webStr = "web端插件未成功安装,请按照文档自行解压安装,如果为纯后端插件请忽略此条提示"
}
if server == -1 {
serverStr = "server端插件未成功安装,请按照文档自行解压安装,如果为纯前端插件请忽略此条提示"
}
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithData([]interface{}{
gin.H{
"code": web,
"msg": webStr,
},
gin.H{
"code": server,
"msg": serverStr,
}}, c)
}
// Packaged
// @Tags AutoCodePlugin
// @Summary 打包插件
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param plugName query string true "插件名称"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "打包插件成功"
// @Router /autoCode/pubPlug [post]
func (a *AutoCodePluginApi) Packaged(c *gin.Context) {
plugName := c.Query("plugName")
zipPath, err := autoCodePluginService.PubPlug(plugName)
if err != nil {
global.GVA_LOG.Error("打包失败!", zap.Error(err))
response.FailWithMessage("打包失败"+err.Error(), c)
return
}
response.OkWithMessage(fmt.Sprintf("打包成功,文件路径为:%s", zipPath), c)
}
// InitMenu
// @Tags AutoCodePlugin
// @Summary 打包插件
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "打包插件成功"
// @Router /autoCode/initMenu [post]
func (a *AutoCodePluginApi) InitMenu(c *gin.Context) {
var menuInfo request.InitMenu
err := c.ShouldBindJSON(&menuInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = autoCodePluginService.InitMenu(menuInfo)
if err != nil {
global.GVA_LOG.Error("创建初始化Menu失败!", zap.Error(err))
response.FailWithMessage("创建初始化Menu失败"+err.Error(), c)
return
}
response.OkWithMessage("文件变更成功", c)
}
// InitAPI
// @Tags AutoCodePlugin
// @Summary 打包插件
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "打包插件成功"
// @Router /autoCode/initAPI [post]
func (a *AutoCodePluginApi) InitAPI(c *gin.Context) {
var apiInfo request.InitApi
err := c.ShouldBindJSON(&apiInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = autoCodePluginService.InitAPI(apiInfo)
if err != nil {
global.GVA_LOG.Error("创建初始化API失败!", zap.Error(err))
response.FailWithMessage("创建初始化API失败"+err.Error(), c)
return
}
response.OkWithMessage("文件变更成功", c)
}
// InitDictionary
// @Tags AutoCodePlugin
// @Summary 打包插件
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "打包插件成功"
// @Router /autoCode/initDictionary [post]
func (a *AutoCodePluginApi) InitDictionary(c *gin.Context) {
var dictInfo request.InitDictionary
err := c.ShouldBindJSON(&dictInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = autoCodePluginService.InitDictionary(dictInfo)
if err != nil {
global.GVA_LOG.Error("创建初始化Dictionary失败!", zap.Error(err))
response.FailWithMessage("创建初始化Dictionary失败"+err.Error(), c)
return
}
response.OkWithMessage("文件变更成功", c)
}
// GetPluginList
// @Tags AutoCodePlugin
// @Summary 获取插件列表
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {object} response.Response{data=[]systemRes.PluginInfo} "获取插件列表成功"
// @Router /autoCode/getPluginList [get]
func (a *AutoCodePluginApi) GetPluginList(c *gin.Context) {
serverDir := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, "plugin")
webDir := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Web, "plugin")
serverEntries, _ := os.ReadDir(serverDir)
webEntries, _ := os.ReadDir(webDir)
configMap := make(map[string]string)
for _, entry := range serverEntries {
if entry.IsDir() {
configMap[entry.Name()] = "server"
}
}
for _, entry := range webEntries {
if entry.IsDir() {
if val, ok := configMap[entry.Name()]; ok {
if val == "server" {
configMap[entry.Name()] = "full"
}
} else {
configMap[entry.Name()] = "web"
}
}
}
var list []systemRes.PluginInfo
for k, v := range configMap {
apis, menus, dicts := utils.GetPluginData(k)
list = append(list, systemRes.PluginInfo{
PluginName: k,
PluginType: v,
Apis: apis,
Menus: menus,
Dictionaries: dicts,
})
}
response.OkWithDetailed(list, "获取成功", c)
}
// Remove
// @Tags AutoCodePlugin
// @Summary 删除插件
// @Security ApiKeyAuth
// @Produce application/json
// @Param pluginName query string true "插件名称"
// @Param pluginType query string true "插件类型"
// @Success 200 {object} response.Response{msg=string} "删除插件成功"
// @Router /autoCode/removePlugin [post]
func (a *AutoCodePluginApi) Remove(c *gin.Context) {
pluginName := c.Query("pluginName")
pluginType := c.Query("pluginType")
err := autoCodePluginService.Remove(pluginName, pluginType)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败"+err.Error(), c)
return
}
response.OkWithMessage("删除成功", c)
}
+121
View File
@@ -0,0 +1,121 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type AutoCodeTemplateApi struct{}
// Preview
// @Tags AutoCodeTemplate
// @Summary 预览创建后的代码
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.AutoCode true "预览创建代码"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "预览创建后的代码"
// @Router /autoCode/preview [post]
func (a *AutoCodeTemplateApi) Preview(c *gin.Context) {
var info request.AutoCode
err := c.ShouldBindJSON(&info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(info, utils.AutoCodeVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = info.Pretreatment()
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
info.PackageT = utils.FirstUpper(info.Package)
autoCode, err := autoCodeTemplateService.Preview(c.Request.Context(), info)
if err != nil {
global.GVA_LOG.Error(err.Error(), zap.Error(err))
response.FailWithMessage("预览失败:"+err.Error(), c)
} else {
response.OkWithDetailed(gin.H{"autoCode": autoCode}, "预览成功", c)
}
}
// Create
// @Tags AutoCodeTemplate
// @Summary 自动代码模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.AutoCode true "创建自动代码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/createTemp [post]
func (a *AutoCodeTemplateApi) Create(c *gin.Context) {
var info request.AutoCode
err := c.ShouldBindJSON(&info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(info, utils.AutoCodeVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = info.Pretreatment()
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = autoCodeTemplateService.Create(c.Request.Context(), info)
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage(err.Error(), c)
} else {
response.OkWithMessage("创建成功", c)
}
}
// AddFunc
// @Tags AddFunc
// @Summary 增加方法
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.AutoCode true "增加方法"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/addFunc [post]
func (a *AutoCodeTemplateApi) AddFunc(c *gin.Context) {
var info request.AutoFunc
err := c.ShouldBindJSON(&info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
var tempMap map[string]string
if info.IsPreview {
info.Router = "填充router"
info.FuncName = "填充funcName"
info.Method = "填充method"
info.Description = "填充description"
tempMap, err = autoCodeTemplateService.GetApiAndServer(info)
} else {
err = autoCodeTemplateService.AddFunc(info)
}
if err != nil {
global.GVA_LOG.Error("注入失败!", zap.Error(err))
response.FailWithMessage("注入失败", c)
} else {
if info.IsPreview {
response.OkWithDetailed(tempMap, "注入成功", c)
return
}
response.OkWithMessage("注入成功", c)
}
}
+24 -3
View File
@@ -14,8 +14,19 @@ type ApiGroup struct {
DictionaryApi
AuthorityMenuApi
OperationRecordApi
AutoCodeHistoryApi
DictionaryDetailApi
AuthorityBtnApi
SysExportTemplateApi
AutoCodePluginApi
AutoCodePackageApi
AutoCodeHistoryApi
AutoCodeTemplateApi
SysParamsApi
SysVersionApi
SysErrorApi
LoginLogApi
ApiTokenApi
SkillsApi
}
var (
@@ -25,12 +36,22 @@ var (
userService = service.ServiceGroupApp.SystemServiceGroup.UserService
initDBService = service.ServiceGroupApp.SystemServiceGroup.InitDBService
casbinService = service.ServiceGroupApp.SystemServiceGroup.CasbinService
autoCodeService = service.ServiceGroupApp.SystemServiceGroup.AutoCodeService
baseMenuService = service.ServiceGroupApp.SystemServiceGroup.BaseMenuService
authorityService = service.ServiceGroupApp.SystemServiceGroup.AuthorityService
dictionaryService = service.ServiceGroupApp.SystemServiceGroup.DictionaryService
authorityBtnService = service.ServiceGroupApp.SystemServiceGroup.AuthorityBtnService
systemConfigService = service.ServiceGroupApp.SystemServiceGroup.SystemConfigService
sysParamsService = service.ServiceGroupApp.SystemServiceGroup.SysParamsService
operationRecordService = service.ServiceGroupApp.SystemServiceGroup.OperationRecordService
autoCodeHistoryService = service.ServiceGroupApp.SystemServiceGroup.AutoCodeHistoryService
dictionaryDetailService = service.ServiceGroupApp.SystemServiceGroup.DictionaryDetailService
autoCodeService = service.ServiceGroupApp.SystemServiceGroup.AutoCodeService
autoCodePluginService = service.ServiceGroupApp.SystemServiceGroup.AutoCodePlugin
autoCodePackageService = service.ServiceGroupApp.SystemServiceGroup.AutoCodePackage
autoCodeHistoryService = service.ServiceGroupApp.SystemServiceGroup.AutoCodeHistory
autoCodeTemplateService = service.ServiceGroupApp.SystemServiceGroup.AutoCodeTemplate
sysVersionService = service.ServiceGroupApp.SystemServiceGroup.SysVersionService
sysErrorService = service.ServiceGroupApp.SystemServiceGroup.SysErrorService
loginLogService = service.ServiceGroupApp.SystemServiceGroup.LoginLogService
apiTokenService = service.ServiceGroupApp.SystemServiceGroup.ApiTokenService
skillsService = service.ServiceGroupApp.SystemServiceGroup.SkillsService
)
+272 -121
View File
@@ -15,158 +15,309 @@ import (
type SystemApiApi struct{}
// @Tags SysApi
// @Summary 创建基础api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysApi true "api路径, api中文描述, api组, 方法"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /api/createApi [post]
// CreateApi
// @Tags SysApi
// @Summary 创建基础api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysApi true "api路径, api中文描述, api组, 方法"
// @Success 200 {object} response.Response{msg=string} "创建基础api"
// @Router /api/createApi [post]
func (s *SystemApiApi) CreateApi(c *gin.Context) {
var api system.SysApi
_ = c.ShouldBindJSON(&api)
if err := utils.Verify(api, utils.ApiVerify); err != nil {
err := c.ShouldBindJSON(&api)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := apiService.CreateApi(api); err != nil {
err = utils.Verify(api, utils.ApiVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = apiService.CreateApi(api)
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
} else {
response.OkWithMessage("创建成功", c)
}
}
// @Tags SysApi
// @Summary 删除api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysApi true "ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /api/deleteApi [post]
func (s *SystemApiApi) DeleteApi(c *gin.Context) {
var api system.SysApi
_ = c.ShouldBindJSON(&api)
if err := utils.Verify(api.GVA_MODEL, utils.IdVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := apiService.DeleteApi(api); err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
}
response.OkWithMessage("创建成功", c)
}
// @Tags SysApi
// @Summary 分页获取API列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.SearchApiParams true "分页获取API列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/getApiList [post]
func (s *SystemApiApi) GetApiList(c *gin.Context) {
var pageInfo systemReq.SearchApiParams
_ = c.ShouldBindJSON(&pageInfo)
if err := utils.Verify(pageInfo.PageInfo, utils.PageInfoVerify); err != nil {
response.FailWithMessage(err.Error(), c)
// SyncApi
// @Tags SysApi
// @Summary 同步API
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "同步API"
// @Router /api/syncApi [get]
func (s *SystemApiApi) SyncApi(c *gin.Context) {
newApis, deleteApis, ignoreApis, err := apiService.SyncApi()
if err != nil {
global.GVA_LOG.Error("同步失败!", zap.Error(err))
response.FailWithMessage("同步失败", c)
return
}
if err, list, total := apiService.GetAPIInfoList(pageInfo.SysApi, pageInfo.PageInfo, pageInfo.OrderKey, pageInfo.Desc); err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
response.OkWithData(gin.H{
"newApis": newApis,
"deleteApis": deleteApis,
"ignoreApis": ignoreApis,
}, c)
}
// @Tags SysApi
// @Summary 根据id获取api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "根据id获取api"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/getApiById [post]
func (s *SystemApiApi) GetApiById(c *gin.Context) {
var idInfo request.GetById
_ = c.ShouldBindJSON(&idInfo)
if err := utils.Verify(idInfo, utils.IdVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err, api := apiService.GetApiById(idInfo.ID)
// GetApiGroups
// @Tags SysApi
// @Summary 获取API分组
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "获取API分组"
// @Router /api/getApiGroups [get]
func (s *SystemApiApi) GetApiGroups(c *gin.Context) {
groups, apiGroupMap, err := apiService.GetApiGroups()
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithData(systemRes.SysAPIResponse{Api: api}, c)
return
}
response.OkWithData(gin.H{
"groups": groups,
"apiGroupMap": apiGroupMap,
}, c)
}
// @Tags SysApi
// @Summary 创建基础api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysApi true "api路径, api中文描述, api组, 方法"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /api/updateApi [post]
func (s *SystemApiApi) UpdateApi(c *gin.Context) {
var api system.SysApi
_ = c.ShouldBindJSON(&api)
if err := utils.Verify(api, utils.ApiVerify); err != nil {
// IgnoreApi
// @Tags IgnoreApi
// @Summary 忽略API
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "同步API"
// @Router /api/ignoreApi [post]
func (s *SystemApiApi) IgnoreApi(c *gin.Context) {
var ignoreApi system.SysIgnoreApi
err := c.ShouldBindJSON(&ignoreApi)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := apiService.UpdateApi(api); err != nil {
global.GVA_LOG.Error("修改失败!", zap.Error(err))
response.FailWithMessage("修改失败", c)
} else {
response.OkWithMessage("修改成功", c)
err = apiService.IgnoreApi(ignoreApi)
if err != nil {
global.GVA_LOG.Error("忽略失败!", zap.Error(err))
response.FailWithMessage("忽略失败", c)
return
}
response.Ok(c)
}
// @Tags SysApi
// @Summary 获取所有的Api 不分页
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/getAllApis [post]
func (s *SystemApiApi) GetAllApis(c *gin.Context) {
if err, apis := apiService.GetAllApis(); err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(systemRes.SysAPIListResponse{Apis: apis}, "获取成功", c)
// EnterSyncApi
// @Tags SysApi
// @Summary 确认同步API
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "确认同步API"
// @Router /api/enterSyncApi [post]
func (s *SystemApiApi) EnterSyncApi(c *gin.Context) {
var syncApi systemRes.SysSyncApis
err := c.ShouldBindJSON(&syncApi)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = apiService.EnterSyncApi(syncApi)
if err != nil {
global.GVA_LOG.Error("忽略失败!", zap.Error(err))
response.FailWithMessage("忽略失败", c)
return
}
response.Ok(c)
}
// @Tags SysApi
// @Summary 删除选中Api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /api/deleteApisByIds [delete]
func (s *SystemApiApi) DeleteApisByIds(c *gin.Context) {
var ids request.IdsReq
_ = c.ShouldBindJSON(&ids)
if err := apiService.DeleteApisByIds(ids); err != nil {
// DeleteApi
// @Tags SysApi
// @Summary 删除api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysApi true "ID"
// @Success 200 {object} response.Response{msg=string} "删除api"
// @Router /api/deleteApi [post]
func (s *SystemApiApi) DeleteApi(c *gin.Context) {
var api system.SysApi
err := c.ShouldBindJSON(&api)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(api.GVA_MODEL, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = apiService.DeleteApi(api)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
return
}
response.OkWithMessage("删除成功", c)
}
// GetApiList
// @Tags SysApi
// @Summary 分页获取API列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.SearchApiParams true "分页获取API列表"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取API列表,返回包括列表,总数,页码,每页数量"
// @Router /api/getApiList [post]
func (s *SystemApiApi) GetApiList(c *gin.Context) {
var pageInfo systemReq.SearchApiParams
err := c.ShouldBindJSON(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(pageInfo.PageInfo, utils.PageInfoVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := apiService.GetAPIInfoList(pageInfo.SysApi, pageInfo.PageInfo, pageInfo.OrderKey, pageInfo.Desc)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
// GetApiById
// @Tags SysApi
// @Summary 根据id获取api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "根据id获取api"
// @Success 200 {object} response.Response{data=systemRes.SysAPIResponse} "根据id获取api,返回包括api详情"
// @Router /api/getApiById [post]
func (s *SystemApiApi) GetApiById(c *gin.Context) {
var idInfo request.GetById
err := c.ShouldBindJSON(&idInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(idInfo, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
api, err := apiService.GetApiById(idInfo.ID)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(systemRes.SysAPIResponse{Api: api}, "获取成功", c)
}
// UpdateApi
// @Tags SysApi
// @Summary 修改基础api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysApi true "api路径, api中文描述, api组, 方法"
// @Success 200 {object} response.Response{msg=string} "修改基础api"
// @Router /api/updateApi [post]
func (s *SystemApiApi) UpdateApi(c *gin.Context) {
var api system.SysApi
err := c.ShouldBindJSON(&api)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(api, utils.ApiVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = apiService.UpdateApi(api)
if err != nil {
global.GVA_LOG.Error("修改失败!", zap.Error(err))
response.FailWithMessage("修改失败", c)
return
}
response.OkWithMessage("修改成功", c)
}
// GetAllApis
// @Tags SysApi
// @Summary 获取所有的Api 不分页
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=systemRes.SysAPIListResponse,msg=string} "获取所有的Api 不分页,返回包括api列表"
// @Router /api/getAllApis [post]
func (s *SystemApiApi) GetAllApis(c *gin.Context) {
authorityID := utils.GetUserAuthorityId(c)
apis, err := apiService.GetAllApis(authorityID)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(systemRes.SysAPIListResponse{Apis: apis}, "获取成功", c)
}
// DeleteApisByIds
// @Tags SysApi
// @Summary 删除选中Api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "ID"
// @Success 200 {object} response.Response{msg=string} "删除选中Api"
// @Router /api/deleteApisByIds [delete]
func (s *SystemApiApi) DeleteApisByIds(c *gin.Context) {
var ids request.IdsReq
err := c.ShouldBindJSON(&ids)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = apiService.DeleteApisByIds(ids)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
return
}
response.OkWithMessage("删除成功", c)
}
// FreshCasbin
// @Tags SysApi
// @Summary 刷新casbin缓存
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "刷新成功"
// @Router /api/freshCasbin [get]
func (s *SystemApiApi) FreshCasbin(c *gin.Context) {
err := casbinService.FreshCasbin()
if err != nil {
global.GVA_LOG.Error("刷新失败!", zap.Error(err))
response.FailWithMessage("刷新失败", c)
return
}
response.OkWithMessage("刷新成功", c)
}
+81
View File
@@ -0,0 +1,81 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
sysReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type ApiTokenApi struct{}
// CreateApiToken 签发Token
func (s *ApiTokenApi) CreateApiToken(c *gin.Context) {
var req struct {
UserID uint `json:"userId"`
AuthorityID uint `json:"authorityId"`
Days int `json:"days"` // -1为永久, 其他为天数
Remark string `json:"remark"`
}
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
token := system.SysApiToken{
UserID: req.UserID,
AuthorityID: req.AuthorityID,
Remark: req.Remark,
}
jwtStr, err := apiTokenService.CreateApiToken(token, req.Days)
if err != nil {
global.GVA_LOG.Error("签发失败!", zap.Error(err))
response.FailWithMessage("签发失败: "+err.Error(), c)
return
}
response.OkWithDetailed(gin.H{"token": jwtStr}, "签发成功", c)
}
// GetApiTokenList 获取列表
func (s *ApiTokenApi) GetApiTokenList(c *gin.Context) {
var pageInfo sysReq.SysApiTokenSearch
err := c.ShouldBindJSON(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := apiTokenService.GetApiTokenList(pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
// DeleteApiToken 作废Token
func (s *ApiTokenApi) DeleteApiToken(c *gin.Context) {
var req system.SysApiToken
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = apiTokenService.DeleteApiToken(req.ID)
if err != nil {
global.GVA_LOG.Error("作废失败!", zap.Error(err))
response.FailWithMessage("作废失败", c)
return
}
response.OkWithMessage("作废成功", c)
}
+132 -95
View File
@@ -2,10 +2,8 @@ package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
@@ -15,151 +13,190 @@ import (
type AuthorityApi struct{}
// @Tags Authority
// @Summary 创建角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysAuthority true "权限id, 权限名, 父角色id"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /authority/createAuthority [post]
// CreateAuthority
// @Tags Authority
// @Summary 创建角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysAuthority true "权限id, 权限名, 父角色id"
// @Success 200 {object} response.Response{data=systemRes.SysAuthorityResponse,msg=string} "创建角色,返回包括系统角色详情"
// @Router /authority/createAuthority [post]
func (a *AuthorityApi) CreateAuthority(c *gin.Context) {
var authority system.SysAuthority
_ = c.ShouldBindJSON(&authority)
if err := utils.Verify(authority, utils.AuthorityVerify); err != nil {
var authority, authBack system.SysAuthority
var err error
if err = c.ShouldBindJSON(&authority); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, authBack := authorityService.CreateAuthority(authority); err != nil {
if err = utils.Verify(authority, utils.AuthorityVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if *authority.ParentId == 0 && global.GVA_CONFIG.System.UseStrictAuth {
authority.ParentId = utils.Pointer(utils.GetUserAuthorityId(c))
}
if authBack, err = authorityService.CreateAuthority(authority); err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败"+err.Error(), c)
} else {
_ = menuService.AddMenuAuthority(systemReq.DefaultMenu(), authority.AuthorityId)
_ = casbinService.UpdateCasbin(authority.AuthorityId, systemReq.DefaultCasbin())
response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authBack}, "创建成功", c)
return
}
err = casbinService.FreshCasbin()
if err != nil {
global.GVA_LOG.Error("创建成功,权限刷新失败。", zap.Error(err))
response.FailWithMessage("创建成功,权限刷新失败。"+err.Error(), c)
return
}
response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authBack}, "创建成功", c)
}
// @Tags Authority
// @Summary 拷贝角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body response.SysAuthorityCopyResponse true "旧角色id, 新权限id, 新权限名, 新父角色id"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"拷贝成功"}"
// @Router /authority/copyAuthority [post]
// CopyAuthority
// @Tags Authority
// @Summary 拷贝角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body response.SysAuthorityCopyResponse true "旧角色id, 新权限id, 新权限名, 新父角色id"
// @Success 200 {object} response.Response{data=systemRes.SysAuthorityResponse,msg=string} "拷贝角色,返回包括系统角色详情"
// @Router /authority/copyAuthority [post]
func (a *AuthorityApi) CopyAuthority(c *gin.Context) {
var copyInfo systemRes.SysAuthorityCopyResponse
_ = c.ShouldBindJSON(&copyInfo)
if err := utils.Verify(copyInfo, utils.OldAuthorityVerify); err != nil {
err := c.ShouldBindJSON(&copyInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := utils.Verify(copyInfo.Authority, utils.AuthorityVerify); err != nil {
err = utils.Verify(copyInfo, utils.OldAuthorityVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, authBack := authorityService.CopyAuthority(copyInfo); err != nil {
err = utils.Verify(copyInfo.Authority, utils.AuthorityVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
adminAuthorityID := utils.GetUserAuthorityId(c)
authBack, err := authorityService.CopyAuthority(adminAuthorityID, copyInfo)
if err != nil {
global.GVA_LOG.Error("拷贝失败!", zap.Error(err))
response.FailWithMessage("拷贝失败"+err.Error(), c)
} else {
response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authBack}, "拷贝成功", c)
return
}
response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authBack}, "拷贝成功", c)
}
// @Tags Authority
// @Summary 删除角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysAuthority true "删除角色"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /authority/deleteAuthority [post]
// DeleteAuthority
// @Tags Authority
// @Summary 删除角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysAuthority true "删除角色"
// @Success 200 {object} response.Response{msg=string} "删除角色"
// @Router /authority/deleteAuthority [post]
func (a *AuthorityApi) DeleteAuthority(c *gin.Context) {
var authority system.SysAuthority
_ = c.ShouldBindJSON(&authority)
if err := utils.Verify(authority, utils.AuthorityIdVerify); err != nil {
var err error
if err = c.ShouldBindJSON(&authority); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := authorityService.DeleteAuthority(&authority); err != nil { // 删除角色之前需要判断是否有用户正在使用此角色
if err = utils.Verify(authority, utils.AuthorityIdVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
// 删除角色之前需要判断是否有用户正在使用此角色
if err = authorityService.DeleteAuthority(&authority); err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败"+err.Error(), c)
} else {
response.OkWithMessage("删除成功", c)
return
}
_ = casbinService.FreshCasbin()
response.OkWithMessage("删除成功", c)
}
// @Tags Authority
// @Summary 更新角色信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysAuthority true "权限id, 权限名, 父角色id"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /authority/updateAuthority [post]
// UpdateAuthority
// @Tags Authority
// @Summary 更新角色信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysAuthority true "权限id, 权限名, 父角色id"
// @Success 200 {object} response.Response{data=systemRes.SysAuthorityResponse,msg=string} "更新角色信息,返回包括系统角色详情"
// @Router /authority/updateAuthority [put]
func (a *AuthorityApi) UpdateAuthority(c *gin.Context) {
var auth system.SysAuthority
_ = c.ShouldBindJSON(&auth)
if err := utils.Verify(auth, utils.AuthorityVerify); err != nil {
err := c.ShouldBindJSON(&auth)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, authority := authorityService.UpdateAuthority(auth); err != nil {
err = utils.Verify(auth, utils.AuthorityVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
authority, err := authorityService.UpdateAuthority(auth)
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败"+err.Error(), c)
} else {
response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authority}, "更新成功", c)
}
}
// @Tags Authority
// @Summary 分页获取角色列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "页码, 每页大小"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /authority/getAuthorityList [post]
func (a *AuthorityApi) GetAuthorityList(c *gin.Context) {
var pageInfo request.PageInfo
_ = c.ShouldBindJSON(&pageInfo)
if err := utils.Verify(pageInfo, utils.PageInfoVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, list, total := authorityService.GetAuthorityInfoList(pageInfo); err != nil {
response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authority}, "更新成功", c)
}
// GetAuthorityList
// @Tags Authority
// @Summary 分页获取角色列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "页码, 每页大小"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取角色列表,返回包括列表,总数,页码,每页数量"
// @Router /authority/getAuthorityList [post]
func (a *AuthorityApi) GetAuthorityList(c *gin.Context) {
authorityID := utils.GetUserAuthorityId(c)
list, err := authorityService.GetAuthorityInfoList(authorityID)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败"+err.Error(), c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
return
}
response.OkWithDetailed(list, "获取成功", c)
}
// @Tags Authority
// @Summary 设置角色资源权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysAuthority true "设置角色资源权限"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
// @Router /authority/setDataAuthority [post]
// SetDataAuthority
// @Tags Authority
// @Summary 设置角色资源权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysAuthority true "设置角色资源权限"
// @Success 200 {object} response.Response{msg=string} "设置角色资源权限"
// @Router /authority/setDataAuthority [post]
func (a *AuthorityApi) SetDataAuthority(c *gin.Context) {
var auth system.SysAuthority
_ = c.ShouldBindJSON(&auth)
if err := utils.Verify(auth, utils.AuthorityIdVerify); err != nil {
err := c.ShouldBindJSON(&auth)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := authorityService.SetDataAuthority(auth); err != nil {
err = utils.Verify(auth, utils.AuthorityIdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
adminAuthorityID := utils.GetUserAuthorityId(c)
err = authorityService.SetDataAuthority(adminAuthorityID, auth)
if err != nil {
global.GVA_LOG.Error("设置失败!", zap.Error(err))
response.FailWithMessage("设置失败"+err.Error(), c)
} else {
response.OkWithMessage("设置成功", c)
return
}
response.OkWithMessage("设置成功", c)
}
+80
View File
@@ -0,0 +1,80 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type AuthorityBtnApi struct{}
// GetAuthorityBtn
// @Tags AuthorityBtn
// @Summary 获取权限按钮
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.SysAuthorityBtnReq true "菜单id, 角色id, 选中的按钮id"
// @Success 200 {object} response.Response{data=response.SysAuthorityBtnRes,msg=string} "返回列表成功"
// @Router /authorityBtn/getAuthorityBtn [post]
func (a *AuthorityBtnApi) GetAuthorityBtn(c *gin.Context) {
var req request.SysAuthorityBtnReq
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
res, err := authorityBtnService.GetAuthorityBtn(req)
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败", c)
return
}
response.OkWithDetailed(res, "查询成功", c)
}
// SetAuthorityBtn
// @Tags AuthorityBtn
// @Summary 设置权限按钮
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.SysAuthorityBtnReq true "菜单id, 角色id, 选中的按钮id"
// @Success 200 {object} response.Response{msg=string} "返回列表成功"
// @Router /authorityBtn/setAuthorityBtn [post]
func (a *AuthorityBtnApi) SetAuthorityBtn(c *gin.Context) {
var req request.SysAuthorityBtnReq
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = authorityBtnService.SetAuthorityBtn(req)
if err != nil {
global.GVA_LOG.Error("分配失败!", zap.Error(err))
response.FailWithMessage("分配失败", c)
return
}
response.OkWithMessage("分配成功", c)
}
// CanRemoveAuthorityBtn
// @Tags AuthorityBtn
// @Summary 设置权限按钮
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "删除成功"
// @Router /authorityBtn/canRemoveAuthorityBtn [post]
func (a *AuthorityBtnApi) CanRemoveAuthorityBtn(c *gin.Context) {
id := c.Query("id")
err := authorityBtnService.CanRemoveAuthorityBtn(id)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithMessage("删除成功", c)
}
+79 -106
View File
@@ -1,121 +1,67 @@
package system
import (
"errors"
"fmt"
"net/url"
"os"
"github.com/flipped-aurora/gin-vue-admin/server/model/common"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type AutoCodeApi struct{}
// PreviewTemp
// @Tags AutoCode
// @Summary 预览创建后的代码
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.AutoCodeStruct true "预览创建代码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/preview [post]
func (autoApi *AutoCodeApi) PreviewTemp(c *gin.Context) {
var a system.AutoCodeStruct
_ = c.ShouldBindJSON(&a)
if err := utils.Verify(a, utils.AutoCodeVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
autoCode, err := autoCodeService.PreviewTemp(a)
if err != nil {
global.GVA_LOG.Error("预览失败!", zap.Error(err))
response.FailWithMessage("预览失败", c)
} else {
response.OkWithDetailed(gin.H{"autoCode": autoCode}, "预览成功", c)
}
}
// CreateTemp
// @Tags AutoCode
// @Summary 自动代码模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.AutoCodeStruct true "创建自动代码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/createTemp [post]
func (autoApi *AutoCodeApi) CreateTemp(c *gin.Context) {
var a system.AutoCodeStruct
_ = c.ShouldBindJSON(&a)
if err := utils.Verify(a, utils.AutoCodeVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
var apiIds []uint
if a.AutoCreateApiToSql {
if ids, err := autoCodeService.AutoCreateApi(&a); err != nil {
global.GVA_LOG.Error("自动化创建失败!请自行清空垃圾数据!", zap.Error(err))
c.Writer.Header().Add("success", "false")
c.Writer.Header().Add("msg", url.QueryEscape("自动化创建失败!请自行清空垃圾数据!"))
return
} else {
apiIds = ids
}
}
err := autoCodeService.CreateTemp(a, apiIds...)
if err != nil {
if errors.Is(err, system.AutoMoveErr) {
c.Writer.Header().Add("success", "true")
c.Writer.Header().Add("msg", url.QueryEscape(err.Error()))
} else {
c.Writer.Header().Add("success", "false")
c.Writer.Header().Add("msg", url.QueryEscape(err.Error()))
_ = os.Remove("./ginvueadmin.zip")
}
} else {
c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", "ginvueadmin.zip")) // fmt.Sprintf("attachment; filename=%s", filename)对下载的文件重命名
c.Writer.Header().Add("Content-Type", "application/json")
c.Writer.Header().Add("success", "true")
c.File("./ginvueadmin.zip")
_ = os.Remove("./ginvueadmin.zip")
}
}
// GetDB
// @Tags AutoCode
// @Summary 获取当前所有数据库
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /autoCode/getDatabase [get]
// @Tags AutoCode
// @Summary 获取当前所有数据库
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取当前所有数据库"
// @Router /autoCode/getDB [get]
func (autoApi *AutoCodeApi) GetDB(c *gin.Context) {
dbs, err := autoCodeService.Database().GetDB()
businessDB := c.Query("businessDB")
dbs, err := autoCodeService.Database(businessDB).GetDB(businessDB)
var dbList []map[string]interface{}
for _, db := range global.GVA_CONFIG.DBList {
var item = make(map[string]interface{})
item["aliasName"] = db.AliasName
item["dbName"] = db.Dbname
item["disable"] = db.Disable
item["dbtype"] = db.Type
dbList = append(dbList, item)
}
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(gin.H{"dbs": dbs, "dbList": dbList}, "获取成功", c)
}
response.OkWithDetailed(gin.H{"dbs": dbs}, "获取成功", c)
}
// GetTables
// @Tags AutoCode
// @Summary 获取当前数据库所有表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /autoCode/getTables [get]
// @Tags AutoCode
// @Summary 获取当前数据库所有表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取当前数据库所有表"
// @Router /autoCode/getTables [get]
func (autoApi *AutoCodeApi) GetTables(c *gin.Context) {
dbName := c.DefaultQuery("dbName", global.GVA_CONFIG.Mysql.Dbname)
tables, err := autoCodeService.Database().GetTables(dbName)
dbName := c.Query("dbName")
businessDB := c.Query("businessDB")
if dbName == "" {
dbName = *global.GVA_ACTIVE_DBNAME
if businessDB != "" {
for _, db := range global.GVA_CONFIG.DBList {
if db.AliasName == businessDB {
dbName = db.Dbname
}
}
}
}
tables, err := autoCodeService.Database(businessDB).GetTables(businessDB, dbName)
if err != nil {
global.GVA_LOG.Error("查询table失败!", zap.Error(err))
response.FailWithMessage("查询table失败", c)
@@ -125,20 +71,47 @@ func (autoApi *AutoCodeApi) GetTables(c *gin.Context) {
}
// GetColumn
// @Tags AutoCode
// @Summary 获取当前表所有字段
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /autoCode/getColumn [get]
// @Tags AutoCode
// @Summary 获取当前表所有字段
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取当前表所有字段"
// @Router /autoCode/getColumn [get]
func (autoApi *AutoCodeApi) GetColumn(c *gin.Context) {
dbName := c.DefaultQuery("dbName", global.GVA_CONFIG.Mysql.Dbname)
businessDB := c.Query("businessDB")
dbName := c.Query("dbName")
if dbName == "" {
dbName = *global.GVA_ACTIVE_DBNAME
if businessDB != "" {
for _, db := range global.GVA_CONFIG.DBList {
if db.AliasName == businessDB {
dbName = db.Dbname
}
}
}
}
tableName := c.Query("tableName")
columns, err := autoCodeService.Database().GetColumn(tableName, dbName)
columns, err := autoCodeService.Database(businessDB).GetColumn(businessDB, tableName, dbName)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(gin.H{"columns": columns}, "获取成功", c)
}
response.OkWithDetailed(gin.H{"columns": columns}, "获取成功", c)
}
func (autoApi *AutoCodeApi) LLMAuto(c *gin.Context) {
var llm common.JSONMap
if err := c.ShouldBindJSON(&llm); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
data, err := autoCodeService.LLMAuto(c.Request.Context(), llm)
if err != nil {
global.GVA_LOG.Error("大模型生成失败!", zap.Error(err))
response.FailWithMessage("大模型生成失败"+err.Error(), c)
return
}
response.OkWithData(data, c)
}
@@ -1,98 +0,0 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type AutoCodeHistoryApi struct{}
// First
// @Tags AutoCode
// @Summary 获取meta信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "请求参数"
// @Success 200 {object} response.Response{} "获取成功!"
// @Router /autoCode/getMeta [post]
func (a *AutoCodeHistoryApi) First(c *gin.Context) {
var info request.GetById
_ = c.ShouldBindJSON(&info)
data, err := autoCodeHistoryService.First(&info)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithDetailed(gin.H{"meta": data}, "获取成功", c)
}
// Delete
// @Tags AutoCode
// @Summary 删除回滚记录
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "请求参数"
// @Success 200 {object} response.Response{} "删除成功!"
// @Router /autoCode/delSysHistory [post]
func (a *AutoCodeHistoryApi) Delete(c *gin.Context) {
var info request.GetById
_ = c.ShouldBindJSON(&info)
err := autoCodeHistoryService.Delete(&info)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
return
}
response.OkWithMessage("删除成功", c)
}
// RollBack
// @Tags AutoCode
// @Summary 回滚自动生成代码
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "请求参数"
// @Success 200 {object} response.Response{} "回滚成功!"
// @Router /autoCode/rollback [post]
func (a *AutoCodeHistoryApi) RollBack(c *gin.Context) {
var info request.GetById
_ = c.ShouldBindJSON(&info)
if err := autoCodeHistoryService.RollBack(&info); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithMessage("回滚成功", c)
}
// GetList
// @Tags AutoCode
// @Summary 查询回滚记录
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.SysAutoHistory true "请求参数"
// @Success 200 {object} response.Response{} "获取成功!"
// @Router /autoCode/getSysHistory [post]
func (a *AutoCodeHistoryApi) GetList(c *gin.Context) {
var search systemReq.SysAutoHistory
_ = c.ShouldBindJSON(&search)
list, total, err := autoCodeHistoryService.GetList(search.PageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: search.Page,
PageSize: search.PageSize,
}, "获取成功", c)
}
+43 -14
View File
@@ -1,6 +1,8 @@
package system
import (
"time"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
@@ -15,27 +17,54 @@ var store = base64Captcha.DefaultMemStore
type BaseApi struct{}
// @Tags Base
// @Summary 生成验证码
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"验证码获取成功"}"
// @Router /base/captcha [post]
// Captcha
// @Tags Base
// @Summary 生成验证码
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=systemRes.SysCaptchaResponse,msg=string} "生成验证码,返回包括随机数id,base64,验证码长度,是否开启验证码"
// @Router /base/captcha [post]
func (b *BaseApi) Captcha(c *gin.Context) {
// 判断验证码是否开启
openCaptcha := global.GVA_CONFIG.Captcha.OpenCaptcha // 是否开启防爆次数
openCaptchaTimeOut := global.GVA_CONFIG.Captcha.OpenCaptchaTimeOut // 缓存超时时间
key := c.ClientIP()
v, ok := global.BlackCache.Get(key)
if !ok {
global.BlackCache.Set(key, 1, time.Second*time.Duration(openCaptchaTimeOut))
}
var oc bool
if openCaptcha == 0 || openCaptcha < interfaceToInt(v) {
oc = true
}
// 字符,公式,验证码配置
// 生成默认数字的driver
driver := base64Captcha.NewDriverDigit(global.GVA_CONFIG.Captcha.ImgHeight, global.GVA_CONFIG.Captcha.ImgWidth, global.GVA_CONFIG.Captcha.KeyLong, 0.7, 80)
// cp := base64Captcha.NewCaptcha(driver, store.UseWithCtx(c)) // v8下使用redis
cp := base64Captcha.NewCaptcha(driver, store)
if id, b64s, err := cp.Generate(); err != nil {
id, b64s, _, err := cp.Generate()
if err != nil {
global.GVA_LOG.Error("验证码获取失败!", zap.Error(err))
response.FailWithMessage("验证码获取失败", c)
} else {
response.OkWithDetailed(systemRes.SysCaptchaResponse{
CaptchaId: id,
PicPath: b64s,
CaptchaLength: global.GVA_CONFIG.Captcha.KeyLong,
}, "验证码获取成功", c)
return
}
response.OkWithDetailed(systemRes.SysCaptchaResponse{
CaptchaId: id,
PicPath: b64s,
CaptchaLength: global.GVA_CONFIG.Captcha.KeyLong,
OpenCaptcha: oc,
}, "验证码获取成功", c)
}
// 类型转换
func interfaceToInt(v interface{}) (i int) {
switch v := v.(type) {
case int:
i = v
default:
i = 0
}
return
}
+37 -23
View File
@@ -12,41 +12,55 @@ import (
type CasbinApi struct{}
// @Tags Casbin
// @Summary 更新角色api权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.CasbinInReceive true "权限id, 权限模型列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /casbin/UpdateCasbin [post]
// UpdateCasbin
// @Tags Casbin
// @Summary 更新角色api权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.CasbinInReceive true "权限id, 权限模型列表"
// @Success 200 {object} response.Response{msg=string} "更新角色api权限"
// @Router /casbin/UpdateCasbin [post]
func (cas *CasbinApi) UpdateCasbin(c *gin.Context) {
var cmr request.CasbinInReceive
_ = c.ShouldBindJSON(&cmr)
if err := utils.Verify(cmr, utils.AuthorityIdVerify); err != nil {
err := c.ShouldBindJSON(&cmr)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := casbinService.UpdateCasbin(cmr.AuthorityId, cmr.CasbinInfos); err != nil {
err = utils.Verify(cmr, utils.AuthorityIdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
adminAuthorityID := utils.GetUserAuthorityId(c)
err = casbinService.UpdateCasbin(adminAuthorityID, cmr.AuthorityId, cmr.CasbinInfos)
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败", c)
} else {
response.OkWithMessage("更新成功", c)
return
}
response.OkWithMessage("更新成功", c)
}
// @Tags Casbin
// @Summary 获取权限列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.CasbinInReceive true "权限id, 权限模型列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /casbin/getPolicyPathByAuthorityId [post]
// GetPolicyPathByAuthorityId
// @Tags Casbin
// @Summary 获取权限列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.CasbinInReceive true "权限id, 权限模型列表"
// @Success 200 {object} response.Response{data=systemRes.PolicyPathResponse,msg=string} "获取权限列表,返回包括casbin详情列表"
// @Router /casbin/getPolicyPathByAuthorityId [post]
func (cas *CasbinApi) GetPolicyPathByAuthorityId(c *gin.Context) {
var casbin request.CasbinInReceive
_ = c.ShouldBindJSON(&casbin)
if err := utils.Verify(casbin, utils.AuthorityIdVerify); err != nil {
err := c.ShouldBindJSON(&casbin)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(casbin, utils.AuthorityIdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
+169 -95
View File
@@ -5,113 +5,187 @@ import (
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
"github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type DictionaryApi struct{}
// @Tags SysDictionary
// @Summary 创建SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionary true "SysDictionary模型"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /sysDictionary/createSysDictionary [post]
// CreateSysDictionary
// @Tags SysDictionary
// @Summary 创建SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionary true "SysDictionary模型"
// @Success 200 {object} response.Response{msg=string} "创建SysDictionary"
// @Router /sysDictionary/createSysDictionary [post]
func (s *DictionaryApi) CreateSysDictionary(c *gin.Context) {
var dictionary system.SysDictionary
_ = c.ShouldBindJSON(&dictionary)
if err := dictionaryService.CreateSysDictionary(dictionary); err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
} else {
response.OkWithMessage("创建成功", c)
}
}
// @Tags SysDictionary
// @Summary 删除SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionary true "SysDictionary模型"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysDictionary/deleteSysDictionary [delete]
func (s *DictionaryApi) DeleteSysDictionary(c *gin.Context) {
var dictionary system.SysDictionary
_ = c.ShouldBindJSON(&dictionary)
if err := dictionaryService.DeleteSysDictionary(dictionary); err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
}
}
// @Tags SysDictionary
// @Summary 更新SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionary true "SysDictionary模型"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysDictionary/updateSysDictionary [put]
func (s *DictionaryApi) UpdateSysDictionary(c *gin.Context) {
var dictionary system.SysDictionary
_ = c.ShouldBindJSON(&dictionary)
if err := dictionaryService.UpdateSysDictionary(&dictionary); err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败", c)
} else {
response.OkWithMessage("更新成功", c)
}
}
// @Tags SysDictionary
// @Summary 用id查询SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query system.SysDictionary true "ID或字典英名"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysDictionary/findSysDictionary [get]
func (s *DictionaryApi) FindSysDictionary(c *gin.Context) {
var dictionary system.SysDictionary
_ = c.ShouldBindQuery(&dictionary)
if err, sysDictionary := dictionaryService.GetSysDictionary(dictionary.Type, dictionary.ID); err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败", c)
} else {
response.OkWithDetailed(gin.H{"resysDictionary": sysDictionary}, "查询成功", c)
}
}
// @Tags SysDictionary
// @Summary 分页获取SysDictionary列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.SysDictionarySearch true "页码, 每页大小, 搜索条件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionary/getSysDictionaryList [get]
func (s *DictionaryApi) GetSysDictionaryList(c *gin.Context) {
var pageInfo request.SysDictionarySearch
_ = c.ShouldBindQuery(&pageInfo)
if err := utils.Verify(pageInfo.PageInfo, utils.PageInfoVerify); err != nil {
err := c.ShouldBindJSON(&dictionary)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, list, total := dictionaryService.GetSysDictionaryInfoList(pageInfo); err != nil {
err = dictionaryService.CreateSysDictionary(dictionary)
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
return
}
response.OkWithMessage("创建成功", c)
}
// DeleteSysDictionary
// @Tags SysDictionary
// @Summary 删除SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionary true "SysDictionary模型"
// @Success 200 {object} response.Response{msg=string} "删除SysDictionary"
// @Router /sysDictionary/deleteSysDictionary [delete]
func (s *DictionaryApi) DeleteSysDictionary(c *gin.Context) {
var dictionary system.SysDictionary
err := c.ShouldBindJSON(&dictionary)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = dictionaryService.DeleteSysDictionary(dictionary)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
return
}
response.OkWithMessage("删除成功", c)
}
// UpdateSysDictionary
// @Tags SysDictionary
// @Summary 更新SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionary true "SysDictionary模型"
// @Success 200 {object} response.Response{msg=string} "更新SysDictionary"
// @Router /sysDictionary/updateSysDictionary [put]
func (s *DictionaryApi) UpdateSysDictionary(c *gin.Context) {
var dictionary system.SysDictionary
err := c.ShouldBindJSON(&dictionary)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = dictionaryService.UpdateSysDictionary(&dictionary)
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败", c)
return
}
response.OkWithMessage("更新成功", c)
}
// FindSysDictionary
// @Tags SysDictionary
// @Summary 用id查询SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query system.SysDictionary true "ID或字典英名"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "用id查询SysDictionary"
// @Router /sysDictionary/findSysDictionary [get]
func (s *DictionaryApi) FindSysDictionary(c *gin.Context) {
var dictionary system.SysDictionary
err := c.ShouldBindQuery(&dictionary)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
sysDictionary, err := dictionaryService.GetSysDictionary(dictionary.Type, dictionary.ID, dictionary.Status)
if err != nil {
global.GVA_LOG.Error("字典未创建或未开启!", zap.Error(err))
response.FailWithMessage("字典未创建或未开启", c)
return
}
response.OkWithDetailed(gin.H{"resysDictionary": sysDictionary}, "查询成功", c)
}
// GetSysDictionaryList
// @Tags SysDictionary
// @Summary 分页获取SysDictionary列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.SysDictionarySearch true "字典 name 或者 type"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取SysDictionary列表,返回包括列表,总数,页码,每页数量"
// @Router /sysDictionary/getSysDictionaryList [get]
func (s *DictionaryApi) GetSysDictionaryList(c *gin.Context) {
var dictionary request.SysDictionarySearch
err := c.ShouldBindQuery(&dictionary)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, err := dictionaryService.GetSysDictionaryInfoList(c, dictionary)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
return
}
response.OkWithDetailed(list, "获取成功", c)
}
// ExportSysDictionary
// @Tags SysDictionary
// @Summary 导出字典JSON(包含字典详情)
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query system.SysDictionary true "字典ID"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "导出字典JSON"
// @Router /sysDictionary/exportSysDictionary [get]
func (s *DictionaryApi) ExportSysDictionary(c *gin.Context) {
var dictionary system.SysDictionary
err := c.ShouldBindQuery(&dictionary)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if dictionary.ID == 0 {
response.FailWithMessage("字典ID不能为空", c)
return
}
exportData, err := dictionaryService.ExportSysDictionary(dictionary.ID)
if err != nil {
global.GVA_LOG.Error("导出失败!", zap.Error(err))
response.FailWithMessage("导出失败", c)
return
}
response.OkWithDetailed(exportData, "导出成功", c)
}
// ImportSysDictionary
// @Tags SysDictionary
// @Summary 导入字典JSON(包含字典详情)
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.ImportSysDictionaryRequest true "字典JSON数据"
// @Success 200 {object} response.Response{msg=string} "导入字典"
// @Router /sysDictionary/importSysDictionary [post]
func (s *DictionaryApi) ImportSysDictionary(c *gin.Context) {
var req request.ImportSysDictionaryRequest
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = dictionaryService.ImportSysDictionary(req.Json)
if err != nil {
global.GVA_LOG.Error("导入失败!", zap.Error(err))
response.FailWithMessage("导入失败: "+err.Error(), c)
return
}
response.OkWithMessage("导入成功", c)
}
+239 -89
View File
@@ -1,6 +1,8 @@
package system
import (
"strconv"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
@@ -12,106 +14,254 @@ import (
type DictionaryDetailApi struct{}
// @Tags SysDictionaryDetail
// @Summary 创建SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionaryDetail true "SysDictionaryDetail模型"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /sysDictionaryDetail/createSysDictionaryDetail [post]
// CreateSysDictionaryDetail
// @Tags SysDictionaryDetail
// @Summary 创建SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionaryDetail true "SysDictionaryDetail模型"
// @Success 200 {object} response.Response{msg=string} "创建SysDictionaryDetail"
// @Router /sysDictionaryDetail/createSysDictionaryDetail [post]
func (s *DictionaryDetailApi) CreateSysDictionaryDetail(c *gin.Context) {
var detail system.SysDictionaryDetail
_ = c.ShouldBindJSON(&detail)
if err := dictionaryDetailService.CreateSysDictionaryDetail(detail); err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
} else {
response.OkWithMessage("创建成功", c)
}
}
// @Tags SysDictionaryDetail
// @Summary 删除SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionaryDetail true "SysDictionaryDetail模型"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysDictionaryDetail/deleteSysDictionaryDetail [delete]
func (s *DictionaryDetailApi) DeleteSysDictionaryDetail(c *gin.Context) {
var detail system.SysDictionaryDetail
_ = c.ShouldBindJSON(&detail)
if err := dictionaryDetailService.DeleteSysDictionaryDetail(detail); err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
}
}
// @Tags SysDictionaryDetail
// @Summary 更新SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionaryDetail true "更新SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysDictionaryDetail/updateSysDictionaryDetail [put]
func (s *DictionaryDetailApi) UpdateSysDictionaryDetail(c *gin.Context) {
var detail system.SysDictionaryDetail
_ = c.ShouldBindJSON(&detail)
if err := dictionaryDetailService.UpdateSysDictionaryDetail(&detail); err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败", c)
} else {
response.OkWithMessage("更新成功", c)
}
}
// @Tags SysDictionaryDetail
// @Summary 用id查询SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query system.SysDictionaryDetail true "用id查询SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysDictionaryDetail/findSysDictionaryDetail [get]
func (s *DictionaryDetailApi) FindSysDictionaryDetail(c *gin.Context) {
var detail system.SysDictionaryDetail
_ = c.ShouldBindQuery(&detail)
if err := utils.Verify(detail, utils.IdVerify); err != nil {
err := c.ShouldBindJSON(&detail)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, resysDictionaryDetail := dictionaryDetailService.GetSysDictionaryDetail(detail.ID); err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败", c)
} else {
response.OkWithDetailed(gin.H{"resysDictionaryDetail": resysDictionaryDetail}, "查询成功", c)
err = dictionaryDetailService.CreateSysDictionaryDetail(detail)
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
return
}
response.OkWithMessage("创建成功", c)
}
// @Tags SysDictionaryDetail
// @Summary 分页获取SysDictionaryDetail列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.SysDictionaryDetailSearch true "页码, 每页大小, 搜索条件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionaryDetail/getSysDictionaryDetailList [get]
// DeleteSysDictionaryDetail
// @Tags SysDictionaryDetail
// @Summary 删除SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionaryDetail true "SysDictionaryDetail模型"
// @Success 200 {object} response.Response{msg=string} "删除SysDictionaryDetail"
// @Router /sysDictionaryDetail/deleteSysDictionaryDetail [delete]
func (s *DictionaryDetailApi) DeleteSysDictionaryDetail(c *gin.Context) {
var detail system.SysDictionaryDetail
err := c.ShouldBindJSON(&detail)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = dictionaryDetailService.DeleteSysDictionaryDetail(detail)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
return
}
response.OkWithMessage("删除成功", c)
}
// UpdateSysDictionaryDetail
// @Tags SysDictionaryDetail
// @Summary 更新SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysDictionaryDetail true "更新SysDictionaryDetail"
// @Success 200 {object} response.Response{msg=string} "更新SysDictionaryDetail"
// @Router /sysDictionaryDetail/updateSysDictionaryDetail [put]
func (s *DictionaryDetailApi) UpdateSysDictionaryDetail(c *gin.Context) {
var detail system.SysDictionaryDetail
err := c.ShouldBindJSON(&detail)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = dictionaryDetailService.UpdateSysDictionaryDetail(&detail)
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败", c)
return
}
response.OkWithMessage("更新成功", c)
}
// FindSysDictionaryDetail
// @Tags SysDictionaryDetail
// @Summary 用id查询SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query system.SysDictionaryDetail true "用id查询SysDictionaryDetail"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "用id查询SysDictionaryDetail"
// @Router /sysDictionaryDetail/findSysDictionaryDetail [get]
func (s *DictionaryDetailApi) FindSysDictionaryDetail(c *gin.Context) {
var detail system.SysDictionaryDetail
err := c.ShouldBindQuery(&detail)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(detail, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
reSysDictionaryDetail, err := dictionaryDetailService.GetSysDictionaryDetail(detail.ID)
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败", c)
return
}
response.OkWithDetailed(gin.H{"reSysDictionaryDetail": reSysDictionaryDetail}, "查询成功", c)
}
// GetSysDictionaryDetailList
// @Tags SysDictionaryDetail
// @Summary 分页获取SysDictionaryDetail列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.SysDictionaryDetailSearch true "页码, 每页大小, 搜索条件"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取SysDictionaryDetail列表,返回包括列表,总数,页码,每页数量"
// @Router /sysDictionaryDetail/getSysDictionaryDetailList [get]
func (s *DictionaryDetailApi) GetSysDictionaryDetailList(c *gin.Context) {
var pageInfo request.SysDictionaryDetailSearch
_ = c.ShouldBindQuery(&pageInfo)
if err, list, total := dictionaryDetailService.GetSysDictionaryDetailInfoList(pageInfo); err != nil {
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := dictionaryDetailService.GetSysDictionaryDetailInfoList(pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
// GetDictionaryTreeList
// @Tags SysDictionaryDetail
// @Summary 获取字典详情树形结构
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param sysDictionaryID query int true "字典ID"
// @Success 200 {object} response.Response{data=[]system.SysDictionaryDetail,msg=string} "获取字典详情树形结构"
// @Router /sysDictionaryDetail/getDictionaryTreeList [get]
func (s *DictionaryDetailApi) GetDictionaryTreeList(c *gin.Context) {
sysDictionaryID := c.Query("sysDictionaryID")
if sysDictionaryID == "" {
response.FailWithMessage("字典ID不能为空", c)
return
}
var id uint
if idUint64, err := strconv.ParseUint(sysDictionaryID, 10, 32); err != nil {
response.FailWithMessage("字典ID格式错误", c)
return
} else {
id = uint(idUint64)
}
list, err := dictionaryDetailService.GetDictionaryTreeList(id)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(gin.H{"list": list}, "获取成功", c)
}
// GetDictionaryTreeListByType
// @Tags SysDictionaryDetail
// @Summary 根据字典类型获取字典详情树形结构
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param type query string true "字典类型"
// @Success 200 {object} response.Response{data=[]system.SysDictionaryDetail,msg=string} "获取字典详情树形结构"
// @Router /sysDictionaryDetail/getDictionaryTreeListByType [get]
func (s *DictionaryDetailApi) GetDictionaryTreeListByType(c *gin.Context) {
dictType := c.Query("type")
if dictType == "" {
response.FailWithMessage("字典类型不能为空", c)
return
}
list, err := dictionaryDetailService.GetDictionaryTreeListByType(dictType)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(gin.H{"list": list}, "获取成功", c)
}
// GetDictionaryDetailsByParent
// @Tags SysDictionaryDetail
// @Summary 根据父级ID获取字典详情
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.GetDictionaryDetailsByParentRequest true "查询参数"
// @Success 200 {object} response.Response{data=[]system.SysDictionaryDetail,msg=string} "获取字典详情列表"
// @Router /sysDictionaryDetail/getDictionaryDetailsByParent [get]
func (s *DictionaryDetailApi) GetDictionaryDetailsByParent(c *gin.Context) {
var req request.GetDictionaryDetailsByParentRequest
err := c.ShouldBindQuery(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, err := dictionaryDetailService.GetDictionaryDetailsByParent(req)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(gin.H{"list": list}, "获取成功", c)
}
// GetDictionaryPath
// @Tags SysDictionaryDetail
// @Summary 获取字典详情的完整路径
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param id query uint true "字典详情ID"
// @Success 200 {object} response.Response{data=[]system.SysDictionaryDetail,msg=string} "获取字典详情路径"
// @Router /sysDictionaryDetail/getDictionaryPath [get]
func (s *DictionaryDetailApi) GetDictionaryPath(c *gin.Context) {
idStr := c.Query("id")
if idStr == "" {
response.FailWithMessage("字典详情ID不能为空", c)
return
}
var id uint
if idUint64, err := strconv.ParseUint(idStr, 10, 32); err != nil {
response.FailWithMessage("字典详情ID格式错误", c)
return
} else {
id = uint(idUint64)
}
path, err := dictionaryDetailService.GetDictionaryPath(id)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(gin.H{"path": path}, "获取成功", c)
}
+199
View File
@@ -0,0 +1,199 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type SysErrorApi struct{}
// CreateSysError 创建错误日志
// @Tags SysError
// @Summary 创建错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body system.SysError true "创建错误日志"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /sysError/createSysError [post]
func (sysErrorApi *SysErrorApi) CreateSysError(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
var sysError system.SysError
err := c.ShouldBindJSON(&sysError)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = sysErrorService.CreateSysError(ctx, &sysError)
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败:"+err.Error(), c)
return
}
response.OkWithMessage("创建成功", c)
}
// DeleteSysError 删除错误日志
// @Tags SysError
// @Summary 删除错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body system.SysError true "删除错误日志"
// @Success 200 {object} response.Response{msg=string} "删除成功"
// @Router /sysError/deleteSysError [delete]
func (sysErrorApi *SysErrorApi) DeleteSysError(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
ID := c.Query("ID")
err := sysErrorService.DeleteSysError(ctx, ID)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败:"+err.Error(), c)
return
}
response.OkWithMessage("删除成功", c)
}
// DeleteSysErrorByIds 批量删除错误日志
// @Tags SysError
// @Summary 批量删除错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "批量删除成功"
// @Router /sysError/deleteSysErrorByIds [delete]
func (sysErrorApi *SysErrorApi) DeleteSysErrorByIds(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
IDs := c.QueryArray("IDs[]")
err := sysErrorService.DeleteSysErrorByIds(ctx, IDs)
if err != nil {
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
response.FailWithMessage("批量删除失败:"+err.Error(), c)
return
}
response.OkWithMessage("批量删除成功", c)
}
// UpdateSysError 更新错误日志
// @Tags SysError
// @Summary 更新错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body system.SysError true "更新错误日志"
// @Success 200 {object} response.Response{msg=string} "更新成功"
// @Router /sysError/updateSysError [put]
func (sysErrorApi *SysErrorApi) UpdateSysError(c *gin.Context) {
// 从ctx获取标准context进行业务行为
ctx := c.Request.Context()
var sysError system.SysError
err := c.ShouldBindJSON(&sysError)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = sysErrorService.UpdateSysError(ctx, sysError)
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败:"+err.Error(), c)
return
}
response.OkWithMessage("更新成功", c)
}
// FindSysError 用id查询错误日志
// @Tags SysError
// @Summary 用id查询错误日志
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param ID query uint true "用id查询错误日志"
// @Success 200 {object} response.Response{data=system.SysError,msg=string} "查询成功"
// @Router /sysError/findSysError [get]
func (sysErrorApi *SysErrorApi) FindSysError(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
ID := c.Query("ID")
resysError, err := sysErrorService.GetSysError(ctx, ID)
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败:"+err.Error(), c)
return
}
response.OkWithData(resysError, c)
}
// GetSysErrorList 分页获取错误日志列表
// @Tags SysError
// @Summary 分页获取错误日志列表
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query systemReq.SysErrorSearch true "分页获取错误日志列表"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /sysError/getSysErrorList [get]
func (sysErrorApi *SysErrorApi) GetSysErrorList(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
var pageInfo systemReq.SysErrorSearch
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := sysErrorService.GetSysErrorInfoList(ctx, pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:"+err.Error(), c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
// GetSysErrorSolution 触发错误日志的异步处理
// @Tags SysError
// @Summary 根据ID触发处理:标记为处理中,1分钟后自动改为处理完成
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param id query string true "错误日志ID"
// @Success 200 {object} response.Response{msg=string} "处理已提交"
// @Router /sysError/getSysErrorSolution [get]
func (sysErrorApi *SysErrorApi) GetSysErrorSolution(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
// 兼容 id 与 ID 两种参数
ID := c.Query("id")
if ID == "" {
response.FailWithMessage("缺少参数: id", c)
return
}
err := sysErrorService.GetSysErrorSolution(ctx, ID)
if err != nil {
global.GVA_LOG.Error("处理触发失败!", zap.Error(err))
response.FailWithMessage("处理触发失败:"+err.Error(), c)
return
}
response.OkWithMessage("已提交至AI处理", c)
}
+456
View File
@@ -0,0 +1,456 @@
package system
import (
"fmt"
"net/http"
"net/url"
"sync"
"time"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/flipped-aurora/gin-vue-admin/server/service"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// 用于token一次性存储
var (
exportTokenCache = make(map[string]interface{})
exportTokenExpiration = make(map[string]time.Time)
tokenMutex sync.RWMutex
)
// 五分钟检测窗口过期
func cleanupExpiredTokens() {
for {
time.Sleep(5 * time.Minute)
tokenMutex.Lock()
now := time.Now()
for token, expiry := range exportTokenExpiration {
if now.After(expiry) {
delete(exportTokenCache, token)
delete(exportTokenExpiration, token)
}
}
tokenMutex.Unlock()
}
}
func init() {
go cleanupExpiredTokens()
}
type SysExportTemplateApi struct {
}
var sysExportTemplateService = service.ServiceGroupApp.SystemServiceGroup.SysExportTemplateService
// PreviewSQL 预览最终生成的SQL
// @Tags SysExportTemplate
// @Summary 预览最终生成的SQL(不执行查询,仅返回SQL字符串)
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param templateID query string true "导出模板ID"
// @Param params query string false "查询参数编码字符串,参考 ExportExcel 组件"
// @Success 200 {object} response.Response{data=map[string]string} "获取成功"
// @Router /sysExportTemplate/previewSQL [get]
func (sysExportTemplateApi *SysExportTemplateApi) PreviewSQL(c *gin.Context) {
templateID := c.Query("templateID")
if templateID == "" {
response.FailWithMessage("模板ID不能为空", c)
return
}
// 直接复用导出接口的参数组织方式:使用 URL Query,其中 params 为内部编码的查询字符串
queryParams := c.Request.URL.Query()
if sqlPreview, err := sysExportTemplateService.PreviewSQL(templateID, queryParams); err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithData(gin.H{"sql": sqlPreview}, c)
}
}
// CreateSysExportTemplate 创建导出模板
// @Tags SysExportTemplate
// @Summary 创建导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysExportTemplate true "创建导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /sysExportTemplate/createSysExportTemplate [post]
func (sysExportTemplateApi *SysExportTemplateApi) CreateSysExportTemplate(c *gin.Context) {
var sysExportTemplate system.SysExportTemplate
err := c.ShouldBindJSON(&sysExportTemplate)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
verify := utils.Rules{
"Name": {utils.NotEmpty()},
}
if err := utils.Verify(sysExportTemplate, verify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := sysExportTemplateService.CreateSysExportTemplate(&sysExportTemplate); err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
} else {
response.OkWithMessage("创建成功", c)
}
}
// DeleteSysExportTemplate 删除导出模板
// @Tags SysExportTemplate
// @Summary 删除导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysExportTemplate true "删除导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysExportTemplate/deleteSysExportTemplate [delete]
func (sysExportTemplateApi *SysExportTemplateApi) DeleteSysExportTemplate(c *gin.Context) {
var sysExportTemplate system.SysExportTemplate
err := c.ShouldBindJSON(&sysExportTemplate)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := sysExportTemplateService.DeleteSysExportTemplate(sysExportTemplate); err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
}
}
// DeleteSysExportTemplateByIds 批量删除导出模板
// @Tags SysExportTemplate
// @Summary 批量删除导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"批量删除成功"}"
// @Router /sysExportTemplate/deleteSysExportTemplateByIds [delete]
func (sysExportTemplateApi *SysExportTemplateApi) DeleteSysExportTemplateByIds(c *gin.Context) {
var IDS request.IdsReq
err := c.ShouldBindJSON(&IDS)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := sysExportTemplateService.DeleteSysExportTemplateByIds(IDS); err != nil {
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
response.FailWithMessage("批量删除失败", c)
} else {
response.OkWithMessage("批量删除成功", c)
}
}
// UpdateSysExportTemplate 更新导出模板
// @Tags SysExportTemplate
// @Summary 更新导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysExportTemplate true "更新导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysExportTemplate/updateSysExportTemplate [put]
func (sysExportTemplateApi *SysExportTemplateApi) UpdateSysExportTemplate(c *gin.Context) {
var sysExportTemplate system.SysExportTemplate
err := c.ShouldBindJSON(&sysExportTemplate)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
verify := utils.Rules{
"Name": {utils.NotEmpty()},
}
if err := utils.Verify(sysExportTemplate, verify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := sysExportTemplateService.UpdateSysExportTemplate(sysExportTemplate); err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败", c)
} else {
response.OkWithMessage("更新成功", c)
}
}
// FindSysExportTemplate 用id查询导出模板
// @Tags SysExportTemplate
// @Summary 用id查询导出模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query system.SysExportTemplate true "用id查询导出模板"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysExportTemplate/findSysExportTemplate [get]
func (sysExportTemplateApi *SysExportTemplateApi) FindSysExportTemplate(c *gin.Context) {
var sysExportTemplate system.SysExportTemplate
err := c.ShouldBindQuery(&sysExportTemplate)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if resysExportTemplate, err := sysExportTemplateService.GetSysExportTemplate(sysExportTemplate.ID); err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败", c)
} else {
response.OkWithData(gin.H{"resysExportTemplate": resysExportTemplate}, c)
}
}
// GetSysExportTemplateList 分页获取导出模板列表
// @Tags SysExportTemplate
// @Summary 分页获取导出模板列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query systemReq.SysExportTemplateSearch true "分页获取导出模板列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysExportTemplate/getSysExportTemplateList [get]
func (sysExportTemplateApi *SysExportTemplateApi) GetSysExportTemplateList(c *gin.Context) {
var pageInfo systemReq.SysExportTemplateSearch
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if list, total, err := sysExportTemplateService.GetSysExportTemplateInfoList(pageInfo); err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
}
// ExportExcel 导出表格token
// @Tags SysExportTemplate
// @Summary 导出表格
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportExcel [get]
func (sysExportTemplateApi *SysExportTemplateApi) ExportExcel(c *gin.Context) {
templateID := c.Query("templateID")
if templateID == "" {
response.FailWithMessage("模板ID不能为空", c)
return
}
queryParams := c.Request.URL.Query()
//创造一次性token
token := utils.RandomString(32) // 随机32位
// 记录本次请求参数
exportParams := map[string]interface{}{
"templateID": templateID,
"queryParams": queryParams,
}
// 参数保留记录完成鉴权
tokenMutex.Lock()
exportTokenCache[token] = exportParams
exportTokenExpiration[token] = time.Now().Add(30 * time.Minute)
tokenMutex.Unlock()
// 生成一次性链接
exportUrl := fmt.Sprintf("/sysExportTemplate/exportExcelByToken?token=%s", token)
response.OkWithData(exportUrl, c)
}
// ExportExcelByToken 导出表格
// @Tags ExportExcelByToken
// @Summary 导出表格
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportExcelByToken [get]
func (sysExportTemplateApi *SysExportTemplateApi) ExportExcelByToken(c *gin.Context) {
token := c.Query("token")
if token == "" {
response.FailWithMessage("导出token不能为空", c)
return
}
// 获取token并且从缓存中剔除
tokenMutex.RLock()
exportParamsRaw, exists := exportTokenCache[token]
expiry, _ := exportTokenExpiration[token]
tokenMutex.RUnlock()
if !exists || time.Now().After(expiry) {
global.GVA_LOG.Error("导出token无效或已过期!")
response.FailWithMessage("导出token无效或已过期", c)
return
}
// 从token获取参数
exportParams, ok := exportParamsRaw.(map[string]interface{})
if !ok {
global.GVA_LOG.Error("解析导出参数失败!")
response.FailWithMessage("解析导出参数失败", c)
return
}
// 获取导出参数
templateID := exportParams["templateID"].(string)
queryParams := exportParams["queryParams"].(url.Values)
// 清理一次性token
tokenMutex.Lock()
delete(exportTokenCache, token)
delete(exportTokenExpiration, token)
tokenMutex.Unlock()
// 导出
if file, name, err := sysExportTemplateService.ExportExcel(templateID, queryParams); err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+utils.RandomString(6)+".xlsx"))
c.Header("success", "true")
c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", file.Bytes())
}
}
// ExportTemplate 导出表格模板
// @Tags SysExportTemplate
// @Summary 导出表格模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportTemplate [get]
func (sysExportTemplateApi *SysExportTemplateApi) ExportTemplate(c *gin.Context) {
templateID := c.Query("templateID")
if templateID == "" {
response.FailWithMessage("模板ID不能为空", c)
return
}
// 创造一次性token
token := utils.RandomString(32) // 随机32位
// 记录本次请求参数
exportParams := map[string]interface{}{
"templateID": templateID,
"isTemplate": true,
}
// 参数保留记录完成鉴权
tokenMutex.Lock()
exportTokenCache[token] = exportParams
exportTokenExpiration[token] = time.Now().Add(30 * time.Minute)
tokenMutex.Unlock()
// 生成一次性链接
exportUrl := fmt.Sprintf("/sysExportTemplate/exportTemplateByToken?token=%s", token)
response.OkWithData(exportUrl, c)
}
// ExportTemplateByToken 通过token导出表格模板
// @Tags ExportTemplateByToken
// @Summary 通过token导出表格模板
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/exportTemplateByToken [get]
func (sysExportTemplateApi *SysExportTemplateApi) ExportTemplateByToken(c *gin.Context) {
token := c.Query("token")
if token == "" {
response.FailWithMessage("导出token不能为空", c)
return
}
// 获取token并且从缓存中剔除
tokenMutex.RLock()
exportParamsRaw, exists := exportTokenCache[token]
expiry, _ := exportTokenExpiration[token]
tokenMutex.RUnlock()
if !exists || time.Now().After(expiry) {
global.GVA_LOG.Error("导出token无效或已过期!")
response.FailWithMessage("导出token无效或已过期", c)
return
}
// 从token获取参数
exportParams, ok := exportParamsRaw.(map[string]interface{})
if !ok {
global.GVA_LOG.Error("解析导出参数失败!")
response.FailWithMessage("解析导出参数失败", c)
return
}
// 检查是否为模板导出
isTemplate, _ := exportParams["isTemplate"].(bool)
if !isTemplate {
global.GVA_LOG.Error("token类型错误!")
response.FailWithMessage("token类型错误", c)
return
}
// 获取导出参数
templateID := exportParams["templateID"].(string)
// 清理一次性token
tokenMutex.Lock()
delete(exportTokenCache, token)
delete(exportTokenExpiration, token)
tokenMutex.Unlock()
// 导出模板
if file, name, err := sysExportTemplateService.ExportTemplate(templateID); err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name+"模板.xlsx"))
c.Header("success", "true")
c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", file.Bytes())
}
}
// ImportExcel 导入表格
// @Tags SysImportTemplate
// @Summary 导入表格
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Router /sysExportTemplate/importExcel [post]
func (sysExportTemplateApi *SysExportTemplateApi) ImportExcel(c *gin.Context) {
templateID := c.Query("templateID")
if templateID == "" {
response.FailWithMessage("模板ID不能为空", c)
return
}
file, err := c.FormFile("file")
if err != nil {
global.GVA_LOG.Error("文件获取失败!", zap.Error(err))
response.FailWithMessage("文件获取失败", c)
return
}
if err := sysExportTemplateService.ImportExcel(templateID, file); err != nil {
global.GVA_LOG.Error(err.Error(), zap.Error(err))
response.FailWithMessage(err.Error(), c)
} else {
response.OkWithMessage("导入成功", c)
}
}
+19 -17
View File
@@ -12,12 +12,12 @@ import (
type DBApi struct{}
// InitDB
// @Tags InitDB
// @Summary 初始化用户数据库
// @Tags InitDB
// @Summary 初始化用户数据库
// @Produce application/json
// @Param data body request.InitDB true "初始化数据库参数"
// @Success 200 {string} string "{"code":0,"data":{},"msg":"自动创建数据库成功"}"
// @Router /init/initdb [post]
// @Param data body request.InitDB true "初始化数据库参数"
// @Success 200 {object} response.Response{data=string} "初始化用户数据库"
// @Router /init/initdb [post]
func (i *DBApi) InitDB(c *gin.Context) {
if global.GVA_DB != nil {
global.GVA_LOG.Error("已存在数据库配置!")
@@ -35,23 +35,25 @@ func (i *DBApi) InitDB(c *gin.Context) {
response.FailWithMessage("自动创建数据库失败,请查看后台日志,检查后在进行初始化", c)
return
}
response.OkWithData("自动创建数据库成功", c)
response.OkWithMessage("自动创建数据库成功", c)
}
// CheckDB
// @Tags CheckDB
// @Summary 初始化用户数据库
// @Tags CheckDB
// @Summary 初始化用户数据库
// @Produce application/json
// @Success 200 {string} string "{"code":0,"data":{},"msg":"探测完成"}"
// @Router /init/checkdb [post]
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "初始化用户数据库"
// @Router /init/checkdb [post]
func (i *DBApi) CheckDB(c *gin.Context) {
var (
message = "前往初始化数据库"
needInit = true
)
if global.GVA_DB != nil {
global.GVA_LOG.Info("数据库无需初始化")
response.OkWithDetailed(gin.H{"needInit": false}, "数据库无需初始化", c)
return
} else {
global.GVA_LOG.Info("前往初始化数据库")
response.OkWithDetailed(gin.H{"needInit": true}, "前往初始化数据库", c)
return
message = "数据库无需初始化"
needInit = false
}
global.GVA_LOG.Info(message)
response.OkWithDetailed(gin.H{"needInit": needInit}, message, c)
}
+15 -11
View File
@@ -4,26 +4,30 @@ import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type JwtApi struct{}
// @Tags Jwt
// @Summary jwt加入黑名单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}"
// @Router /jwt/jsonInBlacklist [post]
// JsonInBlacklist
// @Tags Jwt
// @Summary jwt加入黑名单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "jwt加入黑名单"
// @Router /jwt/jsonInBlacklist [post]
func (j *JwtApi) JsonInBlacklist(c *gin.Context) {
token := c.Request.Header.Get("x-token")
token := utils.GetToken(c)
jwt := system.JwtBlacklist{Jwt: token}
if err := jwtService.JsonInBlacklist(jwt); err != nil {
err := jwtService.JsonInBlacklist(jwt)
if err != nil {
global.GVA_LOG.Error("jwt作废失败!", zap.Error(err))
response.FailWithMessage("jwt作废失败", c)
} else {
response.OkWithMessage("jwt作废成功", c)
return
}
utils.ClearToken(c)
response.OkWithMessage("jwt作废成功", c)
}
+82
View File
@@ -0,0 +1,82 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type LoginLogApi struct{}
func (s *LoginLogApi) DeleteLoginLog(c *gin.Context) {
var loginLog system.SysLoginLog
err := c.ShouldBindJSON(&loginLog)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = loginLogService.DeleteLoginLog(loginLog)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
return
}
response.OkWithMessage("删除成功", c)
}
func (s *LoginLogApi) DeleteLoginLogByIds(c *gin.Context) {
var SDS request.IdsReq
err := c.ShouldBindJSON(&SDS)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = loginLogService.DeleteLoginLogByIds(SDS)
if err != nil {
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
response.FailWithMessage("批量删除失败", c)
return
}
response.OkWithMessage("批量删除成功", c)
}
func (s *LoginLogApi) FindLoginLog(c *gin.Context) {
var loginLog system.SysLoginLog
err := c.ShouldBindQuery(&loginLog)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
reLoginLog, err := loginLogService.GetLoginLog(loginLog.ID)
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败", c)
return
}
response.OkWithDetailed(reLoginLog, "查询成功", c)
}
func (s *LoginLogApi) GetLoginLogList(c *gin.Context) {
var pageInfo systemReq.SysLoginLogSearch
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := loginLogService.GetLoginLogInfoList(pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
+165 -126
View File
@@ -15,57 +15,68 @@ import (
type AuthorityMenuApi struct{}
// @Tags AuthorityMenu
// @Summary 获取用户动态路由
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body request.Empty true "空"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /menu/getMenu [post]
// GetMenu
// @Tags AuthorityMenu
// @Summary 获取用户动态路由
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body request.Empty true "空"
// @Success 200 {object} response.Response{data=systemRes.SysMenusResponse,msg=string} "获取用户动态路由,返回包括系统菜单详情列表"
// @Router /menu/getMenu [post]
func (a *AuthorityMenuApi) GetMenu(c *gin.Context) {
if err, menus := menuService.GetMenuTree(utils.GetUserAuthorityId(c)); err != nil {
menus, err := menuService.GetMenuTree(utils.GetUserAuthorityId(c))
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
if menus == nil {
menus = []system.SysMenu{}
}
response.OkWithDetailed(systemRes.SysMenusResponse{Menus: menus}, "获取成功", c)
return
}
if menus == nil {
menus = []system.SysMenu{}
}
response.OkWithDetailed(systemRes.SysMenusResponse{Menus: menus}, "获取成功", c)
}
// @Tags AuthorityMenu
// @Summary 获取用户动态路由
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body request.Empty true "空"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /menu/getBaseMenuTree [post]
// GetBaseMenuTree
// @Tags AuthorityMenu
// @Summary 获取用户动态路由
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body request.Empty true "空"
// @Success 200 {object} response.Response{data=systemRes.SysBaseMenusResponse,msg=string} "获取用户动态路由,返回包括系统菜单列表"
// @Router /menu/getBaseMenuTree [post]
func (a *AuthorityMenuApi) GetBaseMenuTree(c *gin.Context) {
if err, menus := menuService.GetBaseMenuTree(); err != nil {
authority := utils.GetUserAuthorityId(c)
menus, err := menuService.GetBaseMenuTree(authority)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(systemRes.SysBaseMenusResponse{Menus: menus}, "获取成功", c)
return
}
response.OkWithDetailed(systemRes.SysBaseMenusResponse{Menus: menus}, "获取成功", c)
}
// @Tags AuthorityMenu
// @Summary 增加menu和角色关联关系
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.AddMenuAuthorityInfo true "角色ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"添加成功"}"
// @Router /menu/addMenuAuthority [post]
// AddMenuAuthority
// @Tags AuthorityMenu
// @Summary 增加menu和角色关联关系
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.AddMenuAuthorityInfo true "角色ID"
// @Success 200 {object} response.Response{msg=string} "增加menu和角色关联关系"
// @Router /menu/addMenuAuthority [post]
func (a *AuthorityMenuApi) AddMenuAuthority(c *gin.Context) {
var authorityMenu systemReq.AddMenuAuthorityInfo
_ = c.ShouldBindJSON(&authorityMenu)
err := c.ShouldBindJSON(&authorityMenu)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := utils.Verify(authorityMenu, utils.AuthorityIdVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := menuService.AddMenuAuthority(authorityMenu.Menus, authorityMenu.AuthorityId); err != nil {
adminAuthorityID := utils.GetUserAuthorityId(c)
if err := menuService.AddMenuAuthority(authorityMenu.Menus, adminAuthorityID, authorityMenu.AuthorityId); err != nil {
global.GVA_LOG.Error("添加失败!", zap.Error(err))
response.FailWithMessage("添加失败", c)
} else {
@@ -73,154 +84,182 @@ func (a *AuthorityMenuApi) AddMenuAuthority(c *gin.Context) {
}
}
// @Tags AuthorityMenu
// @Summary 获取指定角色menu
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetAuthorityId true "角色ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /menu/getMenuAuthority [post]
// GetMenuAuthority
// @Tags AuthorityMenu
// @Summary 获取指定角色menu
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetAuthorityId true "角色ID"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取指定角色menu"
// @Router /menu/getMenuAuthority [post]
func (a *AuthorityMenuApi) GetMenuAuthority(c *gin.Context) {
var param request.GetAuthorityId
_ = c.ShouldBindJSON(&param)
if err := utils.Verify(param, utils.AuthorityIdVerify); err != nil {
err := c.ShouldBindJSON(&param)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, menus := menuService.GetMenuAuthority(&param); err != nil {
err = utils.Verify(param, utils.AuthorityIdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
menus, err := menuService.GetMenuAuthority(&param)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithDetailed(systemRes.SysMenusResponse{Menus: menus}, "获取失败", c)
} else {
response.OkWithDetailed(gin.H{"menus": menus}, "获取成功", c)
return
}
response.OkWithDetailed(gin.H{"menus": menus}, "获取成功", c)
}
// @Tags Menu
// @Summary 新增菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysBaseMenu true "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"添加成功"}"
// @Router /menu/addBaseMenu [post]
// AddBaseMenu
// @Tags Menu
// @Summary 新增菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysBaseMenu true "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记"
// @Success 200 {object} response.Response{msg=string} "新增菜单"
// @Router /menu/addBaseMenu [post]
func (a *AuthorityMenuApi) AddBaseMenu(c *gin.Context) {
var menu system.SysBaseMenu
_ = c.ShouldBindJSON(&menu)
if err := utils.Verify(menu, utils.MenuVerify); err != nil {
err := c.ShouldBindJSON(&menu)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := utils.Verify(menu.Meta, utils.MenuMetaVerify); err != nil {
err = utils.Verify(menu, utils.MenuVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := menuService.AddBaseMenu(menu); err != nil {
err = utils.Verify(menu.Meta, utils.MenuMetaVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = menuService.AddBaseMenu(menu)
if err != nil {
global.GVA_LOG.Error("添加失败!", zap.Error(err))
response.FailWithMessage("添加失败", c)
} else {
response.OkWithMessage("添加成功", c)
response.FailWithMessage("添加失败:"+err.Error(), c)
return
}
response.OkWithMessage("添加成功", c)
}
// @Tags Menu
// @Summary 删除菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "菜单id"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /menu/deleteBaseMenu [post]
// DeleteBaseMenu
// @Tags Menu
// @Summary 删除菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "菜单id"
// @Success 200 {object} response.Response{msg=string} "删除菜单"
// @Router /menu/deleteBaseMenu [post]
func (a *AuthorityMenuApi) DeleteBaseMenu(c *gin.Context) {
var menu request.GetById
_ = c.ShouldBindJSON(&menu)
if err := utils.Verify(menu, utils.IdVerify); err != nil {
err := c.ShouldBindJSON(&menu)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := baseMenuService.DeleteBaseMenu(menu.ID); err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
err = utils.Verify(menu, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = baseMenuService.DeleteBaseMenu(menu.ID)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败:"+err.Error(), c)
return
}
response.OkWithMessage("删除成功", c)
}
// @Tags Menu
// @Summary 更新菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysBaseMenu true "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /menu/updateBaseMenu [post]
// UpdateBaseMenu
// @Tags Menu
// @Summary 更新菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysBaseMenu true "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记"
// @Success 200 {object} response.Response{msg=string} "更新菜单"
// @Router /menu/updateBaseMenu [post]
func (a *AuthorityMenuApi) UpdateBaseMenu(c *gin.Context) {
var menu system.SysBaseMenu
_ = c.ShouldBindJSON(&menu)
if err := utils.Verify(menu, utils.MenuVerify); err != nil {
err := c.ShouldBindJSON(&menu)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := utils.Verify(menu.Meta, utils.MenuMetaVerify); err != nil {
err = utils.Verify(menu, utils.MenuVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := baseMenuService.UpdateBaseMenu(menu); err != nil {
err = utils.Verify(menu.Meta, utils.MenuMetaVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = baseMenuService.UpdateBaseMenu(menu)
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败", c)
} else {
response.OkWithMessage("更新成功", c)
return
}
response.OkWithMessage("更新成功", c)
}
// @Tags Menu
// @Summary 根据id获取菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "菜单id"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /menu/getBaseMenuById [post]
// GetBaseMenuById
// @Tags Menu
// @Summary 根据id获取菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "菜单id"
// @Success 200 {object} response.Response{data=systemRes.SysBaseMenuResponse,msg=string} "根据id获取菜单,返回包括系统菜单列表"
// @Router /menu/getBaseMenuById [post]
func (a *AuthorityMenuApi) GetBaseMenuById(c *gin.Context) {
var idInfo request.GetById
_ = c.ShouldBindJSON(&idInfo)
if err := utils.Verify(idInfo, utils.IdVerify); err != nil {
err := c.ShouldBindJSON(&idInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, menu := baseMenuService.GetBaseMenuById(idInfo.ID); err != nil {
err = utils.Verify(idInfo, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
menu, err := baseMenuService.GetBaseMenuById(idInfo.ID)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(systemRes.SysBaseMenuResponse{Menu: menu}, "获取成功", c)
return
}
response.OkWithDetailed(systemRes.SysBaseMenuResponse{Menu: menu}, "获取成功", c)
}
// @Tags Menu
// @Summary 分页获取基础menu列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "页码, 每页大小"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /menu/getMenuList [post]
// GetMenuList
// @Tags Menu
// @Summary 分页获取基础menu列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "页码, 每页大小"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取基础menu列表,返回包括列表,总数,页码,每页数量"
// @Router /menu/getMenuList [post]
func (a *AuthorityMenuApi) GetMenuList(c *gin.Context) {
var pageInfo request.PageInfo
_ = c.ShouldBindJSON(&pageInfo)
if err := utils.Verify(pageInfo, utils.PageInfoVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, menuList, total := menuService.GetInfoList(); err != nil {
authorityID := utils.GetUserAuthorityId(c)
menuList, err := menuService.GetInfoList(authorityID)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: menuList,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
return
}
response.OkWithDetailed(menuList, "获取成功", c)
}
+95 -89
View File
@@ -13,106 +13,112 @@ import (
type OperationRecordApi struct{}
// @Tags SysOperationRecord
// @Summary 创建SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysOperationRecord true "创建SysOperationRecord"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysOperationRecord/createSysOperationRecord [post]
func (s *OperationRecordApi) CreateSysOperationRecord(c *gin.Context) {
var sysOperationRecord system.SysOperationRecord
_ = c.ShouldBindJSON(&sysOperationRecord)
if err := operationRecordService.CreateSysOperationRecord(sysOperationRecord); err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败", c)
} else {
response.OkWithMessage("创建成功", c)
}
}
// @Tags SysOperationRecord
// @Summary 删除SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysOperationRecord true "SysOperationRecord模型"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysOperationRecord/deleteSysOperationRecord [delete]
// DeleteSysOperationRecord
// @Tags SysOperationRecord
// @Summary 删除SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysOperationRecord true "SysOperationRecord模型"
// @Success 200 {object} response.Response{msg=string} "删除SysOperationRecord"
// @Router /sysOperationRecord/deleteSysOperationRecord [delete]
func (s *OperationRecordApi) DeleteSysOperationRecord(c *gin.Context) {
var sysOperationRecord system.SysOperationRecord
_ = c.ShouldBindJSON(&sysOperationRecord)
if err := operationRecordService.DeleteSysOperationRecord(sysOperationRecord); err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
}
}
// @Tags SysOperationRecord
// @Summary 批量删除SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除SysOperationRecord"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"批量删除成功"}"
// @Router /sysOperationRecord/deleteSysOperationRecordByIds [delete]
func (s *OperationRecordApi) DeleteSysOperationRecordByIds(c *gin.Context) {
var IDS request.IdsReq
_ = c.ShouldBindJSON(&IDS)
if err := operationRecordService.DeleteSysOperationRecordByIds(IDS); err != nil {
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
response.FailWithMessage("批量删除失败", c)
} else {
response.OkWithMessage("批量删除成功", c)
}
}
// @Tags SysOperationRecord
// @Summary 用id查询SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query system.SysOperationRecord true "Id"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysOperationRecord/findSysOperationRecord [get]
func (s *OperationRecordApi) FindSysOperationRecord(c *gin.Context) {
var sysOperationRecord system.SysOperationRecord
_ = c.ShouldBindQuery(&sysOperationRecord)
if err := utils.Verify(sysOperationRecord, utils.IdVerify); err != nil {
err := c.ShouldBindJSON(&sysOperationRecord)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, resysOperationRecord := operationRecordService.GetSysOperationRecord(sysOperationRecord.ID); err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败", c)
} else {
response.OkWithDetailed(gin.H{"resysOperationRecord": resysOperationRecord}, "查询成功", c)
err = operationRecordService.DeleteSysOperationRecord(sysOperationRecord)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
return
}
response.OkWithMessage("删除成功", c)
}
// @Tags SysOperationRecord
// @Summary 分页获取SysOperationRecord列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.SysOperationRecordSearch true "页码, 每页大小, 搜索条件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysOperationRecord/getSysOperationRecordList [get]
// DeleteSysOperationRecordByIds
// @Tags SysOperationRecord
// @Summary 批量删除SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除SysOperationRecord"
// @Success 200 {object} response.Response{msg=string} "批量删除SysOperationRecord"
// @Router /sysOperationRecord/deleteSysOperationRecordByIds [delete]
func (s *OperationRecordApi) DeleteSysOperationRecordByIds(c *gin.Context) {
var IDS request.IdsReq
err := c.ShouldBindJSON(&IDS)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = operationRecordService.DeleteSysOperationRecordByIds(IDS)
if err != nil {
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
response.FailWithMessage("批量删除失败", c)
return
}
response.OkWithMessage("批量删除成功", c)
}
// FindSysOperationRecord
// @Tags SysOperationRecord
// @Summary 用id查询SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query system.SysOperationRecord true "Id"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "用id查询SysOperationRecord"
// @Router /sysOperationRecord/findSysOperationRecord [get]
func (s *OperationRecordApi) FindSysOperationRecord(c *gin.Context) {
var sysOperationRecord system.SysOperationRecord
err := c.ShouldBindQuery(&sysOperationRecord)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(sysOperationRecord, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
reSysOperationRecord, err := operationRecordService.GetSysOperationRecord(sysOperationRecord.ID)
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败", c)
return
}
response.OkWithDetailed(gin.H{"reSysOperationRecord": reSysOperationRecord}, "查询成功", c)
}
// GetSysOperationRecordList
// @Tags SysOperationRecord
// @Summary 分页获取SysOperationRecord列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query request.SysOperationRecordSearch true "页码, 每页大小, 搜索条件"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取SysOperationRecord列表,返回包括列表,总数,页码,每页数量"
// @Router /sysOperationRecord/getSysOperationRecordList [get]
func (s *OperationRecordApi) GetSysOperationRecordList(c *gin.Context) {
var pageInfo systemReq.SysOperationRecordSearch
_ = c.ShouldBindQuery(&pageInfo)
if err, list, total := operationRecordService.GetSysOperationRecordInfoList(pageInfo); err != nil {
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := operationRecordService.GetSysOperationRecordInfoList(pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
+171
View File
@@ -0,0 +1,171 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type SysParamsApi struct{}
// CreateSysParams 创建参数
// @Tags SysParams
// @Summary 创建参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysParams true "创建参数"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /sysParams/createSysParams [post]
func (sysParamsApi *SysParamsApi) CreateSysParams(c *gin.Context) {
var sysParams system.SysParams
err := c.ShouldBindJSON(&sysParams)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = sysParamsService.CreateSysParams(&sysParams)
if err != nil {
global.GVA_LOG.Error("创建失败!", zap.Error(err))
response.FailWithMessage("创建失败:"+err.Error(), c)
return
}
response.OkWithMessage("创建成功", c)
}
// DeleteSysParams 删除参数
// @Tags SysParams
// @Summary 删除参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysParams true "删除参数"
// @Success 200 {object} response.Response{msg=string} "删除成功"
// @Router /sysParams/deleteSysParams [delete]
func (sysParamsApi *SysParamsApi) DeleteSysParams(c *gin.Context) {
ID := c.Query("ID")
err := sysParamsService.DeleteSysParams(ID)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败:"+err.Error(), c)
return
}
response.OkWithMessage("删除成功", c)
}
// DeleteSysParamsByIds 批量删除参数
// @Tags SysParams
// @Summary 批量删除参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "批量删除成功"
// @Router /sysParams/deleteSysParamsByIds [delete]
func (sysParamsApi *SysParamsApi) DeleteSysParamsByIds(c *gin.Context) {
IDs := c.QueryArray("IDs[]")
err := sysParamsService.DeleteSysParamsByIds(IDs)
if err != nil {
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
response.FailWithMessage("批量删除失败:"+err.Error(), c)
return
}
response.OkWithMessage("批量删除成功", c)
}
// UpdateSysParams 更新参数
// @Tags SysParams
// @Summary 更新参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysParams true "更新参数"
// @Success 200 {object} response.Response{msg=string} "更新成功"
// @Router /sysParams/updateSysParams [put]
func (sysParamsApi *SysParamsApi) UpdateSysParams(c *gin.Context) {
var sysParams system.SysParams
err := c.ShouldBindJSON(&sysParams)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = sysParamsService.UpdateSysParams(sysParams)
if err != nil {
global.GVA_LOG.Error("更新失败!", zap.Error(err))
response.FailWithMessage("更新失败:"+err.Error(), c)
return
}
response.OkWithMessage("更新成功", c)
}
// FindSysParams 用id查询参数
// @Tags SysParams
// @Summary 用id查询参数
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query system.SysParams true "用id查询参数"
// @Success 200 {object} response.Response{data=system.SysParams,msg=string} "查询成功"
// @Router /sysParams/findSysParams [get]
func (sysParamsApi *SysParamsApi) FindSysParams(c *gin.Context) {
ID := c.Query("ID")
resysParams, err := sysParamsService.GetSysParams(ID)
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败:"+err.Error(), c)
return
}
response.OkWithData(resysParams, c)
}
// GetSysParamsList 分页获取参数列表
// @Tags SysParams
// @Summary 分页获取参数列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data query systemReq.SysParamsSearch true "分页获取参数列表"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /sysParams/getSysParamsList [get]
func (sysParamsApi *SysParamsApi) GetSysParamsList(c *gin.Context) {
var pageInfo systemReq.SysParamsSearch
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := sysParamsService.GetSysParamsInfoList(pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:"+err.Error(), c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
// GetSysParam 根据key获取参数value
// @Tags SysParams
// @Summary 根据key获取参数value
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param key query string true "key"
// @Success 200 {object} response.Response{data=system.SysParams,msg=string} "获取成功"
// @Router /sysParams/getSysParam [get]
func (sysParamsApi *SysParamsApi) GetSysParam(c *gin.Context) {
k := c.Query("key")
params, err := sysParamsService.GetSysParam(k)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:"+err.Error(), c)
return
}
response.OkWithDetailed(params, "获取成功", c)
}
+219
View File
@@ -0,0 +1,219 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type SkillsApi struct{}
func (s *SkillsApi) GetTools(c *gin.Context) {
data, err := skillsService.Tools(c.Request.Context())
if err != nil {
global.GVA_LOG.Error("获取工具列表失败", zap.Error(err))
response.FailWithMessage("获取工具列表失败", c)
return
}
response.OkWithDetailed(gin.H{"tools": data}, "获取成功", c)
}
func (s *SkillsApi) GetSkillList(c *gin.Context) {
var req request.SkillToolRequest
_ = c.ShouldBindJSON(&req)
data, err := skillsService.List(c.Request.Context(), req.Tool)
if err != nil {
global.GVA_LOG.Error("获取技能列表失败", zap.Error(err))
response.FailWithMessage("获取技能列表失败", c)
return
}
response.OkWithDetailed(gin.H{"skills": data}, "获取成功", c)
}
func (s *SkillsApi) GetSkillDetail(c *gin.Context) {
var req request.SkillDetailRequest
_ = c.ShouldBindJSON(&req)
data, err := skillsService.Detail(c.Request.Context(), req.Tool, req.Skill)
if err != nil {
global.GVA_LOG.Error("获取技能详情失败", zap.Error(err))
response.FailWithMessage("获取技能详情失败", c)
return
}
response.OkWithDetailed(gin.H{"detail": data}, "获取成功", c)
}
func (s *SkillsApi) SaveSkill(c *gin.Context) {
var req request.SkillSaveRequest
_ = c.ShouldBindJSON(&req)
if err := skillsService.Save(c.Request.Context(), req); err != nil {
global.GVA_LOG.Error("保存技能失败", zap.Error(err))
response.FailWithMessage("保存技能失败", c)
return
}
response.OkWithMessage("保存成功", c)
}
func (s *SkillsApi) CreateScript(c *gin.Context) {
var req request.SkillScriptCreateRequest
_ = c.ShouldBindJSON(&req)
fileName, content, err := skillsService.CreateScript(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("创建脚本失败", zap.Error(err))
response.FailWithMessage("创建脚本失败", c)
return
}
response.OkWithDetailed(gin.H{"fileName": fileName, "content": content}, "创建成功", c)
}
func (s *SkillsApi) GetScript(c *gin.Context) {
var req request.SkillFileRequest
_ = c.ShouldBindJSON(&req)
content, err := skillsService.GetScript(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("读取脚本失败", zap.Error(err))
response.FailWithMessage("读取脚本失败", c)
return
}
response.OkWithDetailed(gin.H{"content": content}, "获取成功", c)
}
func (s *SkillsApi) SaveScript(c *gin.Context) {
var req request.SkillFileSaveRequest
_ = c.ShouldBindJSON(&req)
if err := skillsService.SaveScript(c.Request.Context(), req); err != nil {
global.GVA_LOG.Error("保存脚本失败", zap.Error(err))
response.FailWithMessage("保存脚本失败", c)
return
}
response.OkWithMessage("保存成功", c)
}
func (s *SkillsApi) CreateResource(c *gin.Context) {
var req request.SkillResourceCreateRequest
_ = c.ShouldBindJSON(&req)
fileName, content, err := skillsService.CreateResource(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("创建资源失败", zap.Error(err))
response.FailWithMessage("创建资源失败", c)
return
}
response.OkWithDetailed(gin.H{"fileName": fileName, "content": content}, "创建成功", c)
}
func (s *SkillsApi) GetResource(c *gin.Context) {
var req request.SkillFileRequest
_ = c.ShouldBindJSON(&req)
content, err := skillsService.GetResource(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("读取资源失败", zap.Error(err))
response.FailWithMessage("读取资源失败", c)
return
}
response.OkWithDetailed(gin.H{"content": content}, "获取成功", c)
}
func (s *SkillsApi) SaveResource(c *gin.Context) {
var req request.SkillFileSaveRequest
_ = c.ShouldBindJSON(&req)
if err := skillsService.SaveResource(c.Request.Context(), req); err != nil {
global.GVA_LOG.Error("保存资源失败", zap.Error(err))
response.FailWithMessage("保存资源失败", c)
return
}
response.OkWithMessage("保存成功", c)
}
func (s *SkillsApi) CreateReference(c *gin.Context) {
var req request.SkillReferenceCreateRequest
_ = c.ShouldBindJSON(&req)
fileName, content, err := skillsService.CreateReference(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("创建参考失败", zap.Error(err))
response.FailWithMessage("创建参考失败", c)
return
}
response.OkWithDetailed(gin.H{"fileName": fileName, "content": content}, "创建成功", c)
}
func (s *SkillsApi) GetReference(c *gin.Context) {
var req request.SkillFileRequest
_ = c.ShouldBindJSON(&req)
content, err := skillsService.GetReference(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("读取参考失败", zap.Error(err))
response.FailWithMessage("读取参考失败", c)
return
}
response.OkWithDetailed(gin.H{"content": content}, "获取成功", c)
}
func (s *SkillsApi) SaveReference(c *gin.Context) {
var req request.SkillFileSaveRequest
_ = c.ShouldBindJSON(&req)
if err := skillsService.SaveReference(c.Request.Context(), req); err != nil {
global.GVA_LOG.Error("保存参考失败", zap.Error(err))
response.FailWithMessage("保存参考失败", c)
return
}
response.OkWithMessage("保存成功", c)
}
func (s *SkillsApi) CreateTemplate(c *gin.Context) {
var req request.SkillTemplateCreateRequest
_ = c.ShouldBindJSON(&req)
fileName, content, err := skillsService.CreateTemplate(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("创建模板失败", zap.Error(err))
response.FailWithMessage("创建模板失败", c)
return
}
response.OkWithDetailed(gin.H{"fileName": fileName, "content": content}, "创建成功", c)
}
func (s *SkillsApi) GetTemplate(c *gin.Context) {
var req request.SkillFileRequest
_ = c.ShouldBindJSON(&req)
content, err := skillsService.GetTemplate(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("读取模板失败", zap.Error(err))
response.FailWithMessage("读取模板失败", c)
return
}
response.OkWithDetailed(gin.H{"content": content}, "获取成功", c)
}
func (s *SkillsApi) SaveTemplate(c *gin.Context) {
var req request.SkillFileSaveRequest
_ = c.ShouldBindJSON(&req)
if err := skillsService.SaveTemplate(c.Request.Context(), req); err != nil {
global.GVA_LOG.Error("保存模板失败", zap.Error(err))
response.FailWithMessage("保存模板失败", c)
return
}
response.OkWithMessage("保存成功", c)
}
func (s *SkillsApi) GetGlobalConstraint(c *gin.Context) {
var req request.SkillToolRequest
_ = c.ShouldBindJSON(&req)
content, exists, err := skillsService.GetGlobalConstraint(c.Request.Context(), req.Tool)
if err != nil {
global.GVA_LOG.Error("读取全局约束失败", zap.Error(err))
response.FailWithMessage("读取全局约束失败", c)
return
}
response.OkWithDetailed(gin.H{"content": content, "exists": exists}, "获取成功", c)
}
func (s *SkillsApi) SaveGlobalConstraint(c *gin.Context) {
var req request.SkillGlobalConstraintSaveRequest
_ = c.ShouldBindJSON(&req)
if err := skillsService.SaveGlobalConstraint(c.Request.Context(), req); err != nil {
global.GVA_LOG.Error("保存全局约束失败", zap.Error(err))
response.FailWithMessage("保存全局约束失败", c)
return
}
response.OkWithMessage("保存成功", c)
}
+52 -41
View File
@@ -6,73 +6,84 @@ import (
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type SystemApi struct{}
// @Tags System
// @Summary 获取配置文件内容
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /system/getSystemConfig [post]
// GetSystemConfig
// @Tags System
// @Summary 获取配置文件内容
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {object} response.Response{data=systemRes.SysConfigResponse,msg=string} "获取配置文件内容,返回包括系统配置"
// @Router /system/getSystemConfig [post]
func (s *SystemApi) GetSystemConfig(c *gin.Context) {
if err, config := systemConfigService.GetSystemConfig(); err != nil {
config, err := systemConfigService.GetSystemConfig()
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(systemRes.SysConfigResponse{Config: config}, "获取成功", c)
return
}
response.OkWithDetailed(systemRes.SysConfigResponse{Config: config}, "获取成功", c)
}
// @Tags System
// @Summary 设置配置文件内容
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body system.System true "设置配置文件内容"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
// @Router /system/setSystemConfig [post]
// SetSystemConfig
// @Tags System
// @Summary 设置配置文件内容
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body system.System true "设置配置文件内容"
// @Success 200 {object} response.Response{data=string} "设置配置文件内容"
// @Router /system/setSystemConfig [post]
func (s *SystemApi) SetSystemConfig(c *gin.Context) {
var sys system.System
_ = c.ShouldBindJSON(&sys)
if err := systemConfigService.SetSystemConfig(sys); err != nil {
err := c.ShouldBindJSON(&sys)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = systemConfigService.SetSystemConfig(sys)
if err != nil {
global.GVA_LOG.Error("设置失败!", zap.Error(err))
response.FailWithMessage("设置失败", c)
} else {
response.OkWithData("设置成功", c)
return
}
response.OkWithMessage("设置成功", c)
}
// @Tags System
// @Summary 重启系统
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"code":0,"data":{},"msg":"重启系统成功"}"
// @Router /system/reloadSystem [post]
// ReloadSystem
// @Tags System
// @Summary 重载系统
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "重载系统"
// @Router /system/reloadSystem [post]
func (s *SystemApi) ReloadSystem(c *gin.Context) {
err := utils.Reload()
// 触发系统重载事件
err := utils.GlobalSystemEvents.TriggerReload()
if err != nil {
global.GVA_LOG.Error("重启系统失败!", zap.Error(err))
response.FailWithMessage("重启系统失败", c)
} else {
response.OkWithMessage("重启系统成功", c)
global.GVA_LOG.Error("重载系统失败!", zap.Error(err))
response.FailWithMessage("重载系统失败:"+err.Error(), c)
return
}
response.OkWithMessage("重载系统成功", c)
}
// @Tags System
// @Summary 获取服务器信息
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /system/getServerInfo [post]
// GetServerInfo
// @Tags System
// @Summary 获取服务器信息
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取服务器信息"
// @Router /system/getServerInfo [post]
func (s *SystemApi) GetServerInfo(c *gin.Context) {
if server, err := systemConfigService.GetServerInfo(); err != nil {
server, err := systemConfigService.GetServerInfo()
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(gin.H{"server": server}, "获取成功", c)
return
}
response.OkWithDetailed(gin.H{"server": server}, "获取成功", c)
}
+360 -166
View File
@@ -2,81 +2,140 @@ package system
import (
"strconv"
"time"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
)
// @Tags Base
// @Summary 用户登录
// @Produce application/json
// @Param data body systemReq.Login true "用户名, 密码, 验证码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"登陆成功"}"
// @Router /base/login [post]
// Login
// @Tags Base
// @Summary 用户登录
// @Produce application/json
// @Param data body systemReq.Login true "用户名, 密码, 验证码"
// @Success 200 {object} response.Response{data=systemRes.LoginResponse,msg=string} "返回包括用户信息,token,过期时间"
// @Router /base/login [post]
func (b *BaseApi) Login(c *gin.Context) {
var l systemReq.Login
_ = c.ShouldBindJSON(&l)
if err := utils.Verify(l, utils.LoginVerify); err != nil {
err := c.ShouldBindJSON(&l)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if store.Verify(l.CaptchaId, l.Captcha, true) {
u := &system.SysUser{Username: l.Username, Password: l.Password}
if err, user := userService.Login(u); err != nil {
global.GVA_LOG.Error("登陆失败! 用户名不存在或者密码错误!", zap.Error(err))
response.FailWithMessage("用户名不存在或者密码错误", c)
} else {
b.tokenNext(c, *user)
}
} else {
response.FailWithMessage("验证码错误", c)
err = utils.Verify(l, utils.LoginVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
key := c.ClientIP()
// 判断验证码是否开启
openCaptcha := global.GVA_CONFIG.Captcha.OpenCaptcha // 是否开启防爆次数
openCaptchaTimeOut := global.GVA_CONFIG.Captcha.OpenCaptchaTimeOut // 缓存超时时间
v, ok := global.BlackCache.Get(key)
if !ok {
global.BlackCache.Set(key, 1, time.Second*time.Duration(openCaptchaTimeOut))
}
var oc bool = openCaptcha == 0 || openCaptcha < interfaceToInt(v)
if oc && (l.Captcha == "" || l.CaptchaId == "" || !store.Verify(l.CaptchaId, l.Captcha, true)) {
// 验证码次数+1
global.BlackCache.Increment(key, 1)
response.FailWithMessage("验证码错误", c)
// 记录登录失败日志
loginLogService.CreateLoginLog(system.SysLoginLog{
Username: l.Username,
Ip: c.ClientIP(),
Agent: c.Request.UserAgent(),
Status: false,
ErrorMessage: "验证码错误",
})
return
}
u := &system.SysUser{Username: l.Username, Password: l.Password}
user, err := userService.Login(u)
if err != nil {
global.GVA_LOG.Error("登陆失败! 用户名不存在或者密码错误!", zap.Error(err))
// 验证码次数+1
global.BlackCache.Increment(key, 1)
response.FailWithMessage("用户名不存在或者密码错误", c)
// 记录登录失败日志
loginLogService.CreateLoginLog(system.SysLoginLog{
Username: l.Username,
Ip: c.ClientIP(),
Agent: c.Request.UserAgent(),
Status: false,
ErrorMessage: "用户名不存在或者密码错误",
})
return
}
if user.Enable != 1 {
global.GVA_LOG.Error("登陆失败! 用户被禁止登录!")
// 验证码次数+1
global.BlackCache.Increment(key, 1)
response.FailWithMessage("用户被禁止登录", c)
// 记录登录失败日志
loginLogService.CreateLoginLog(system.SysLoginLog{
Username: l.Username,
Ip: c.ClientIP(),
Agent: c.Request.UserAgent(),
Status: false,
ErrorMessage: "用户被禁止登录",
UserID: user.ID,
})
return
}
b.TokenNext(c, *user)
}
// 登录以后签发jwt
func (b *BaseApi) tokenNext(c *gin.Context, user system.SysUser) {
j := &utils.JWT{SigningKey: []byte(global.GVA_CONFIG.JWT.SigningKey)} // 唯一签名
claims := j.CreateClaims(systemReq.BaseClaims{
UUID: user.UUID,
ID: user.ID,
NickName: user.NickName,
Username: user.Username,
AuthorityId: user.AuthorityId,
})
token, err := j.CreateToken(claims)
// TokenNext 登录以后签发jwt
func (b *BaseApi) TokenNext(c *gin.Context, user system.SysUser) {
token, claims, err := utils.LoginToken(&user)
if err != nil {
global.GVA_LOG.Error("获取token失败!", zap.Error(err))
response.FailWithMessage("获取token失败", c)
return
}
// 记录登录成功日志
loginLogService.CreateLoginLog(system.SysLoginLog{
Username: user.Username,
Ip: c.ClientIP(),
Agent: c.Request.UserAgent(),
Status: true,
UserID: user.ID,
ErrorMessage: "登录成功",
})
if !global.GVA_CONFIG.System.UseMultipoint {
utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
response.OkWithDetailed(systemRes.LoginResponse{
User: user,
Token: token,
ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
}, "登录成功", c)
return
}
if err, jwtStr := jwtService.GetRedisJWT(user.Username); err == redis.Nil {
if err := jwtService.SetRedisJWT(token, user.Username); err != nil {
if jwtStr, err := jwtService.GetRedisJWT(user.Username); err == redis.Nil {
if err := utils.SetRedisJWT(token, user.Username); err != nil {
global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
response.FailWithMessage("设置登录状态失败", c)
return
}
utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
response.OkWithDetailed(systemRes.LoginResponse{
User: user,
Token: token,
ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
}, "登录成功", c)
} else if err != nil {
global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
@@ -88,28 +147,35 @@ func (b *BaseApi) tokenNext(c *gin.Context, user system.SysUser) {
response.FailWithMessage("jwt作废失败", c)
return
}
if err := jwtService.SetRedisJWT(token, user.Username); err != nil {
if err := utils.SetRedisJWT(token, user.GetUsername()); err != nil {
response.FailWithMessage("设置登录状态失败", c)
return
}
utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
response.OkWithDetailed(systemRes.LoginResponse{
User: user,
Token: token,
ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
}, "登录成功", c)
}
}
// @Tags SysUser
// @Summary 用户注册账号
// @Produce application/json
// @Param data body systemReq.Register true "用户名, 昵称, 密码, 角色ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"注册成功"}"
// @Router /user/register [post]
// Register
// @Tags SysUser
// @Summary 用户注册账号
// @Produce application/json
// @Param data body systemReq.Register true "用户名, 昵称, 密码, 角色ID"
// @Success 200 {object} response.Response{data=systemRes.SysUserResponse,msg=string} "用户注册账号,返回包括用户信息"
// @Router /user/admin_register [post]
func (b *BaseApi) Register(c *gin.Context) {
var r systemReq.Register
_ = c.ShouldBindJSON(&r)
if err := utils.Verify(r, utils.RegisterVerify); err != nil {
err := c.ShouldBindJSON(&r)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(r, utils.RegisterVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
@@ -119,204 +185,332 @@ func (b *BaseApi) Register(c *gin.Context) {
AuthorityId: v,
})
}
user := &system.SysUser{Username: r.Username, NickName: r.NickName, Password: r.Password, HeaderImg: r.HeaderImg, AuthorityId: r.AuthorityId, Authorities: authorities}
err, userReturn := userService.Register(*user)
user := &system.SysUser{Username: r.Username, NickName: r.NickName, Password: r.Password, HeaderImg: r.HeaderImg, AuthorityId: r.AuthorityId, Authorities: authorities, Enable: r.Enable, Phone: r.Phone, Email: r.Email}
userReturn, err := userService.Register(*user)
if err != nil {
global.GVA_LOG.Error("注册失败!", zap.Error(err))
response.FailWithDetailed(systemRes.SysUserResponse{User: userReturn}, "注册失败", c)
} else {
response.OkWithDetailed(systemRes.SysUserResponse{User: userReturn}, "注册成功", c)
return
}
response.OkWithDetailed(systemRes.SysUserResponse{User: userReturn}, "注册成功", c)
}
// @Tags SysUser
// @Summary 用户修改密码
// @Security ApiKeyAuth
// ChangePassword
// @Tags SysUser
// @Summary 用户修改密码
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body systemReq.ChangePasswordStruct true "用户名, 原密码, 新密码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/changePassword [post]
// @Param data body systemReq.ChangePasswordReq true "用户名, 原密码, 新密码"
// @Success 200 {object} response.Response{msg=string} "用户修改密码"
// @Router /user/changePassword [post]
func (b *BaseApi) ChangePassword(c *gin.Context) {
var user systemReq.ChangePasswordStruct
_ = c.ShouldBindJSON(&user)
if err := utils.Verify(user, utils.ChangePasswordVerify); err != nil {
var req systemReq.ChangePasswordReq
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
u := &system.SysUser{Username: user.Username, Password: user.Password}
if err, _ := userService.ChangePassword(u, user.NewPassword); err != nil {
err = utils.Verify(req, utils.ChangePasswordVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
uid := utils.GetUserID(c)
u := &system.SysUser{GVA_MODEL: global.GVA_MODEL{ID: uid}, Password: req.Password}
err = userService.ChangePassword(u, req.NewPassword)
if err != nil {
global.GVA_LOG.Error("修改失败!", zap.Error(err))
response.FailWithMessage("修改失败,原密码与当前账户不符", c)
} else {
response.OkWithMessage("修改成功", c)
return
}
response.OkWithMessage("修改成功", c)
}
// @Tags SysUser
// @Summary 分页获取用户列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "页码, 每页大小"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /user/getUserList [post]
// GetUserList
// @Tags SysUser
// @Summary 分页获取用户列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.GetUserList true "页码, 每页大小"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取用户列表,返回包括列表,总数,页码,每页数量"
// @Router /user/getUserList [post]
func (b *BaseApi) GetUserList(c *gin.Context) {
var pageInfo request.PageInfo
_ = c.ShouldBindJSON(&pageInfo)
if err := utils.Verify(pageInfo, utils.PageInfoVerify); err != nil {
var pageInfo systemReq.GetUserList
err := c.ShouldBindJSON(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, list, total := userService.GetUserInfoList(pageInfo); err != nil {
err = utils.Verify(pageInfo, utils.PageInfoVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := userService.GetUserInfoList(pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
// @Tags SysUser
// @Summary 更改用户权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.SetUserAuth true "用户UUID, 角色ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/setUserAuthority [post]
// SetUserAuthority
// @Tags SysUser
// @Summary 更改用户权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.SetUserAuth true "用户UUID, 角色ID"
// @Success 200 {object} response.Response{msg=string} "设置用户权限"
// @Router /user/setUserAuthority [post]
func (b *BaseApi) SetUserAuthority(c *gin.Context) {
var sua systemReq.SetUserAuth
_ = c.ShouldBindJSON(&sua)
err := c.ShouldBindJSON(&sua)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if UserVerifyErr := utils.Verify(sua, utils.SetUserAuthorityVerify); UserVerifyErr != nil {
response.FailWithMessage(UserVerifyErr.Error(), c)
return
}
userID := utils.GetUserID(c)
uuid := utils.GetUserUuid(c)
if err := userService.SetUserAuthority(userID, uuid, sua.AuthorityId); err != nil {
err = userService.SetUserAuthority(userID, sua.AuthorityId)
if err != nil {
global.GVA_LOG.Error("修改失败!", zap.Error(err))
response.FailWithMessage(err.Error(), c)
} else {
claims := utils.GetUserInfo(c)
j := &utils.JWT{SigningKey: []byte(global.GVA_CONFIG.JWT.SigningKey)} // 唯一签名
claims.AuthorityId = sua.AuthorityId
if token, err := j.CreateToken(*claims); err != nil {
global.GVA_LOG.Error("修改失败!", zap.Error(err))
response.FailWithMessage(err.Error(), c)
} else {
c.Header("new-token", token)
c.Header("new-expires-at", strconv.FormatInt(claims.ExpiresAt, 10))
response.OkWithMessage("修改成功", c)
}
return
}
claims := utils.GetUserInfo(c)
claims.AuthorityId = sua.AuthorityId
token, err := utils.NewJWT().CreateToken(*claims)
if err != nil {
global.GVA_LOG.Error("修改失败!", zap.Error(err))
response.FailWithMessage(err.Error(), c)
return
}
c.Header("new-token", token)
c.Header("new-expires-at", strconv.FormatInt(claims.ExpiresAt.Unix(), 10))
utils.SetToken(c, token, int(claims.ExpiresAt.Unix()-time.Now().Unix()))
response.OkWithMessage("修改成功", c)
}
// @Tags SysUser
// @Summary 设置用户权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.SetUserAuthorities true "用户UUID, 角色ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/setUserAuthorities [post]
// SetUserAuthorities
// @Tags SysUser
// @Summary 设置用户权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body systemReq.SetUserAuthorities true "用户UUID, 角色ID"
// @Success 200 {object} response.Response{msg=string} "设置用户权限"
// @Router /user/setUserAuthorities [post]
func (b *BaseApi) SetUserAuthorities(c *gin.Context) {
var sua systemReq.SetUserAuthorities
_ = c.ShouldBindJSON(&sua)
if err := userService.SetUserAuthorities(sua.ID, sua.AuthorityIds); err != nil {
err := c.ShouldBindJSON(&sua)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
authorityID := utils.GetUserAuthorityId(c)
err = userService.SetUserAuthorities(authorityID, sua.ID, sua.AuthorityIds)
if err != nil {
global.GVA_LOG.Error("修改失败!", zap.Error(err))
response.FailWithMessage("修改失败", c)
} else {
response.OkWithMessage("修改成功", c)
return
}
response.OkWithMessage("修改成功", c)
}
// @Tags SysUser
// @Summary 删除用户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "用户ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /user/deleteUser [delete]
// DeleteUser
// @Tags SysUser
// @Summary 删除用户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "用户ID"
// @Success 200 {object} response.Response{msg=string} "删除用户"
// @Router /user/deleteUser [delete]
func (b *BaseApi) DeleteUser(c *gin.Context) {
var reqId request.GetById
_ = c.ShouldBindJSON(&reqId)
if err := utils.Verify(reqId, utils.IdVerify); err != nil {
err := c.ShouldBindJSON(&reqId)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = utils.Verify(reqId, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
jwtId := utils.GetUserID(c)
if jwtId == uint(reqId.ID) {
response.FailWithMessage("删除失败, 自杀失败", c)
response.FailWithMessage("删除失败, 无法删除自己。", c)
return
}
if err := userService.DeleteUser(reqId.ID); err != nil {
err = userService.DeleteUser(reqId.ID)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败", c)
} else {
response.OkWithMessage("删除成功", c)
return
}
response.OkWithMessage("删除成功", c)
}
// @Tags SysUser
// @Summary 设置用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysUser true "ID, 用户名, 昵称, 头像链接"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
// @Router /user/setUserInfo [put]
// SetUserInfo
// @Tags SysUser
// @Summary 设置用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysUser true "ID, 用户名, 昵称, 头像链接"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "设置用户信息"
// @Router /user/setUserInfo [put]
func (b *BaseApi) SetUserInfo(c *gin.Context) {
var user system.SysUser
_ = c.ShouldBindJSON(&user)
if err := utils.Verify(user, utils.IdVerify); err != nil {
var user systemReq.ChangeUserInfo
err := c.ShouldBindJSON(&user)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, ReqUser := userService.SetUserInfo(user); err != nil {
err = utils.Verify(user, utils.IdVerify)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if len(user.AuthorityIds) != 0 {
authorityID := utils.GetUserAuthorityId(c)
err = userService.SetUserAuthorities(authorityID, user.ID, user.AuthorityIds)
if err != nil {
global.GVA_LOG.Error("设置失败!", zap.Error(err))
response.FailWithMessage("设置失败", c)
return
}
}
err = userService.SetUserInfo(system.SysUser{
GVA_MODEL: global.GVA_MODEL{
ID: user.ID,
},
NickName: user.NickName,
HeaderImg: user.HeaderImg,
Phone: user.Phone,
Email: user.Email,
Enable: user.Enable,
})
if err != nil {
global.GVA_LOG.Error("设置失败!", zap.Error(err))
response.FailWithMessage("设置失败", c)
} else {
response.OkWithDetailed(gin.H{"userInfo": ReqUser}, "设置成功", c)
return
}
response.OkWithMessage("设置成功", c)
}
// @Tags SysUser
// @Summary 获取用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /user/getUserInfo [get]
// SetSelfInfo
// @Tags SysUser
// @Summary 设置用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysUser true "ID, 用户名, 昵称, 头像链接"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "设置用户信息"
// @Router /user/SetSelfInfo [put]
func (b *BaseApi) SetSelfInfo(c *gin.Context) {
var user systemReq.ChangeUserInfo
err := c.ShouldBindJSON(&user)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
user.ID = utils.GetUserID(c)
err = userService.SetSelfInfo(system.SysUser{
GVA_MODEL: global.GVA_MODEL{
ID: user.ID,
},
NickName: user.NickName,
HeaderImg: user.HeaderImg,
Phone: user.Phone,
Email: user.Email,
Enable: user.Enable,
})
if err != nil {
global.GVA_LOG.Error("设置失败!", zap.Error(err))
response.FailWithMessage("设置失败", c)
return
}
response.OkWithMessage("设置成功", c)
}
// SetSelfSetting
// @Tags SysUser
// @Summary 设置用户配置
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body map[string]interface{} true "用户配置数据"
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "设置用户配置"
// @Router /user/SetSelfSetting [put]
func (b *BaseApi) SetSelfSetting(c *gin.Context) {
var req common.JSONMap
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = userService.SetSelfSetting(req, utils.GetUserID(c))
if err != nil {
global.GVA_LOG.Error("设置失败!", zap.Error(err))
response.FailWithMessage("设置失败", c)
return
}
response.OkWithMessage("设置成功", c)
}
// GetUserInfo
// @Tags SysUser
// @Summary 获取用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取用户信息"
// @Router /user/getUserInfo [get]
func (b *BaseApi) GetUserInfo(c *gin.Context) {
uuid := utils.GetUserUuid(c)
if err, ReqUser := userService.GetUserInfo(uuid); err != nil {
ReqUser, err := userService.GetUserInfo(uuid)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(gin.H{"userInfo": ReqUser}, "获取成功", c)
return
}
response.OkWithDetailed(gin.H{"userInfo": ReqUser}, "获取成功", c)
}
// @Tags SysUser
// @Summary 用户修改密码
// @Security ApiKeyAuth
// ResetPassword
// @Tags SysUser
// @Summary 重置用户密码
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body system.SysUser true "ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/resetPassword [post]
// @Param data body system.SysUser true "ID"
// @Success 200 {object} response.Response{msg=string} "重置用户密码"
// @Router /user/resetPassword [post]
func (b *BaseApi) ResetPassword(c *gin.Context) {
var user system.SysUser
_ = c.ShouldBindJSON(&user)
if err := userService.ResetPassword(user.ID); err != nil {
var rps systemReq.ResetPassword
err := c.ShouldBindJSON(&rps)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
err = userService.ResetPassword(rps.ID, rps.Password)
if err != nil {
global.GVA_LOG.Error("重置失败!", zap.Error(err))
response.FailWithMessage("重置失败"+err.Error(), c)
} else {
response.OkWithMessage("重置成功", c)
return
}
response.OkWithMessage("重置成功", c)
}
+486
View File
@@ -0,0 +1,486 @@
package system
import (
"encoding/json"
"fmt"
"net/http"
"sort"
"strconv"
"time"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type SysVersionApi struct{}
// buildMenuTree 构建菜单树结构
func buildMenuTree(menus []system.SysBaseMenu) []system.SysBaseMenu {
// 创建菜单映射
menuMap := make(map[uint]*system.SysBaseMenu)
for i := range menus {
menuMap[menus[i].ID] = &menus[i]
}
// 构建树结构
var rootMenus []system.SysBaseMenu
for _, menu := range menus {
if menu.ParentId == 0 {
// 根菜单
menuData := convertMenuToStruct(menu, menuMap)
rootMenus = append(rootMenus, menuData)
}
}
// 按sort排序根菜单
sort.Slice(rootMenus, func(i, j int) bool {
return rootMenus[i].Sort < rootMenus[j].Sort
})
return rootMenus
}
// convertMenuToStruct 将菜单转换为结构体并递归处理子菜单
func convertMenuToStruct(menu system.SysBaseMenu, menuMap map[uint]*system.SysBaseMenu) system.SysBaseMenu {
result := system.SysBaseMenu{
Path: menu.Path,
Name: menu.Name,
Hidden: menu.Hidden,
Component: menu.Component,
Sort: menu.Sort,
Meta: menu.Meta,
}
// 清理并复制参数数据
if len(menu.Parameters) > 0 {
cleanParameters := make([]system.SysBaseMenuParameter, 0, len(menu.Parameters))
for _, param := range menu.Parameters {
cleanParam := system.SysBaseMenuParameter{
Type: param.Type,
Key: param.Key,
Value: param.Value,
// 不复制 ID, CreatedAt, UpdatedAt, SysBaseMenuID
}
cleanParameters = append(cleanParameters, cleanParam)
}
result.Parameters = cleanParameters
}
// 清理并复制菜单按钮数据
if len(menu.MenuBtn) > 0 {
cleanMenuBtns := make([]system.SysBaseMenuBtn, 0, len(menu.MenuBtn))
for _, btn := range menu.MenuBtn {
cleanBtn := system.SysBaseMenuBtn{
Name: btn.Name,
Desc: btn.Desc,
// 不复制 ID, CreatedAt, UpdatedAt, SysBaseMenuID
}
cleanMenuBtns = append(cleanMenuBtns, cleanBtn)
}
result.MenuBtn = cleanMenuBtns
}
// 查找并处理子菜单
var children []system.SysBaseMenu
for _, childMenu := range menuMap {
if childMenu.ParentId == menu.ID {
childData := convertMenuToStruct(*childMenu, menuMap)
children = append(children, childData)
}
}
// 按sort排序子菜单
if len(children) > 0 {
sort.Slice(children, func(i, j int) bool {
return children[i].Sort < children[j].Sort
})
result.Children = children
}
return result
}
// DeleteSysVersion 删除版本管理
// @Tags SysVersion
// @Summary 删除版本管理
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body system.SysVersion true "删除版本管理"
// @Success 200 {object} response.Response{msg=string} "删除成功"
// @Router /sysVersion/deleteSysVersion [delete]
func (sysVersionApi *SysVersionApi) DeleteSysVersion(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
ID := c.Query("ID")
err := sysVersionService.DeleteSysVersion(ctx, ID)
if err != nil {
global.GVA_LOG.Error("删除失败!", zap.Error(err))
response.FailWithMessage("删除失败:"+err.Error(), c)
return
}
response.OkWithMessage("删除成功", c)
}
// DeleteSysVersionByIds 批量删除版本管理
// @Tags SysVersion
// @Summary 批量删除版本管理
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "批量删除成功"
// @Router /sysVersion/deleteSysVersionByIds [delete]
func (sysVersionApi *SysVersionApi) DeleteSysVersionByIds(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
IDs := c.QueryArray("IDs[]")
err := sysVersionService.DeleteSysVersionByIds(ctx, IDs)
if err != nil {
global.GVA_LOG.Error("批量删除失败!", zap.Error(err))
response.FailWithMessage("批量删除失败:"+err.Error(), c)
return
}
response.OkWithMessage("批量删除成功", c)
}
// FindSysVersion 用id查询版本管理
// @Tags SysVersion
// @Summary 用id查询版本管理
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param ID query uint true "用id查询版本管理"
// @Success 200 {object} response.Response{data=system.SysVersion,msg=string} "查询成功"
// @Router /sysVersion/findSysVersion [get]
func (sysVersionApi *SysVersionApi) FindSysVersion(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
ID := c.Query("ID")
resysVersion, err := sysVersionService.GetSysVersion(ctx, ID)
if err != nil {
global.GVA_LOG.Error("查询失败!", zap.Error(err))
response.FailWithMessage("查询失败:"+err.Error(), c)
return
}
response.OkWithData(resysVersion, c)
}
// GetSysVersionList 分页获取版本管理列表
// @Tags SysVersion
// @Summary 分页获取版本管理列表
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query systemReq.SysVersionSearch true "分页获取版本管理列表"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /sysVersion/getSysVersionList [get]
func (sysVersionApi *SysVersionApi) GetSysVersionList(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
var pageInfo systemReq.SysVersionSearch
err := c.ShouldBindQuery(&pageInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, total, err := sysVersionService.GetSysVersionInfoList(ctx, pageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:"+err.Error(), c)
return
}
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
// GetSysVersionPublic 不需要鉴权的版本管理接口
// @Tags SysVersion
// @Summary 不需要鉴权的版本管理接口
// @Accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /sysVersion/getSysVersionPublic [get]
func (sysVersionApi *SysVersionApi) GetSysVersionPublic(c *gin.Context) {
// 创建业务用Context
ctx := c.Request.Context()
// 此接口不需要鉴权
// 示例为返回了一个固定的消息接口,一般本接口用于C端服务,需要自己实现业务逻辑
sysVersionService.GetSysVersionPublic(ctx)
response.OkWithDetailed(gin.H{
"info": "不需要鉴权的版本管理接口信息",
}, "获取成功", c)
}
// ExportVersion 创建发版数据
// @Tags SysVersion
// @Summary 创建发版数据
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body systemReq.ExportVersionRequest true "创建发版数据"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /sysVersion/exportVersion [post]
func (sysVersionApi *SysVersionApi) ExportVersion(c *gin.Context) {
ctx := c.Request.Context()
var req systemReq.ExportVersionRequest
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
// 获取选中的菜单数据
var menuData []system.SysBaseMenu
if len(req.MenuIds) > 0 {
menuData, err = sysVersionService.GetMenusByIds(ctx, req.MenuIds)
if err != nil {
global.GVA_LOG.Error("获取菜单数据失败!", zap.Error(err))
response.FailWithMessage("获取菜单数据失败:"+err.Error(), c)
return
}
}
// 获取选中的API数据
var apiData []system.SysApi
if len(req.ApiIds) > 0 {
apiData, err = sysVersionService.GetApisByIds(ctx, req.ApiIds)
if err != nil {
global.GVA_LOG.Error("获取API数据失败!", zap.Error(err))
response.FailWithMessage("获取API数据失败:"+err.Error(), c)
return
}
}
// 获取选中的字典数据
var dictData []system.SysDictionary
if len(req.DictIds) > 0 {
dictData, err = sysVersionService.GetDictionariesByIds(ctx, req.DictIds)
if err != nil {
global.GVA_LOG.Error("获取字典数据失败!", zap.Error(err))
response.FailWithMessage("获取字典数据失败:"+err.Error(), c)
return
}
}
// 处理菜单数据,构建递归的children结构
processedMenus := buildMenuTree(menuData)
// 处理API数据,清除ID和时间戳字段
processedApis := make([]system.SysApi, 0, len(apiData))
for _, api := range apiData {
cleanApi := system.SysApi{
Path: api.Path,
Description: api.Description,
ApiGroup: api.ApiGroup,
Method: api.Method,
}
processedApis = append(processedApis, cleanApi)
}
// 处理字典数据,清除ID和时间戳字段,包含字典详情
processedDicts := make([]system.SysDictionary, 0, len(dictData))
for _, dict := range dictData {
cleanDict := system.SysDictionary{
Name: dict.Name,
Type: dict.Type,
Status: dict.Status,
Desc: dict.Desc,
}
// 处理字典详情数据,清除ID和时间戳字段
cleanDetails := make([]system.SysDictionaryDetail, 0, len(dict.SysDictionaryDetails))
for _, detail := range dict.SysDictionaryDetails {
cleanDetail := system.SysDictionaryDetail{
Label: detail.Label,
Value: detail.Value,
Extend: detail.Extend,
Status: detail.Status,
Sort: detail.Sort,
// 不复制 ID, CreatedAt, UpdatedAt, SysDictionaryID
}
cleanDetails = append(cleanDetails, cleanDetail)
}
cleanDict.SysDictionaryDetails = cleanDetails
processedDicts = append(processedDicts, cleanDict)
}
// 构建导出数据
exportData := systemRes.ExportVersionResponse{
Version: systemReq.VersionInfo{
Name: req.VersionName,
Code: req.VersionCode,
Description: req.Description,
ExportTime: time.Now().Format("2006-01-02 15:04:05"),
},
Menus: processedMenus,
Apis: processedApis,
Dictionaries: processedDicts,
}
// 转换为JSON
jsonData, err := json.MarshalIndent(exportData, "", " ")
if err != nil {
global.GVA_LOG.Error("JSON序列化失败!", zap.Error(err))
response.FailWithMessage("JSON序列化失败:"+err.Error(), c)
return
}
// 保存版本记录
version := system.SysVersion{
VersionName: utils.Pointer(req.VersionName),
VersionCode: utils.Pointer(req.VersionCode),
Description: utils.Pointer(req.Description),
VersionData: utils.Pointer(string(jsonData)),
}
err = sysVersionService.CreateSysVersion(ctx, &version)
if err != nil {
global.GVA_LOG.Error("保存版本记录失败!", zap.Error(err))
response.FailWithMessage("保存版本记录失败:"+err.Error(), c)
return
}
response.OkWithMessage("创建发版成功", c)
}
// DownloadVersionJson 下载版本JSON数据
// @Tags SysVersion
// @Summary 下载版本JSON数据
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param ID query string true "版本ID"
// @Success 200 {object} response.Response{data=object,msg=string} "下载成功"
// @Router /sysVersion/downloadVersionJson [get]
func (sysVersionApi *SysVersionApi) DownloadVersionJson(c *gin.Context) {
ctx := c.Request.Context()
ID := c.Query("ID")
if ID == "" {
response.FailWithMessage("版本ID不能为空", c)
return
}
// 获取版本记录
version, err := sysVersionService.GetSysVersion(ctx, ID)
if err != nil {
global.GVA_LOG.Error("获取版本记录失败!", zap.Error(err))
response.FailWithMessage("获取版本记录失败:"+err.Error(), c)
return
}
// 构建JSON数据
var jsonData []byte
if version.VersionData != nil && *version.VersionData != "" {
jsonData = []byte(*version.VersionData)
} else {
// 如果没有存储的JSON数据,构建一个基本的结构
basicData := systemRes.ExportVersionResponse{
Version: systemReq.VersionInfo{
Name: *version.VersionName,
Code: *version.VersionCode,
Description: *version.Description,
ExportTime: version.CreatedAt.Format("2006-01-02 15:04:05"),
},
Menus: []system.SysBaseMenu{},
Apis: []system.SysApi{},
}
jsonData, _ = json.MarshalIndent(basicData, "", " ")
}
// 设置下载响应头
filename := fmt.Sprintf("version_%s_%s.json", *version.VersionCode, time.Now().Format("20060102150405"))
c.Header("Content-Type", "application/json")
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
c.Header("Content-Length", strconv.Itoa(len(jsonData)))
c.Data(http.StatusOK, "application/json", jsonData)
}
// ImportVersion 导入版本数据
// @Tags SysVersion
// @Summary 导入版本数据
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body systemReq.ImportVersionRequest true "版本JSON数据"
// @Success 200 {object} response.Response{msg=string} "导入成功"
// @Router /sysVersion/importVersion [post]
func (sysVersionApi *SysVersionApi) ImportVersion(c *gin.Context) {
ctx := c.Request.Context()
// 获取JSON数据
var importData systemReq.ImportVersionRequest
err := c.ShouldBindJSON(&importData)
if err != nil {
response.FailWithMessage("解析JSON数据失败:"+err.Error(), c)
return
}
// 验证数据格式
if importData.VersionInfo.Name == "" || importData.VersionInfo.Code == "" {
response.FailWithMessage("版本信息格式错误", c)
return
}
// 导入菜单数据
if len(importData.ExportMenu) > 0 {
if err := sysVersionService.ImportMenus(ctx, importData.ExportMenu); err != nil {
global.GVA_LOG.Error("导入菜单失败!", zap.Error(err))
response.FailWithMessage("导入菜单失败: "+err.Error(), c)
return
}
}
// 导入API数据
if len(importData.ExportApi) > 0 {
if err := sysVersionService.ImportApis(importData.ExportApi); err != nil {
global.GVA_LOG.Error("导入API失败!", zap.Error(err))
response.FailWithMessage("导入API失败: "+err.Error(), c)
return
}
}
// 导入字典数据
if len(importData.ExportDictionary) > 0 {
if err := sysVersionService.ImportDictionaries(importData.ExportDictionary); err != nil {
global.GVA_LOG.Error("导入字典失败!", zap.Error(err))
response.FailWithMessage("导入字典失败: "+err.Error(), c)
return
}
}
// 创建导入记录
jsonData, _ := json.Marshal(importData)
version := system.SysVersion{
VersionName: utils.Pointer(importData.VersionInfo.Name),
VersionCode: utils.Pointer(fmt.Sprintf("%s_imported_%s", importData.VersionInfo.Code, time.Now().Format("20060102150405"))),
Description: utils.Pointer(fmt.Sprintf("导入版本: %s", importData.VersionInfo.Description)),
VersionData: utils.Pointer(string(jsonData)),
}
err = sysVersionService.CreateSysVersion(ctx, &version)
if err != nil {
global.GVA_LOG.Error("保存导入记录失败!", zap.Error(err))
// 这里不返回错误,因为数据已经导入成功
}
response.OkWithMessage("导入成功", c)
}
+239 -108
View File
@@ -2,153 +2,284 @@
# jwt configuration
jwt:
signing-key: 'qmPlus'
expires-time: 604800
buffer-time: 86400
signing-key: qmPlus
expires-time: 7d
buffer-time: 1d
issuer: qmPlus
# zap logger configuration
zap:
level: 'info'
format: 'console'
prefix: '[github.com/flipped-aurora/gin-vue-admin/server]'
director: 'log'
link-name: 'latest_log'
show-line: true
encode-level: 'LowercaseColorLevelEncoder'
stacktrace-key: 'stacktrace'
log-in-console: true
level: info
format: console
prefix: "[github.com/flipped-aurora/gin-vue-admin/server]"
director: log
show-line: true
encode-level: LowercaseColorLevelEncoder
stacktrace-key: stacktrace
log-in-console: true
retention-day: -1
# redis configuration
redis:
db: 0
addr: '177.7.0.14:6379'
password: ''
#是否使用redis集群模式
useCluster: false
#使用集群模式addr和db默认无效
addr: 177.7.0.14:6379
password: ""
db: 0
clusterAddrs:
- "177.7.0.14:7000"
- "177.7.0.15:7001"
- "177.7.0.13:7002"
# redis-list configuration
redis-list:
- name: cache # 数据库的名称,注意: name 需要在 redis-list 中唯一
useCluster: false # 是否使用redis集群模式
addr: 177.7.0.14:6379 # 使用集群模式addr和db默认无效
password: ""
db: 0
clusterAddrs:
- "177.7.0.14:7000"
- "177.7.0.15:7001"
- "177.7.0.13:7002"
# mongo configuration
mongo:
coll: ''
options: ''
database: ''
username: ''
password: ''
auth-source: ''
min-pool-size: 0
max-pool-size: 100
socket-timeout-ms: 0
connect-timeout-ms: 0
is-zap: false
hosts:
- host: ''
port: ''
# email configuration
email:
to: 'xxx@qq.com'
port: 465
from: 'xxx@163.com'
host: 'smtp.163.com'
is-ssl: true
secret: 'xxx'
nickname: 'test'
# casbin configuration
casbin:
model-path: './resource/rbac_model.conf'
to: xxx@qq.com
port: 465
from: xxx@163.com
host: smtp.163.com
is-ssl: true
secret: xxx
nickname: test
# system configuration
system:
env: 'public' # Change to "develop" to skip authentication for development mode
addr: 8888
db-type: 'mysql'
oss-type: 'local' # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
use-multipoint: false
env: local # 修改为public可以关闭路由日志输出
addr: 8888
db-type: mysql
oss-type: local # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
use-redis: false # 使用redis
use-mongo: false # 使用mongo
use-multipoint: false
# IP限制次数 一个小时15000次
iplimit-count: 15000
# IP限制一个小时
iplimit-time: 3600
# 路由全局前缀
router-prefix: ""
# 严格角色模式 打开后权限将会存在上下级关系
use-strict-auth: false
# captcha configuration
captcha:
key-long: 6
img-width: 240
img-height: 80
key-long: 6
img-width: 240
img-height: 80
open-captcha: 0 # 0代表一直开启,大于0代表限制次数
open-captcha-timeout: 3600 # open-captcha大于0时才生效
# mysql connect configuration
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
mysql:
path: ''
port: ''
config: ''
db-name: ''
username: ''
password: ''
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
# pgsql connect configuration
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
pgsql:
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
oracle:
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
mssql:
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
sqlite:
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
db-list:
- disable: true # 是否禁用
type: "" # 数据库的类型,目前支持mysql、pgsql、mssql、oracle
alias-name: "" # 数据库的名称,注意: alias-name 需要在db-list中唯一
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
# local configuration
local:
path: 'uploads/file'
path: uploads/file
store-path: uploads/file
# autocode configuration
autocode:
transfer-restart: true
root: ""
server: /server
server-api: /api/v1
server-initialize: /initialize
server-model: /model
server-request: /model/request/
server-router: /router
server-service: /service
web: /web/src
web-api: /api
web-form: /view
web-table: /view
web: web/src
root: "" # root 自动适配项目根目录, 请不要手动配置,他会在项目加载的时候识别出根路径
server: server
module: 'github.com/flipped-aurora/gin-vue-admin/server'
ai-path: "" # AI服务路径
# qiniu configuration (请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址)
qiniu:
zone: 'ZoneHuaDong'
bucket: ''
img-path: ''
use-https: false
access-key: ''
secret-key: ''
use-cdn-domains: false
zone: ZoneHuaDong
bucket: ""
img-path: ""
use-https: false
access-key: ""
secret-key: ""
use-cdn-domains: false
# minio oss configuration
minio:
endpoint: yourEndpoint
access-key-id: yourAccessKeyId
access-key-secret: yourAccessKeySecret
bucket-name: yourBucketName
use-ssl: false
base-path: ""
bucket-url: "http://host:9000/yourBucketName"
# aliyun oss configuration
aliyun-oss:
endpoint: 'yourEndpoint'
access-key-id: 'yourAccessKeyId'
access-key-secret: 'yourAccessKeySecret'
bucket-name: 'yourBucketName'
bucket-url: 'yourBucketUrl'
endpoint: yourEndpoint
access-key-id: yourAccessKeyId
access-key-secret: yourAccessKeySecret
bucket-name: yourBucketName
bucket-url: yourBucketUrl
base-path: yourBasePath
# tencent cos configuration
tencent-cos:
bucket: 'xxxxx-10005608'
region: 'ap-shanghai'
secret-id: 'xxxxxxxx'
secret-key: 'xxxxxxxx'
base-url: 'https://gin.vue.admin'
path-prefix: 'github.com/flipped-aurora/gin-vue-admin/server'
bucket: xxxxx-10005608
region: ap-shanghai
secret-id: your-secret-id
secret-key: your-secret-key
base-url: https://gin.vue.admin
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
# aws s3 configuration (minio compatible)
aws-s3:
bucket: xxxxx-10005608
region: ap-shanghai
endpoint: ""
s3-force-path-style: false
disable-ssl: false
secret-id: your-secret-id
secret-key: your-secret-key
base-url: https://gin.vue.admin
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
# cloudflare r2 configuration
cloudflare-r2:
bucket: xxxx0bucket
base-url: https://gin.vue.admin.com
path: uploads
account-id: xxx_account_id
access-key-id: xxx_key_id
secret-access-key: xxx_secret_key
# huawei obs configuration
hua-wei-obs:
path: 'you-path'
bucket: 'you-bucket'
endpoint: 'you-endpoint'
access-key: 'you-access-key'
secret-key: 'you-secret-key'
path: you-path
bucket: you-bucket
endpoint: you-endpoint
access-key: you-access-key
secret-key: you-secret-key
# excel configuration
excel:
dir: './resource/excel/'
dir: ./resource/excel/
# timer task db clear table
Timer:
start: true
spec: "@daily" # 定时任务详细配置参考 https://pkg.go.dev/github.com/robfig/cron/v3
detail: [
# tableName: 需要清理的表名
# compareField: 需要比较时间的字段
# interval: 时间间隔, 具体配置详看 time.ParseDuration() 中字符串表示 且不能为负数
# 2160h = 24 * 30 * 3 -> 三个月
{ tableName: "sys_operation_records" , compareField: "created_at", interval: "2160h" },
#{ tableName: "log2" , compareField: "created_at", interval: "2160h" }
]
# disk usage configuration
disk-list:
- mount-point: "/"
# 跨域配置
# 需要配合 server/initialize/router.go#L32 使用
# 需要配合 server/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用
cors:
mode: whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝
whitelist:
- allow-origin: example1.com
allow-headers: content-type
allow-methods: GET, POST
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
allow-credentials: true # 布尔值
- allow-origin: example2.com
allow-headers: content-type
allow-methods: GET, POST
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
allow-credentials: true # 布尔值
mode: strict-whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝
whitelist:
- allow-origin: example1.com
allow-headers: Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id
allow-methods: POST, GET
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
allow-credentials: true # 布尔值
- allow-origin: example2.com
allow-headers: content-type
allow-methods: GET, POST
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
allow-credentials: true # 布尔值
mcp:
name: GVA_MCP
version: v1.0.0
sse_path: /sse
message_path: /message
url_prefix: ''
addr: 8889
separate: false
+237 -147
View File
@@ -2,195 +2,285 @@
# jwt configuration
jwt:
signing-key: 'qmPlus'
expires-time: 604800
buffer-time: 86400
issuer: 'qmPlus'
signing-key: qmPlus
expires-time: 7d
buffer-time: 1d
issuer: qmPlus
# zap logger configuration
zap:
level: 'info'
format: 'console'
prefix: '[github.com/flipped-aurora/gin-vue-admin/server]'
director: 'log'
show-line: true
encode-level: 'LowercaseColorLevelEncoder'
stacktrace-key: 'stacktrace'
log-in-console: true
level: info
format: console
prefix: "[github.com/flipped-aurora/gin-vue-admin/server]"
director: log
show-line: true
encode-level: LowercaseColorLevelEncoder
stacktrace-key: stacktrace
log-in-console: true
retention-day: -1
# redis configuration
redis:
db: 0
addr: '127.0.0.1:6379'
password: ''
#是否使用redis集群模式
useCluster: false
#使用集群模式addr和db默认无效
addr: 127.0.0.1:6379
password: ""
db: 0
clusterAddrs:
- "172.21.0.3:7000"
- "172.21.0.4:7001"
- "172.21.0.2:7002"
# redis-list configuration
redis-list:
- name: cache # 数据库的名称,注意: name 需要在 redis-list 中唯一
useCluster: false # 是否使用redis集群模式
addr: 127.0.0.1:6379 # 使用集群模式addr和db默认无效
password: ""
db: 0
clusterAddrs:
- "172.21.0.3:7000"
- "172.21.0.4:7001"
- "172.21.0.2:7002"
# mongo configuration
mongo:
coll: ''
options: ''
database: ''
username: ''
password: ''
auth-source: ''
min-pool-size: 0
max-pool-size: 100
socket-timeout-ms: 0
connect-timeout-ms: 0
is-zap: false
hosts:
- host: ''
port: ''
# email configuration
email:
to: 'xxx@qq.com'
port: 465
from: 'xxx@163.com'
host: 'smtp.163.com'
is-ssl: true
secret: 'xxx'
nickname: 'test'
# casbin configuration
casbin:
model-path: './resource/rbac_model.conf'
to: xxx@qq.com
port: 465
from: xxx@163.com
host: smtp.163.com
is-ssl: true
secret: xxx
nickname: test
# system configuration
system:
env: 'public' # Change to "develop" to skip authentication for development mode
addr: 8888
db-type: 'mysql'
oss-type: 'local' # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
use-multipoint: false
# IP限制次数 一个小时15000次
iplimit-count: 15000
# IP限制一个小时
iplimit-time: 3600
env: local # 修改为public可以关闭路由日志输出
addr: 8888
db-type: mysql
oss-type: local # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
use-redis: false # 使用redis
use-mongo: false # 使用mongo
use-multipoint: false
# IP限制次数 一个小时15000次
iplimit-count: 15000
# IP限制一个小时
iplimit-time: 3600
# 路由全局前缀
router-prefix: ""
# 严格角色模式 打开后权限将会存在上下级关系
use-strict-auth: false
# 禁用自动迁移数据库表结构,生产环境建议设为true,手动迁移
disable-auto-migrate: false
# captcha configuration
captcha:
key-long: 6
img-width: 240
img-height: 80
key-long: 6
img-width: 240
img-height: 80
open-captcha: 0 # 0代表一直开启,大于0代表限制次数
open-captcha-timeout: 3600 # open-captcha大于0时才生效
# mysql connect configuration
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://www.github.com/flipped-aurora/gin-vue-admin/server.com/docs/first)
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
mysql:
path: ''
port: ''
config: ''
db-name: ''
username: ''
password: ''
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
# pgsql connect configuration
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://www.github.com/flipped-aurora/gin-vue-admin/server.com/docs/first)
# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master)
pgsql:
path: ''
port: ''
config: ''
db-name: ''
username: ''
password: ''
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
db-list: [
{
disabled: true, # 是否启用
type: "", # 数据库的类型,目前支持mysql、pgsql
alias-name: "", # 数据库的名称,注意: alias-name 需要在db-list中唯一
path: '',
port: '',
config: '',
db-name: '',
username: '',
password: '',
max-idle-conns: 10,
max-open-conns: 100,
log-mode: "",
log-zap: false,
}
]
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
oracle:
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
mssql:
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
sqlite:
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
db-list:
- disable: true # 是否禁用
type: "" # 数据库的类型,目前支持mysql、pgsql、mssql、oracle
alias-name: "" # 数据库的名称,注意: alias-name 需要在db-list中唯一
path: ""
port: ""
config: ""
db-name: ""
username: ""
password: ""
max-idle-conns: 10
max-open-conns: 100
log-mode: ""
log-zap: false
# local configuration
local:
path: 'uploads/file'
path: uploads/file
store-path: uploads/file
# autocode configuration
autocode:
transfer-restart: true
# root 自动适配项目根目录
# 请不要手动配置,他会在项目加载的时候识别出根路径
root: ""
server: /server
server-api: /api/v1/autocode
server-initialize: /initialize
server-model: /model/autocode
server-request: /model/autocode/request/
server-router: /router/autocode
server-service: /service/autocode
web: /web/src
web-api: /api
web-form: /view
web-table: /view
web: web/src
root: "" # root 自动适配项目根目录, 请不要手动配置,他会在项目加载的时候识别出根路径
server: server
module: 'github.com/flipped-aurora/gin-vue-admin/server'
ai-path: "" # AI服务路径
# qiniu configuration (请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址)
qiniu:
zone: 'ZoneHuaDong'
bucket: ''
img-path: ''
use-https: false
access-key: ''
secret-key: ''
use-cdn-domains: false
zone: ZoneHuaDong
bucket: ""
img-path: ""
use-https: false
access-key: ""
secret-key: ""
use-cdn-domains: false
# minio oss configuration
minio:
endpoint: yourEndpoint
access-key-id: yourAccessKeyId
access-key-secret: yourAccessKeySecret
bucket-name: yourBucketName
use-ssl: false
base-path: ""
bucket-url: "http://host:9000/yourBucketName"
# aliyun oss configuration
aliyun-oss:
endpoint: 'yourEndpoint'
access-key-id: 'yourAccessKeyId'
access-key-secret: 'yourAccessKeySecret'
bucket-name: 'yourBucketName'
bucket-url: 'yourBucketUrl'
base-path: 'yourBasePath'
endpoint: yourEndpoint
access-key-id: yourAccessKeyId
access-key-secret: yourAccessKeySecret
bucket-name: yourBucketName
bucket-url: yourBucketUrl
base-path: yourBasePath
# tencent cos configuration
tencent-cos:
bucket: 'xxxxx-10005608'
region: 'ap-shanghai'
secret-id: 'xxxxxxxx'
secret-key: 'xxxxxxxx'
base-url: 'https://gin.vue.admin'
path-prefix: 'github.com/flipped-aurora/gin-vue-admin/server'
bucket: xxxxx-10005608
region: ap-shanghai
secret-id: your-secret-id
secret-key: your-secret-key
base-url: https://gin.vue.admin
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
# aws s3 configuration (minio compatible)
aws-s3:
bucket: xxxxx-10005608
region: ap-shanghai
endpoint: ""
s3-force-path-style: false
disable-ssl: false
secret-id: your-secret-id
secret-key: your-secret-key
base-url: https://gin.vue.admin
path-prefix: github.com/flipped-aurora/gin-vue-admin/server
# cloudflare r2 configuration
cloudflare-r2:
bucket: xxxx0bucket
base-url: https://gin.vue.admin.com
path: uploads
account-id: xxx_account_id
access-key-id: xxx_key_id
secret-access-key: xxx_secret_key
# huawei obs configuration
hua-wei-obs:
path: 'you-path'
bucket: 'you-bucket'
endpoint: 'you-endpoint'
access-key: 'you-access-key'
secret-key: 'you-secret-key'
path: you-path
bucket: you-bucket
endpoint: you-endpoint
access-key: you-access-key
secret-key: you-secret-key
# excel configuration
excel:
dir: './resource/excel/'
dir: ./resource/excel/
# timer task db clear table
Timer:
start: true
spec: "@daily" # 定时任务详细配置参考 https://pkg.go.dev/github.com/robfig/cron/v3
detail: [
# tableName: 需要清理的表名
# compareField: 需要比较时间的字段
# interval: 时间间隔, 具体配置详看 time.ParseDuration() 中字符串表示 且不能为负数
# 2160h = 24 * 30 * 3 -> 三个月
{ tableName: "sys_operation_records" , compareField: "created_at", interval: "2160h" },
{ tableName: "jwt_blacklists" , compareField: "created_at", interval: "168h" }
#{ tableName: "log2" , compareField: "created_at", interval: "2160h" }
]
# disk usage configuration
disk-list:
- mount-point: "/"
# 跨域配置
# 需要配合 server/initialize/router.go#L32 使用
# 需要配合 server/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用
cors:
mode: whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝
whitelist:
- allow-origin: example1.com
allow-headers: content-type
allow-methods: GET, POST
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
allow-credentials: true # 布尔值
- allow-origin: example2.com
allow-headers: content-type
allow-methods: GET, POST
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
allow-credentials: true # 布尔值
mode: strict-whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝
whitelist:
- allow-origin: example1.com
allow-headers: Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id
allow-methods: POST, GET
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
allow-credentials: true # 布尔值
- allow-origin: example2.com
allow-headers: content-type
allow-methods: GET, POST
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
allow-credentials: true # 布尔值
mcp:
name: GVA_MCP
version: v1.0.0
sse_path: /sse
message_path: /message
url_prefix: ''
addr: 8889
separate: false
+18 -13
View File
@@ -1,17 +1,22 @@
package config
import (
"path/filepath"
"strings"
)
type Autocode struct {
TransferRestart bool `mapstructure:"transfer-restart" json:"transferRestart" yaml:"transfer-restart"`
Root string `mapstructure:"root" json:"root" yaml:"root"`
Server string `mapstructure:"server" json:"server" yaml:"server"`
SApi string `mapstructure:"server-api" json:"serverApi" yaml:"server-api"`
SInitialize string `mapstructure:"server-initialize" json:"serverInitialize" yaml:"server-initialize"`
SModel string `mapstructure:"server-model" json:"serverModel" yaml:"server-model"`
SRequest string `mapstructure:"server-request" json:"serverRequest" yaml:"server-request"`
SRouter string `mapstructure:"server-router" json:"serverRouter" yaml:"server-router"`
SService string `mapstructure:"server-service" json:"serverService" yaml:"server-service"`
Web string `mapstructure:"web" json:"web" yaml:"web"`
WApi string `mapstructure:"web-api" json:"webApi" yaml:"web-api"`
WForm string `mapstructure:"web-form" json:"webForm" yaml:"web-form"`
WTable string `mapstructure:"web-table" json:"webTable" yaml:"web-table"`
Web string `mapstructure:"web" json:"web" yaml:"web"`
Root string `mapstructure:"root" json:"root" yaml:"root"`
Server string `mapstructure:"server" json:"server" yaml:"server"`
Module string `mapstructure:"module" json:"module" yaml:"module"`
AiPath string `mapstructure:"ai-path" json:"ai-path" yaml:"ai-path"`
}
func (a *Autocode) WebRoot() string {
webs := strings.Split(a.Web, "/")
if len(webs) == 0 {
webs = strings.Split(a.Web, "\\")
}
return filepath.Join(webs...)
}
+5 -3
View File
@@ -1,7 +1,9 @@
package config
type Captcha struct {
KeyLong int `mapstructure:"key-long" json:"keyLong" yaml:"key-long"` // 验证码长度
ImgWidth int `mapstructure:"img-width" json:"imgWidth" yaml:"img-width"` // 验证码宽度
ImgHeight int `mapstructure:"img-height" json:"imgHeight" yaml:"img-height"` // 验证码高度
KeyLong int `mapstructure:"key-long" json:"key-long" yaml:"key-long"` // 验证码长度
ImgWidth int `mapstructure:"img-width" json:"img-width" yaml:"img-width"` // 验证码宽度
ImgHeight int `mapstructure:"img-height" json:"img-height" yaml:"img-height"` // 验证码高度
OpenCaptcha int `mapstructure:"open-captcha" json:"open-captcha" yaml:"open-captcha"` // 防爆破验证码开启此数,0代表每次登录都需要验证码,其他数字代表错误密码次数,如3代表错误三次后出现验证码
OpenCaptchaTimeOut int `mapstructure:"open-captcha-timeout" json:"open-captcha-timeout" yaml:"open-captcha-timeout"` // 防爆破验证码超时时间,单位:s(秒)
}
-5
View File
@@ -1,5 +0,0 @@
package config
type Casbin struct {
ModelPath string `mapstructure:"model-path" json:"modelPath" yaml:"model-path"` // 存放casbin模型的相对路径
}
+28 -17
View File
@@ -1,29 +1,40 @@
package config
type Server struct {
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"`
Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"`
Email Email `mapstructure:"email" json:"email" yaml:"email"`
Casbin Casbin `mapstructure:"casbin" json:"casbin" yaml:"casbin"`
System System `mapstructure:"system" json:"system" yaml:"system"`
Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"`
Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"`
RedisList []Redis `mapstructure:"redis-list" json:"redis-list" yaml:"redis-list"`
Mongo Mongo `mapstructure:"mongo" json:"mongo" yaml:"mongo"`
Email Email `mapstructure:"email" json:"email" yaml:"email"`
System System `mapstructure:"system" json:"system" yaml:"system"`
Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
// auto
AutoCode Autocode `mapstructure:"autoCode" json:"autoCode" yaml:"autoCode"`
AutoCode Autocode `mapstructure:"autocode" json:"autocode" yaml:"autocode"`
// gorm
Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
Pgsql Pgsql `mapstructure:"pgsql" json:"pgsql" yaml:"pgsql"`
DBList []DB `mapstructure:"db-list" json:"db-list" yaml:"db-list"`
Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
Mssql Mssql `mapstructure:"mssql" json:"mssql" yaml:"mssql"`
Pgsql Pgsql `mapstructure:"pgsql" json:"pgsql" yaml:"pgsql"`
Oracle Oracle `mapstructure:"oracle" json:"oracle" yaml:"oracle"`
Sqlite Sqlite `mapstructure:"sqlite" json:"sqlite" yaml:"sqlite"`
DBList []SpecializedDB `mapstructure:"db-list" json:"db-list" yaml:"db-list"`
// oss
Local Local `mapstructure:"local" json:"local" yaml:"local"`
Qiniu Qiniu `mapstructure:"qiniu" json:"qiniu" yaml:"qiniu"`
AliyunOSS AliyunOSS `mapstructure:"aliyun-oss" json:"aliyunOSS" yaml:"aliyun-oss"`
HuaWeiObs HuaWeiObs `mapstructure:"hua-wei-obs" json:"huaWeiObs" yaml:"hua-wei-obs"`
TencentCOS TencentCOS `mapstructure:"tencent-cos" json:"tencentCOS" yaml:"tencent-cos"`
Local Local `mapstructure:"local" json:"local" yaml:"local"`
Qiniu Qiniu `mapstructure:"qiniu" json:"qiniu" yaml:"qiniu"`
AliyunOSS AliyunOSS `mapstructure:"aliyun-oss" json:"aliyun-oss" yaml:"aliyun-oss"`
HuaWeiObs HuaWeiObs `mapstructure:"hua-wei-obs" json:"hua-wei-obs" yaml:"hua-wei-obs"`
TencentCOS TencentCOS `mapstructure:"tencent-cos" json:"tencent-cos" yaml:"tencent-cos"`
AwsS3 AwsS3 `mapstructure:"aws-s3" json:"aws-s3" yaml:"aws-s3"`
CloudflareR2 CloudflareR2 `mapstructure:"cloudflare-r2" json:"cloudflare-r2" yaml:"cloudflare-r2"`
Minio Minio `mapstructure:"minio" json:"minio" yaml:"minio"`
Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"`
Timer Timer `mapstructure:"timer" json:"timer" yaml:"timer"`
DiskList []DiskList `mapstructure:"disk-list" json:"disk-list" yaml:"disk-list"`
// 跨域配置
Cors CORS `mapstructure:"cors" json:"cors" yaml:"cors"`
// MCP配置
MCP MCP `mapstructure:"mcp" json:"mcp" yaml:"mcp"`
}
+48 -16
View File
@@ -1,21 +1,53 @@
package config
type DB struct {
Disable bool `mapstructure:"disable" json:"disable" yaml:"disable"`
Type string `mapstructure:"type" json:"type" yaml:"type"`
AliasName string `mapstructure:"alias-name" json:"alias-name" yaml:"alias-name"`
Path string `mapstructure:"path" json:"path" yaml:"path"` // 服务器地址:端口
Port string `mapstructure:"port" json:"port" yaml:"port"` //:端口
Config string `mapstructure:"config" json:"config" yaml:"config"` // 高级配置
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"` // 数据库名
Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库用户名
Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"` // 空闲中的最大连接数
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"` // 打开到数据库的最大连接数
LogMode string `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"` // 是否开启Gorm全局日志
LogZap bool `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"`
import (
"strings"
"gorm.io/gorm/logger"
)
type DsnProvider interface {
Dsn() string
}
func (m *DB) Dsn() string {
return m.Username + ":" + m.Password + "@tcp(" + m.Path + ":" + m.Port + ")/" + m.Dbname + "?" + m.Config
// Embeded 结构体可以压平到上一层,从而保持 config 文件的结构和原来一样
// 见 playground: https://go.dev/play/p/KIcuhqEoxmY
// GeneralDB 也被 Pgsql 和 Mysql 原样使用
type GeneralDB struct {
Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` // 数据库前缀
Port string `mapstructure:"port" json:"port" yaml:"port"` // 数据库端口
Config string `mapstructure:"config" json:"config" yaml:"config"` // 高级配置
Dbname string `mapstructure:"db-name" json:"db-name" yaml:"db-name"` // 数据库名
Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库账号
Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码
Path string `mapstructure:"path" json:"path" yaml:"path"` // 数据库地址
Engine string `mapstructure:"engine" json:"engine" yaml:"engine" default:"InnoDB"` // 数据库引擎,默认InnoDB
LogMode string `mapstructure:"log-mode" json:"log-mode" yaml:"log-mode"` // 是否开启Gorm全局日志
MaxIdleConns int `mapstructure:"max-idle-conns" json:"max-idle-conns" yaml:"max-idle-conns"` // 空闲中的最大连接数
MaxOpenConns int `mapstructure:"max-open-conns" json:"max-open-conns" yaml:"max-open-conns"` // 打开到数据库的最大连接数
Singular bool `mapstructure:"singular" json:"singular" yaml:"singular"` // 是否开启全局禁用复数,true表示开启
LogZap bool `mapstructure:"log-zap" json:"log-zap" yaml:"log-zap"` // 是否通过zap写入日志文件
}
func (c GeneralDB) LogLevel() logger.LogLevel {
switch strings.ToLower(c.LogMode) {
case "silent":
return logger.Silent
case "error":
return logger.Error
case "warn":
return logger.Warn
case "info":
return logger.Info
default:
return logger.Info
}
}
type SpecializedDB struct {
Type string `mapstructure:"type" json:"type" yaml:"type"`
AliasName string `mapstructure:"alias-name" json:"alias-name" yaml:"alias-name"`
GeneralDB `yaml:",inline" mapstructure:",squash"`
Disable bool `mapstructure:"disable" json:"disable" yaml:"disable"`
}
+9
View File
@@ -0,0 +1,9 @@
package config
type Disk struct {
MountPoint string `mapstructure:"mount-point" json:"mount-point" yaml:"mount-point"`
}
type DiskList struct {
Disk `yaml:",inline" mapstructure:",squash"`
}
+8 -7
View File
@@ -1,11 +1,12 @@
package config
type Email struct {
To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔
Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口
From string `mapstructure:"from" json:"from" yaml:"from"` // 收件人
Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址
IsSSL bool `mapstructure:"is-ssl" json:"isSSL" yaml:"is-ssl"` // 是否SSL
Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥
Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称
To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔 例:a@qq.com b@qq.com 正式开发中请把此项目作为参数使用
From string `mapstructure:"from" json:"from" yaml:"from"` // 发件人 你自己要发邮件的邮箱
Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址 例如 smtp.qq.com 请前往QQ或者你要发邮件的邮箱查看其smtp协议
Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥 用于登录的密钥 最好不要用邮箱密码 去邮箱smtp申请一个用于登录的密钥
Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称 发件人昵称 通常为自己的邮箱
Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口 请前往QQ或者你要发邮件的邮箱查看其smtp协议 大多为 465
IsSSL bool `mapstructure:"is-ssl" json:"is-ssl" yaml:"is-ssl"` // 是否SSL 是否开启SSL
IsLoginAuth bool `mapstructure:"is-loginauth" json:"is-loginauth" yaml:"is-loginauth"` // 是否LoginAuth 是否使用LoginAuth认证方式(适用于IBM、微软邮箱服务器等)
}
+10
View File
@@ -0,0 +1,10 @@
package config
type Mssql struct {
GeneralDB `yaml:",inline" mapstructure:",squash"`
}
// Dsn "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
func (m *Mssql) Dsn() string {
return "sqlserver://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "?database=" + m.Dbname + "&encrypt=disable"
}
+1 -10
View File
@@ -1,16 +1,7 @@
package config
type Mysql struct {
Path string `mapstructure:"path" json:"path" yaml:"path"` // 服务器地址
Port string `mapstructure:"port" json:"port" yaml:"port"` // 端口
Config string `mapstructure:"config" json:"config" yaml:"config"` // 高级配置
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"` // 数据库名
Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库用户名
Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"` // 空闲中的最大连接数
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"` // 打开到数据库的最大连接数
LogMode string `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"` // 是否开启Gorm全局日志
LogZap bool `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"` // 是否通过zap写入日志文件
GeneralDB `yaml:",inline" mapstructure:",squash"`
}
func (m *Mysql) Dsn() string {
+18
View File
@@ -0,0 +1,18 @@
package config
import (
"fmt"
"net"
"net/url"
)
type Oracle struct {
GeneralDB `yaml:",inline" mapstructure:",squash"`
}
func (m *Oracle) Dsn() string {
dsn := fmt.Sprintf("oracle://%s:%s@%s/%s?%s", url.PathEscape(m.Username), url.PathEscape(m.Password),
net.JoinHostPort(m.Path, m.Port), url.PathEscape(m.Dbname), m.Config)
return dsn
}
+1 -10
View File
@@ -1,16 +1,7 @@
package config
type Pgsql struct {
Path string `mapstructure:"path" json:"path" yaml:"path"` // 服务器地址:端口
Port string `mapstructure:"port" json:"port" yaml:"port"` //:端口
Config string `mapstructure:"config" json:"config" yaml:"config"` // 高级配置
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"` // 数据库名
Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库用户名
Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"` // 空闲中的最大连接数
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"` // 打开到数据库的最大连接数
LogMode string `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"` // 是否开启Gorm全局日志
LogZap bool `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"` // 是否通过zap写入日志文件
GeneralDB `yaml:",inline" mapstructure:",squash"`
}
// Dsn 基于配置文件获取 dsn
+13
View File
@@ -0,0 +1,13 @@
package config
import (
"path/filepath"
)
type Sqlite struct {
GeneralDB `yaml:",inline" mapstructure:",squash"`
}
func (s *Sqlite) Dsn() string {
return filepath.Join(s.Path, s.Dbname+".db")
}
+4 -4
View File
@@ -1,8 +1,8 @@
package config
type JWT struct {
SigningKey string `mapstructure:"signing-key" json:"signingKey" yaml:"signing-key"` // jwt签名
ExpiresTime int64 `mapstructure:"expires-time" json:"expiresTime" yaml:"expires-time"` // 过期时间
BufferTime int64 `mapstructure:"buffer-time" json:"bufferTime" yaml:"buffer-time"` // 缓冲时间
Issuer string `mapstructure:"issuer" json:"issuer" yaml:"issuer"` // 签发者
SigningKey string `mapstructure:"signing-key" json:"signing-key" yaml:"signing-key"` // jwt签名
ExpiresTime string `mapstructure:"expires-time" json:"expires-time" yaml:"expires-time"` // 过期时间
BufferTime string `mapstructure:"buffer-time" json:"buffer-time" yaml:"buffer-time"` // 缓冲时间
Issuer string `mapstructure:"issuer" json:"issuer" yaml:"issuer"` // 签发者
}
+11
View File
@@ -0,0 +1,11 @@
package config
type MCP struct {
Name string `mapstructure:"name" json:"name" yaml:"name"` // MCP名称
Version string `mapstructure:"version" json:"version" yaml:"version"` // MCP版本
SSEPath string `mapstructure:"sse_path" json:"sse_path" yaml:"sse_path"` // SSE路径
MessagePath string `mapstructure:"message_path" json:"message_path" yaml:"message_path"` // 消息路径
UrlPrefix string `mapstructure:"url_prefix" json:"url_prefix" yaml:"url_prefix"` // URL前缀
Addr int `mapstructure:"addr" json:"addr" yaml:"addr"` // 独立MCP服务端口
Separate bool `mapstructure:"separate" json:"separate" yaml:"separate"` // 是否独立运行MCP服务
}
+41
View File
@@ -0,0 +1,41 @@
package config
import (
"fmt"
"strings"
)
type Mongo struct {
Coll string `json:"coll" yaml:"coll" mapstructure:"coll"` // collection name
Options string `json:"options" yaml:"options" mapstructure:"options"` // mongodb options
Database string `json:"database" yaml:"database" mapstructure:"database"` // database name
Username string `json:"username" yaml:"username" mapstructure:"username"` // 用户名
Password string `json:"password" yaml:"password" mapstructure:"password"` // 密码
AuthSource string `json:"auth-source" yaml:"auth-source" mapstructure:"auth-source"` // 验证数据库
MinPoolSize uint64 `json:"min-pool-size" yaml:"min-pool-size" mapstructure:"min-pool-size"` // 最小连接池
MaxPoolSize uint64 `json:"max-pool-size" yaml:"max-pool-size" mapstructure:"max-pool-size"` // 最大连接池
SocketTimeoutMs int64 `json:"socket-timeout-ms" yaml:"socket-timeout-ms" mapstructure:"socket-timeout-ms"` // socket超时时间
ConnectTimeoutMs int64 `json:"connect-timeout-ms" yaml:"connect-timeout-ms" mapstructure:"connect-timeout-ms"` // 连接超时时间
IsZap bool `json:"is-zap" yaml:"is-zap" mapstructure:"is-zap"` // 是否开启zap日志
Hosts []*MongoHost `json:"hosts" yaml:"hosts" mapstructure:"hosts"` // 主机列表
}
type MongoHost struct {
Host string `json:"host" yaml:"host" mapstructure:"host"` // ip地址
Port string `json:"port" yaml:"port" mapstructure:"port"` // 端口
}
// Uri .
func (x *Mongo) Uri() string {
length := len(x.Hosts)
hosts := make([]string, 0, length)
for i := 0; i < length; i++ {
if x.Hosts[i].Host != "" && x.Hosts[i].Port != "" {
hosts = append(hosts, x.Hosts[i].Host+":"+x.Hosts[i].Port)
}
}
if x.Options != "" {
return fmt.Sprintf("mongodb://%s/%s?%s", strings.Join(hosts, ","), x.Database, x.Options)
}
return fmt.Sprintf("mongodb://%s/%s", strings.Join(hosts, ","), x.Database)
}
+5 -5
View File
@@ -2,9 +2,9 @@ package config
type AliyunOSS struct {
Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
AccessKeyId string `mapstructure:"access-key-id" json:"accessKeyId" yaml:"access-key-id"`
AccessKeySecret string `mapstructure:"access-key-secret" json:"accessKeySecret" yaml:"access-key-secret"`
BucketName string `mapstructure:"bucket-name" json:"bucketName" yaml:"bucket-name"`
BucketUrl string `mapstructure:"bucket-url" json:"bucketUrl" yaml:"bucket-url"`
BasePath string `mapstructure:"base-path" json:"basePath" yaml:"base-path"`
AccessKeyId string `mapstructure:"access-key-id" json:"access-key-id" yaml:"access-key-id"`
AccessKeySecret string `mapstructure:"access-key-secret" json:"access-key-secret" yaml:"access-key-secret"`
BucketName string `mapstructure:"bucket-name" json:"bucket-name" yaml:"bucket-name"`
BucketUrl string `mapstructure:"bucket-url" json:"bucket-url" yaml:"bucket-url"`
BasePath string `mapstructure:"base-path" json:"base-path" yaml:"base-path"`
}
+13
View File
@@ -0,0 +1,13 @@
package config
type AwsS3 struct {
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
Region string `mapstructure:"region" json:"region" yaml:"region"`
Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
SecretID string `mapstructure:"secret-id" json:"secret-id" yaml:"secret-id"`
SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"`
BaseURL string `mapstructure:"base-url" json:"base-url" yaml:"base-url"`
PathPrefix string `mapstructure:"path-prefix" json:"path-prefix" yaml:"path-prefix"`
S3ForcePathStyle bool `mapstructure:"s3-force-path-style" json:"s3-force-path-style" yaml:"s3-force-path-style"`
DisableSSL bool `mapstructure:"disable-ssl" json:"disable-ssl" yaml:"disable-ssl"`
}
+10
View File
@@ -0,0 +1,10 @@
package config
type CloudflareR2 struct {
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
BaseURL string `mapstructure:"base-url" json:"base-url" yaml:"base-url"`
Path string `mapstructure:"path" json:"path" yaml:"path"`
AccountID string `mapstructure:"account-id" json:"account-id" yaml:"account-id"`
AccessKeyID string `mapstructure:"access-key-id" json:"access-key-id" yaml:"access-key-id"`
SecretAccessKey string `mapstructure:"secret-access-key" json:"secret-access-key" yaml:"secret-access-key"`
}
+2 -2
View File
@@ -4,6 +4,6 @@ type HuaWeiObs struct {
Path string `mapstructure:"path" json:"path" yaml:"path"`
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
AccessKey string `mapstructure:"access-key" json:"accessKey" yaml:"access-key"`
SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`
AccessKey string `mapstructure:"access-key" json:"access-key" yaml:"access-key"`
SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"`
}
+2 -1
View File
@@ -1,5 +1,6 @@
package config
type Local struct {
Path string `mapstructure:"path" json:"path" yaml:"path"` // 本地文件路径
Path string `mapstructure:"path" json:"path" yaml:"path"` // 本地文件访问路径
StorePath string `mapstructure:"store-path" json:"store-path" yaml:"store-path"` // 本地文件存储路径
}
+11
View File
@@ -0,0 +1,11 @@
package config
type Minio struct {
Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
AccessKeyId string `mapstructure:"access-key-id" json:"access-key-id" yaml:"access-key-id"`
AccessKeySecret string `mapstructure:"access-key-secret" json:"access-key-secret" yaml:"access-key-secret"`
BucketName string `mapstructure:"bucket-name" json:"bucket-name" yaml:"bucket-name"`
UseSSL bool `mapstructure:"use-ssl" json:"use-ssl" yaml:"use-ssl"`
BasePath string `mapstructure:"base-path" json:"base-path" yaml:"base-path"`
BucketUrl string `mapstructure:"bucket-url" json:"bucket-url" yaml:"bucket-url"`
}
+7 -7
View File
@@ -1,11 +1,11 @@
package config
type Qiniu struct {
Zone string `mapstructure:"zone" json:"zone" yaml:"zone"` // 存储区域
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` // 空间名称
ImgPath string `mapstructure:"img-path" json:"imgPath" yaml:"img-path"` // CDN加速域名
UseHTTPS bool `mapstructure:"use-https" json:"useHttps" yaml:"use-https"` // 是否使用https
AccessKey string `mapstructure:"access-key" json:"accessKey" yaml:"access-key"` // 秘钥AK
SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"` // 秘钥SK
UseCdnDomains bool `mapstructure:"use-cdn-domains" json:"useCdnDomains" yaml:"use-cdn-domains"` // 上传是否使用CDN上传加速
Zone string `mapstructure:"zone" json:"zone" yaml:"zone"` // 存储区域
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` // 空间名称
ImgPath string `mapstructure:"img-path" json:"img-path" yaml:"img-path"` // CDN加速域名
AccessKey string `mapstructure:"access-key" json:"access-key" yaml:"access-key"` // 秘钥AK
SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"` // 秘钥SK
UseHTTPS bool `mapstructure:"use-https" json:"use-https" yaml:"use-https"` // 是否使用https
UseCdnDomains bool `mapstructure:"use-cdn-domains" json:"use-cdn-domains" yaml:"use-cdn-domains"` // 上传是否使用CDN上传加速
}
+4 -4
View File
@@ -3,8 +3,8 @@ package config
type TencentCOS struct {
Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
Region string `mapstructure:"region" json:"region" yaml:"region"`
SecretID string `mapstructure:"secret-id" json:"secretID" yaml:"secret-id"`
SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`
BaseURL string `mapstructure:"base-url" json:"baseURL" yaml:"base-url"`
PathPrefix string `mapstructure:"path-prefix" json:"pathPrefix" yaml:"path-prefix"`
SecretID string `mapstructure:"secret-id" json:"secret-id" yaml:"secret-id"`
SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"`
BaseURL string `mapstructure:"base-url" json:"base-url" yaml:"base-url"`
PathPrefix string `mapstructure:"path-prefix" json:"path-prefix" yaml:"path-prefix"`
}
+6 -3
View File
@@ -1,7 +1,10 @@
package config
type Redis struct {
DB int `mapstructure:"db" json:"db" yaml:"db"` // redis的哪个数据库
Addr string `mapstructure:"addr" json:"addr" yaml:"addr"` // 服务器地址:端口
Password string `mapstructure:"password" json:"password" yaml:"password"` // 密码
Name string `mapstructure:"name" json:"name" yaml:"name"` // 代表当前实例的名字
Addr string `mapstructure:"addr" json:"addr" yaml:"addr"` // 服务器地址:端口
Password string `mapstructure:"password" json:"password" yaml:"password"` // 密码
DB int `mapstructure:"db" json:"db" yaml:"db"` // 单实例模式下redis的哪个数据库
UseCluster bool `mapstructure:"useCluster" json:"useCluster" yaml:"useCluster"` // 是否使用集群模式
ClusterAddrs []string `mapstructure:"clusterAddrs" json:"clusterAddrs" yaml:"clusterAddrs"` // 集群模式下的节点地址列表
}
+11 -7
View File
@@ -1,11 +1,15 @@
package config
type System struct {
Env string `mapstructure:"env" json:"env" yaml:"env"` // 环境值
Addr int `mapstructure:"addr" json:"addr" yaml:"addr"` // 端口值
DbType string `mapstructure:"db-type" json:"dbType" yaml:"db-type"` // 数据库类型:mysql(默认)|sqlite|sqlserver|postgresql
OssType string `mapstructure:"oss-type" json:"ossType" yaml:"oss-type"` // Oss类型
UseMultipoint bool `mapstructure:"use-multipoint" json:"useMultipoint" yaml:"use-multipoint"` // 多点登录拦截
LimitCountIP int `mapstructure:"iplimit-count" json:"iplimitCount" yaml:"iplimit-count"`
LimitTimeIP int `mapstructure:"iplimit-time" json:"iplimitTime" yaml:"iplimit-time"`
DbType string `mapstructure:"db-type" json:"db-type" yaml:"db-type"` // 数据库类型:mysql(默认)|sqlite|sqlserver|postgresql
OssType string `mapstructure:"oss-type" json:"oss-type" yaml:"oss-type"` // Oss类型
RouterPrefix string `mapstructure:"router-prefix" json:"router-prefix" yaml:"router-prefix"`
Addr int `mapstructure:"addr" json:"addr" yaml:"addr"` // 端口值
LimitCountIP int `mapstructure:"iplimit-count" json:"iplimit-count" yaml:"iplimit-count"`
LimitTimeIP int `mapstructure:"iplimit-time" json:"iplimit-time" yaml:"iplimit-time"`
UseMultipoint bool `mapstructure:"use-multipoint" json:"use-multipoint" yaml:"use-multipoint"` // 多点登录拦截
UseRedis bool `mapstructure:"use-redis" json:"use-redis" yaml:"use-redis"` // 使用redis
UseMongo bool `mapstructure:"use-mongo" json:"use-mongo" yaml:"use-mongo"` // 使用mongo
UseStrictAuth bool `mapstructure:"use-strict-auth" json:"use-strict-auth" yaml:"use-strict-auth"` // 使用树形角色分配模式
DisableAutoMigrate bool `mapstructure:"disable-auto-migrate" json:"disable-auto-migrate" yaml:"disable-auto-migrate"` // 自动迁移数据库表结构,生产环境建议设为false,手动迁移
}
-13
View File
@@ -1,13 +0,0 @@
package config
type Timer struct {
Start bool `mapstructure:"start" json:"start" yaml:"start"` // 是否启用
Spec string `mapstructure:"spec" json:"spec" yaml:"spec"` // CRON表达式
Detail []Detail `mapstructure:"detail" json:"detail" yaml:"detail"`
}
type Detail struct {
TableName string `mapstructure:"tableName" json:"tableName" yaml:"tableName"` // 需要清理的表名
CompareField string `mapstructure:"compareField" json:"compareField" yaml:"compareField"` // 需要比较时间的字段
Interval string `mapstructure:"interval" json:"interval" yaml:"interval"` // 时间间隔
}
+67 -8
View File
@@ -1,12 +1,71 @@
package config
import (
"go.uber.org/zap/zapcore"
"time"
)
type Zap struct {
Level string `mapstructure:"level" json:"level" yaml:"level"` // 级别
Format string `mapstructure:"format" json:"format" yaml:"format"` // 输出
Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` // 日志前缀
Director string `mapstructure:"director" json:"director" yaml:"director"` // 日志文件夹
ShowLine bool `mapstructure:"show-line" json:"showLine" yaml:"showLine"` // 显示行
EncodeLevel string `mapstructure:"encode-level" json:"encodeLevel" yaml:"encode-level"` // 编码级
StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktraceKey" yaml:"stacktrace-key"` // 栈名
LogInConsole bool `mapstructure:"log-in-console" json:"logInConsole" yaml:"log-in-console"` // 输出控制台
Level string `mapstructure:"level" json:"level" yaml:"level"` // 级别
Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` // 日志前缀
Format string `mapstructure:"format" json:"format" yaml:"format"` // 输出
Director string `mapstructure:"director" json:"director" yaml:"director"` // 日志文件夹
EncodeLevel string `mapstructure:"encode-level" json:"encode-level" yaml:"encode-level"` // 编码级
StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktrace-key" yaml:"stacktrace-key"` // 栈名
ShowLine bool `mapstructure:"show-line" json:"show-line" yaml:"show-line"` // 显示行
LogInConsole bool `mapstructure:"log-in-console" json:"log-in-console" yaml:"log-in-console"` // 输出控制台
RetentionDay int `mapstructure:"retention-day" json:"retention-day" yaml:"retention-day"` // 日志保留天数
}
// Levels 根据字符串转化为 zapcore.Levels
func (c *Zap) Levels() []zapcore.Level {
levels := make([]zapcore.Level, 0, 7)
level, err := zapcore.ParseLevel(c.Level)
if err != nil {
level = zapcore.DebugLevel
}
for ; level <= zapcore.FatalLevel; level++ {
levels = append(levels, level)
}
return levels
}
func (c *Zap) Encoder() zapcore.Encoder {
config := zapcore.EncoderConfig{
TimeKey: "time",
NameKey: "name",
LevelKey: "level",
CallerKey: "caller",
MessageKey: "message",
StacktraceKey: c.StacktraceKey,
LineEnding: zapcore.DefaultLineEnding,
EncodeTime: func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
encoder.AppendString(c.Prefix + t.Format("2006-01-02 15:04:05.000"))
},
EncodeLevel: c.LevelEncoder(),
EncodeCaller: zapcore.FullCallerEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
}
if c.Format == "json" {
return zapcore.NewJSONEncoder(config)
}
return zapcore.NewConsoleEncoder(config)
}
// LevelEncoder 根据 EncodeLevel 返回 zapcore.LevelEncoder
// Author [SliverHorn](https://github.com/SliverHorn)
func (c *Zap) LevelEncoder() zapcore.LevelEncoder {
switch {
case c.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
return zapcore.LowercaseLevelEncoder
case c.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
return zapcore.LowercaseColorLevelEncoder
case c.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
return zapcore.CapitalLevelEncoder
case c.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
return zapcore.CapitalColorLevelEncoder
default:
return zapcore.LowercaseLevelEncoder
}
}
+9
View File
@@ -0,0 +1,9 @@
package internal
const (
ConfigEnv = "GVA_CONFIG"
ConfigDefaultFile = "config.yaml"
ConfigTestFile = "config.test.yaml"
ConfigDebugFile = "config.debug.yaml"
ConfigReleaseFile = "config.release.yaml"
)
+125
View File
@@ -0,0 +1,125 @@
package internal
import (
"fmt"
"os"
"path/filepath"
"sync"
"time"
)
// Cutter 实现 io.Writer 接口
// 用于日志切割, strings.Join([]string{director,layout, formats..., level+".log"}, os.PathSeparator)
type Cutter struct {
level string // 日志级别(debug, info, warn, error, dpanic, panic, fatal)
layout string // 时间格式 2006-01-02 15:04:05
formats []string // 自定义参数([]string{Director,"2006-01-02", "business"(此参数可不写), level+".log"}
director string // 日志文件夹
retentionDay int //日志保留天数
file *os.File // 文件句柄
mutex *sync.RWMutex // 读写锁
}
type CutterOption func(*Cutter)
// CutterWithLayout 时间格式
func CutterWithLayout(layout string) CutterOption {
return func(c *Cutter) {
c.layout = layout
}
}
// CutterWithFormats 格式化参数
func CutterWithFormats(format ...string) CutterOption {
return func(c *Cutter) {
if len(format) > 0 {
c.formats = format
}
}
}
func NewCutter(director string, level string, retentionDay int, options ...CutterOption) *Cutter {
rotate := &Cutter{
level: level,
director: director,
retentionDay: retentionDay,
mutex: new(sync.RWMutex),
}
for i := 0; i < len(options); i++ {
options[i](rotate)
}
return rotate
}
// Write satisfies the io.Writer interface. It writes to the
// appropriate file handle that is currently being used.
// If we have reached rotation time, the target file gets
// automatically rotated, and also purged if necessary.
func (c *Cutter) Write(bytes []byte) (n int, err error) {
c.mutex.Lock()
defer func() {
if c.file != nil {
_ = c.file.Close()
c.file = nil
}
c.mutex.Unlock()
}()
length := len(c.formats)
values := make([]string, 0, 3+length)
values = append(values, c.director)
if c.layout != "" {
values = append(values, time.Now().Format(c.layout))
}
for i := 0; i < length; i++ {
values = append(values, c.formats[i])
}
values = append(values, c.level+".log")
filename := filepath.Join(values...)
director := filepath.Dir(filename)
err = os.MkdirAll(director, os.ModePerm)
if err != nil {
return 0, err
}
defer func() {
err := removeNDaysFolders(c.director, c.retentionDay)
if err != nil {
fmt.Println("清理过期日志失败", err)
}
}()
c.file, err = os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return 0, err
}
return c.file.Write(bytes)
}
func (c *Cutter) Sync() error {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.file != nil {
return c.file.Sync()
}
return nil
}
// 增加日志目录文件清理 小于等于零的值默认忽略不再处理
func removeNDaysFolders(dir string, days int) error {
if days <= 0 {
return nil
}
cutoff := time.Now().AddDate(0, 0, -days)
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() && info.ModTime().Before(cutoff) && path != dir {
err = os.RemoveAll(path)
if err != nil {
return err
}
}
return nil
})
}
+133
View File
@@ -0,0 +1,133 @@
package internal
import (
"context"
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
"github.com/flipped-aurora/gin-vue-admin/server/service"
astutil "github.com/flipped-aurora/gin-vue-admin/server/utils/ast"
"github.com/flipped-aurora/gin-vue-admin/server/utils/stacktrace"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
"strings"
"time"
)
type ZapCore struct {
level zapcore.Level
zapcore.Core
}
func NewZapCore(level zapcore.Level) *ZapCore {
entity := &ZapCore{level: level}
syncer := entity.WriteSyncer()
levelEnabler := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
return l == level
})
entity.Core = zapcore.NewCore(global.GVA_CONFIG.Zap.Encoder(), syncer, levelEnabler)
return entity
}
func (z *ZapCore) WriteSyncer(formats ...string) zapcore.WriteSyncer {
cutter := NewCutter(
global.GVA_CONFIG.Zap.Director,
z.level.String(),
global.GVA_CONFIG.Zap.RetentionDay,
CutterWithLayout(time.DateOnly),
CutterWithFormats(formats...),
)
if global.GVA_CONFIG.Zap.LogInConsole {
multiSyncer := zapcore.NewMultiWriteSyncer(os.Stdout, cutter)
return zapcore.AddSync(multiSyncer)
}
return zapcore.AddSync(cutter)
}
func (z *ZapCore) Enabled(level zapcore.Level) bool {
return z.level == level
}
func (z *ZapCore) With(fields []zapcore.Field) zapcore.Core {
return z.Core.With(fields)
}
func (z *ZapCore) Check(entry zapcore.Entry, check *zapcore.CheckedEntry) *zapcore.CheckedEntry {
if z.Enabled(entry.Level) {
return check.AddCore(entry, z)
}
return check
}
func (z *ZapCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
for i := 0; i < len(fields); i++ {
if fields[i].Key == "business" || fields[i].Key == "folder" || fields[i].Key == "directory" {
syncer := z.WriteSyncer(fields[i].String)
z.Core = zapcore.NewCore(global.GVA_CONFIG.Zap.Encoder(), syncer, z.level)
}
}
// 先写入原日志目标
err := z.Core.Write(entry, fields)
// 捕捉 Error 及以上级别日志并入库,且可提取 zap.Error(err) 的错误内容
if entry.Level >= zapcore.ErrorLevel {
// 避免与 GORM zap 写入互相递归:跳过由 gorm logger writer 触发的日志
if strings.Contains(entry.Caller.File, "gorm_logger_writer.go") {
return err
}
form := "后端"
level := entry.Level.String()
// 生成基础信息
info := entry.Message
// 提取 zap.Error(err) 内容
var errStr string
for i := 0; i < len(fields); i++ {
f := fields[i]
if f.Type == zapcore.ErrorType || f.Key == "error" || f.Key == "err" {
if f.Interface != nil {
errStr = fmt.Sprintf("%v", f.Interface)
} else if f.String != "" {
errStr = f.String
}
break
}
}
if errStr != "" {
info = fmt.Sprintf("%s | 错误: %s", info, errStr)
}
// 附加来源与堆栈信息
if entry.Caller.File != "" {
info = fmt.Sprintf("%s \n 源文件:%s:%d", info, entry.Caller.File, entry.Caller.Line)
}
stack := entry.Stack
if stack != "" {
info = fmt.Sprintf("%s \n 调用栈:%s", info, stack)
// 解析最终业务调用方,并提取其方法源码
if frame, ok := stacktrace.FindFinalCaller(stack); ok {
fnName, fnSrc, sLine, eLine, exErr := astutil.ExtractFuncSourceByPosition(frame.File, frame.Line)
if exErr == nil {
info = fmt.Sprintf("%s \n 最终调用方法:%s:%d (%s lines %d-%d)\n----- 产生日志的方法代码如下 -----\n%s", info, frame.File, frame.Line, fnName, sLine, eLine, fnSrc)
} else {
info = fmt.Sprintf("%s \n 最终调用方法:%s:%d (%s) | extract_err=%v", info, frame.File, frame.Line, fnName, exErr)
}
}
}
// 使用后台上下文,避免依赖 gin.Context
ctx := context.Background()
_ = service.ServiceGroupApp.SystemServiceGroup.SysErrorService.CreateSysError(ctx, &system.SysError{
Form: &form,
Info: &info,
Level: level,
})
}
return err
}
func (z *ZapCore) Sync() error {
return z.Core.Sync()
}
+26 -21
View File
@@ -2,24 +2,28 @@ package core
import (
"fmt"
"time"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/initialize"
"github.com/flipped-aurora/gin-vue-admin/server/service/system"
"go.uber.org/zap"
"time"
)
type server interface {
ListenAndServe() error
}
func RunWindowsServer() {
if global.GVA_CONFIG.System.UseMultipoint {
func RunServer() {
if global.GVA_CONFIG.System.UseRedis {
// 初始化redis服务
initialize.Redis()
if global.GVA_CONFIG.System.UseMultipoint {
initialize.RedisList()
}
}
if global.GVA_CONFIG.System.UseMongo {
err := initialize.Mongo.Initialization()
if err != nil {
zap.L().Error(fmt.Sprintf("%+v", err))
}
}
// 从db加载jwt数据
if global.GVA_DB != nil {
system.LoadAll()
@@ -27,23 +31,24 @@ func RunWindowsServer() {
Router := initialize.Routers()
Router.Static("/form-generator", "./resource/page")
address := fmt.Sprintf(":%d", global.GVA_CONFIG.System.Addr)
s := initServer(address, Router)
// 保证文本顺序输出
// In order to ensure that the text order output can be deleted
time.Sleep(10 * time.Microsecond)
global.GVA_LOG.Info("server run success on ", zap.String("address", address))
fmt.Printf(`
欢迎使用 github.com/flipped-aurora/gin-vue-admin/server
当前版本:V2.4.6
加群方式:微信号:shouzi_1994 QQ群:622360840
欢迎使用 gin-vue-admin
当前版本:%s
加群方式:微信号:shouzi_1994 QQ群:470239250
项目地址:https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com
GVA讨论社区:https://support.qq.com/products/371961
默认自动化文档地址:http://127.0.0.1%s/swagger/index.html
默认MCP SSE地址:http://127.0.0.1%s%s
默认MCP Message地址:http://127.0.0.1%s%s
默认前端文件运行地址:http://127.0.0.1:8080
如果项目让您获得了收益,希望您能请团队喝杯可乐:https://www.github.com/flipped-aurora/gin-vue-admin/server.com/docs/coffee
`, address)
global.GVA_LOG.Error(s.ListenAndServe().Error())
--------------------------------------版权声明--------------------------------------
** 版权所有方:flipped-aurora开源团队 **
** 版权持有公司:北京翻转极光科技有限责任公司 **
** 剔除授权标识需购买商用授权:https://plugin.gin-vue-admin.com/license **
** 感谢您对Gin-Vue-Admin的支持与关注 合法授权使用更有利于项目的长久发展**
`, global.Version, address, address, global.GVA_CONFIG.MCP.SSEPath, address, global.GVA_CONFIG.MCP.MessagePath)
initServer(address, Router, 10*time.Minute, 10*time.Minute)
}
-19
View File
@@ -1,19 +0,0 @@
//go:build !windows
// +build !windows
package core
import (
"time"
"github.com/fvbock/endless"
"github.com/gin-gonic/gin"
)
func initServer(address string, router *gin.Engine) server {
s := endless.NewServer(address, router)
s.ReadHeaderTimeout = 20 * time.Second
s.WriteTimeout = 20 * time.Second
s.MaxHeaderBytes = 1 << 20
return s
}
+60
View File
@@ -0,0 +1,60 @@
package core
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type server interface {
ListenAndServe() error
Shutdown(context.Context) error
}
// initServer 启动服务并实现优雅关闭
func initServer(address string, router *gin.Engine, readTimeout, writeTimeout time.Duration) {
// 创建服务
srv := &http.Server{
Addr: address,
Handler: router,
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
MaxHeaderBytes: 1 << 20,
}
// 在goroutine中启动服务
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
fmt.Printf("listen: %s\n", err)
zap.L().Error("server启动失败", zap.Error(err))
os.Exit(1)
}
}()
// 等待中断信号以优雅地关闭服务器
quit := make(chan os.Signal, 1)
// kill (无参数) 默认发送 syscall.SIGTERM
// kill -2 发送 syscall.SIGINT
// kill -9 发送 syscall.SIGKILL,但是无法被捕获,所以不需要添加
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
zap.L().Info("关闭WEB服务...")
// 设置5秒的超时时间
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
zap.L().Fatal("WEB服务关闭异常", zap.Error(err))
}
zap.L().Info("WEB服务已关闭")
}

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