Compare commits

...
219 Commits
Author SHA1 Message Date
pixel b5efcd251a Merge remote-tracking branch 'origin/master' 2021-03-05 20:33:58 +08:00
pixel b74ea58172 版本号更改提交 2021-03-05 20:30:02 +08:00
pixel 707dbac2ca 自动初始化中间件拦截 防止误操作无法进入初始化功能 2021-03-04 19:48:38 +08:00
pixel 184b1a903f 自动初始化整体调试完成 2021-03-04 19:38:07 +08:00
pixel 4a995a1c56 修复初始apibug 2021-03-04 16:02:17 +08:00
pixel e6768d5e17 cmd剔除 初始数据结构转移 修复初始携带apibug 2021-03-04 16:02:09 +08:00
pixel e3057c4bd9 自动初始化数据库功能后端部分完成 2021-03-04 15:57:07 +08:00
pixel 87f101a7bf 包位置调整 2021-03-02 19:53:26 +08:00
奇淼(piexlmax ab435d131c Merge pull request #387 from songzhibin97/gva_gormv2_dev
新增功能-api生成数据库并初始化回写配置
2021-03-02 19:29:34 +08:00
songzhibin97 674ae4c4a0 补充修改 2021-03-02 16:20:42 +08:00
songzhibin97 f3a84e2ca8 补充修改 2021-03-02 12:33:28 +08:00
songzhibin97 835dd15c47 订正了swagger
修改了
- server/api/v1/sys_initdb.go
- server/api/v1/sys_system.go
迁移了模型
- server/model/sys_init.go -> sysver/model/request/sys_init.go
2021-03-02 12:32:47 +08:00
pixel c983370162 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2021-03-01 10:33:26 +08:00
songzhibin97 00b5024f20 新增功能-api生成数据库并初始化回写配置
修改gva initdb 判断是否已经创建的一些小问题
新增api生成数据库并初始化回写配置
修改文件:
server/cmd/gva/initdb.go
server/cmd/information/data_authorities.go
server/cmd/information/workflow.go
server/initialize/gorm
server/main.go

新增文件:
server/api/v1/sys.initdb.go
server/middleware/init.go
server/model/sys_init.go
server/service/sys_initdb.go
servcer/utils/init_db.go

迁移文件
server/cmd/gva/mysql.go->server/utils/mysql.go
2021-02-27 17:32:41 +08:00
pixel ae0af55d17 字典样式修改 2021-02-27 12:48:18 +08:00
奇淼(piexlmax f19b398c93 Merge pull request #386 from songzhibin97/gva_gormv2_dev
新增api 重启服务(非windows)
2021-02-27 12:11:36 +08:00
songzhibin97 8743b63869 Update sys_system.go 2021-02-27 12:05:24 +08:00
songzhibin97 4af1627116 新增api重启系统(支持非windows)
修改
- server/api/v1/sys_system.go
- server/router/sys_system.go
2021-02-27 12:03:28 +08:00
pixel 5d4c4d53fc 前端系统配置增加 tencent-cos aliyun-oss 配置 2021-02-27 10:59:53 +08:00
pixel 62bc8092e2 对合并代码进行微调 2021-02-27 10:48:51 +08:00
pixel 4cea6f9f5d 更新了某些文本 让提示更加友好
根据scuxiatian提供的方案 修改了workflow前端组件的一些bug
2021-02-27 10:29:28 +08:00
奇淼(piexlmax decee13bf1 Merge pull request #384 from lauyang/develop
增加阿里云OSS
2021-02-27 10:26:15 +08:00
奇淼(piexlmax 60bfe48307 Merge branch 'develop' into develop 2021-02-27 10:26:00 +08:00
奇淼(piexlmax bca54282c9 Merge pull request #381 from MUHM/develop
为OSS增加腾讯云对象存储支持
2021-02-27 10:23:09 +08:00
pixel db933cecb6 更新了某些文本 让提示更加友好
根据scuxiatian提供的方案 修改了workflow前端组件的一些bug
2021-02-26 12:14:28 +08:00
yang.liu06 3f06c8ba7d add aliyun oss support 2021-02-24 22:07:50 +08:00
pixel f7fb34ec16 Merge remote-tracking branch 'origin/master' 2021-02-24 09:54:03 +08:00
pixel b691d53523 增加快速设置父级菜单功能 修复本地上传文件用户使用头像存在问题的bug 2021-02-24 09:53:45 +08:00
奇淼(piexlmax 5396aa40cb Update FUNDING.yml 2021-02-23 15:50:10 +08:00
pixel 1a43b89674 Merge remote-tracking branch 'origin/master' 2021-02-23 15:00:22 +08:00
奇淼(piexlmax fb570acf7c Merge pull request #376 from xiaoweihong/patch-1
NavigationDuplicated error
2021-02-23 15:00:03 +08:00
pixel 8c5d0ad64b Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin 2021-02-23 14:48:47 +08:00
pixel 74a92b08d8 更改 捐赠地址 2021-02-23 14:47:39 +08:00
klausY 3e6a3d97bb 提供一二级路由模板 2021-02-23 14:43:12 +08:00
pixel b3e4666108 Merge remote-tracking branch 'origin/master' 2021-02-23 11:00:56 +08:00
pixel a344f2bdb7 github.com/shirou/gopsutil 包版本修改为 v3.21.1 2021-02-23 10:39:03 +08:00
MUHM 4b6eb80ddb add TencentCOS support to OSS 2021-02-22 16:37:00 +08:00
奇淼(piexlmax 5226a2a26f Update FUNDING.yml 2021-02-20 11:00:04 +08:00
奇淼(piexlmax e8bb532cdc Update FUNDING.yml 2021-02-20 10:59:11 +08:00
pixel 171be652eb excel导入导出功能合并并且细节修改完成 2021-02-19 15:45:55 +08:00
xiaowei c410125c8f NavigationDuplicated error
NavigationDuplicated: Avoided redundant navigation to current location
![](https://img-blog.csdnimg.cn/20200901093646588.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjQwMjg0NQ==,size_16,color_FFFFFF,t_70)
2021-02-19 13:00:07 +08:00
pixel 0f6613c4a1 Merge branch 'develop' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev
 Conflicts:
	web/package.json
2021-02-14 21:41:34 +08:00
奇淼(piexlmax d278344dd4 Merge pull request #370 from hwb2017/develop-feature-excel
增加Excel导入导出示例功能
2021-02-14 21:40:04 +08:00
pixel c47b3eee2c 修复预览代码和生成代码均成为预览的问题 2021-02-14 12:54:17 +08:00
pixel 162b8df569 修复路径分割不同系统分隔符不同导致的panic 2021-02-14 12:53:47 +08:00
pixel 55e2109091 代码自动化生成支持预览功能 2021-02-13 16:24:38 +08:00
pixel 11efbe7699 initdb默认string长度改为191 2021-02-13 16:22:50 +08:00
pixel 329d094e2a Merge branch 'master' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2021-02-13 14:52:33 +08:00
奇淼(piexlmax 414766001b Merge pull request #374 from songzhibin97/gva_gormv2_dev
提供自动化代码预览功能
2021-02-13 14:51:28 +08:00
songzhibin97 e05e16dce4 抽出重复的内容优化PreviewTemp和CreateTemp 2021-02-11 19:33:11 +08:00
songzhibin97 3549f4cf1f 自动生成代码新增预览接口 2021-02-11 19:00:06 +08:00
pixel bedbd3c872 修复了子路由模式下两个keepalive相互切换 keepalive失效的问题 2021-02-09 19:25:56 +08:00
pixel 296110f969 修复了子路由模式下两个keepalive相互切换 keepalive失效的问题 2021-02-09 19:25:14 +08:00
hwb2017 f60b0f1750 增加Excel导入导出示例功能 2021-01-28 00:48:47 +08:00
SliverHorn 6ad13c5930 添加基础路由 返回错误后,仍然执行创建创建代码bug, 修复bug, #367 2021-01-26 17:12:51 +08:00
SliverHorn 6a1b53e3d4 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2021-01-26 17:10:07 +08:00
蒋吉兆 21ef7bdcc0 修改版本号 2021-01-24 17:44:00 +08:00
蒋吉兆 718574cdf3 修复了登陆时首页蓝点未点亮的bug 2021-01-24 17:36:38 +08:00
蒋吉兆 18571ca224 修复多次切换菜单后会出现路由地址改变,页面不变的情况 2021-01-24 17:08:35 +08:00
蒋吉兆 41c164a8ef Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin 2021-01-24 17:02:01 +08:00
蒋吉兆 f82acdb478 增加menu可配置是否自动关闭功能 增加单页面刷新功能 2021-01-24 17:01:43 +08:00
SliverHorn 40b56b6bf5 Merge pull request #364 from SliverHorn/gva_gormv2_dev
升级gva 工具 支持创建数据库与utf8mb4的sql修正功能, 版本迭代为v0.0.4
2021-01-21 22:54:33 +08:00
SliverHorn f259d69910 升级gva 工具 支持创建数据库与utf8mb4的sql修正功能, 版本迭代为v0.0.4 2021-01-21 19:44:55 +08:00
pixel 3952d5ec14 Merge branch 'develop' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev
 Conflicts:
	server/Makefile
	web/src/view/superAdmin/operation/sysOperationRecord.vue
2021-01-14 14:38:25 +08:00
pixel c1745f6f40 Merge branch 'master' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2021-01-14 14:33:59 +08:00
pixel 0940a70d86 支持默认首页 2021-01-14 12:37:49 +08:00
pixel 7abe6987a5 支持不同角色自定义首页 2021-01-14 12:28:13 +08:00
SliverHorn 7baa2c84a3 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2021-01-13 12:22:58 +08:00
songzhibin97 6867eb2c05 修复了在代码生成特殊情况下自动迁移文件移动错位置的情况
修改了services/sys_auto_code.go/addAutoMoveFile
修改了
services/sys_auto_code.go/CreateTemp
2021-01-13 12:03:11 +08:00
QM303176530 3d01706fb6 增加文件上传仓库配置注释说明 2021-01-10 23:48:50 +08:00
QM303176530 7707d4c99d 修复了媒体库中本地图片不显示的bug 2021-01-10 23:45:36 +08:00
QM303176530 b66d7a4e7a 解决了权限放在public组也会走权限控制的bug 2021-01-10 23:03:09 +08:00
pixel 8a67795faf 代码规范化整理 2021-01-08 17:34:17 +08:00
pixel 64299e6912 清理多余代码 2021-01-08 17:32:39 +08:00
pixel fdd522e56a 无用代码清理 2021-01-08 16:54:09 +08:00
奇淼(piexlmax 1c257fa830 Merge pull request #344 from 7beCn/master
修复table数据大于50条时页面卡死
2021-01-08 16:33:42 +08:00
SliverHorn 3d9fbbac63 Merge pull request #351 from flipped-aurora/gva_gormv2_dev
紧急修复bug
2021-01-05 23:13:55 +08:00
SliverHorn f83332b2c8 docker-compose shell 脚本更新 2021-01-05 23:02:11 +08:00
SliverHorn b8d187bb35 Makefile修改 4个空格 --> tab 2021-01-05 22:57:42 +08:00
SliverHorn 9567564bf4 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2020-12-30 20:58:01 +08:00
zzZ007 d05bf07db8 Update table.vue.tpl
修改自动生成代码,当table数据大于50条时,页面会卡死,替换掉 el-popover即可。
2020-12-30 17:20:35 +08:00
奇淼(piexlmax 5adb89694b Merge pull request #339 from flipped-aurora/revert-338-develop
Revert "修复了swag文档自动化生成失败的bug;完善了自动生成代码的swag部分"
2020-12-27 17:47:54 +08:00
奇淼(piexlmax e21146d048 Revert "修复了swag文档自动化生成失败的bug;完善了自动生成代码的swag部分" 2020-12-27 17:46:53 +08:00
QM303176530 4c7f04536d 修复了在当前表格当前页删除为空的情况下页面被锁死的bug 2020-12-27 17:46:11 +08:00
SliverHorn 71d0883c3d 优化gorm的自定义logger代码, 升级gorm的版本为1.20.9, Makefile 添加goproxy代理 2020-12-27 17:46:11 +08:00
pixel ee9022f9e3 user新建用户 bug处理 2020-12-27 17:46:11 +08:00
奇淼(piexlmax cc0a894162 Update README.md 2020-12-27 17:46:11 +08:00
奇淼(piexlmax d27f2ec966 Update README.md 2020-12-27 17:46:11 +08:00
pixel 83b7927c4b 登陆成功不再调用验证码接口 2020-12-27 17:46:11 +08:00
pixel e1975682a9 将JWT过期时间 刷新时间 放置进入config 2020-12-27 17:46:10 +08:00
pixel f914f96b9a 消除初始化时间0值报错 2020-12-27 17:46:10 +08:00
QM303176530 35a21d4e24 清理图标 form table 富文本 示例 2020-12-27 17:46:10 +08:00
奇淼(piexlmax 3e58190112 Update README.md 2020-12-27 17:46:10 +08:00
pixel 39150b2b2b 添加个人中心遮罩,添加自动更改title功能 2020-12-27 17:46:10 +08:00
SliverHorn f2b287f933 自定义logger保留gorm的格式输出控制台, 修改SetUserInfo的校验规则为IdVerify 2020-12-27 17:46:10 +08:00
QM303176530 e458e583ee 修复了在当前表格当前页删除为空的情况下页面被锁死的bug 2020-12-27 17:33:44 +08:00
奇淼(piexlmax 74c1fd5b7d Merge pull request #338 from ljj6218/develop
修复了swag文档自动化生成失败的bug;完善了自动生成代码的swag部分
2020-12-27 17:27:09 +08:00
QM303176530 2547ba88ae 修复了在当前表格当前页删除为空的情况下页面被锁死的bug 2020-12-27 17:20:54 +08:00
QM303176530 5c78ecc2d3 Merge branches 'develop' and 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2020-12-27 16:47:03 +08:00
奇淼(piexlmax 9c934917d0 Merge pull request #337 from SliverHorn/sliver_develop
优化gorm的自定义logger代码, 升级gorm的版本为1.20.9, Makefile 添加goproxy代理
2020-12-27 16:46:35 +08:00
奇淼(piexlmax 1132723355 Merge pull request #336 from JunIce/develop
chore: 增加自动扫描package.json, 从cdn引入资源
2020-12-27 16:44:29 +08:00
梁俊景 26261001f5 fix bug 2020-12-26 23:59:28 +08:00
梁俊景 2e3a1582ab 完善 2020-12-26 23:51:52 +08:00
梁俊景 5d1bcb3575 autocode 修复swag相关功能 2020-12-26 20:35:26 +08:00
SliverHorn 6c7d49b323 优化gorm的自定义logger代码, 升级gorm的版本为1.20.9, Makefile 添加goproxy代理 2020-12-26 00:52:18 +08:00
volcan0 843a585b7f chore: 增加自动扫描package.json, 从cdn引入资源 2020-12-25 14:03:49 +08:00
pixel 8df6fa6a33 user新建用户 bug处理 2020-12-19 16:05:52 +08:00
pixel 9ccb5439df Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin 2020-12-19 15:43:56 +08:00
奇淼(piexlmax 928d816c68 Update README.md 2020-12-16 15:51:25 +08:00
奇淼(piexlmax 27df9862ea Update README.md 2020-12-16 15:50:25 +08:00
pixel d428ed6876 登陆成功不再调用验证码接口 2020-12-16 15:44:37 +08:00
pixel 72fd7beec0 将JWT过期时间 刷新时间 放置进入config 2020-12-16 13:17:00 +08:00
pixel 7613b85271 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin 2020-12-16 11:43:45 +08:00
pixel 23eac98551 消除初始化时间0值报错 2020-12-16 11:43:22 +08:00
SliverHorn 8bd245b1f1 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2020-12-16 10:40:21 +08:00
QM303176530 b13bbfced1 清理图标 form table 富文本 示例 2020-12-13 12:42:38 +08:00
奇淼(piexlmax 645c788512 Update README.md 2020-12-11 15:12:28 +08:00
pixel 9f6c8f5e22 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2020-12-09 16:30:17 +08:00
pixel 9a4667fa46 添加个人中心遮罩,添加自动更改title功能 2020-12-09 16:30:06 +08:00
奇淼(piexlmax 338d81e101 Merge pull request #306 from SliverHorn/sliverhorn_dev
自定义logger保留gorm的格式输出控制台, 修改SetUserInfo的校验规则为IdVerify
2020-12-08 23:18:33 -06:00
SliverHorn 336d7473f7 自定义logger保留gorm的格式输出控制台, 修改SetUserInfo的校验规则为IdVerify 2020-12-07 12:11:50 +08:00
SliverHorn 265cd4d885 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2020-12-07 11:19:08 +08:00
QM303176530 cab8de721f 添加首字母小写方法 增加自动填充按键 2020-12-06 16:23:43 +08:00
QM303176530 4030cd325c Merge branches 'develop', 'gva_gormv2_dev' and 'master' of https://github.com/flipped-aurora/gin-vue-admin into develop 2020-12-06 15:37:36 +08:00
奇淼(piexlmax d796a39aa7 Merge pull request #299 from tingfeng-key/patch-1
Update image.vue
2020-12-06 01:24:42 -06:00
奇淼(piexlmax 04d8303f28 Merge pull request #304 from songzhibin97/gva_gormv2_dev
修改了热更正在运行时重启信号的丢弃
2020-12-06 01:21:10 -06:00
奇淼(piexlmax 5eec28a964 Merge pull request #302 from tingfeng-key/patch-3
添加自动填充功能
2020-12-06 01:20:49 -06:00
songzhibin97 a5e5c588ba Update cmd_Task.go 2020-12-05 22:49:57 +08:00
SliverHorn 34e6ccc6e2 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2020-12-04 23:20:45 +08:00
奇淼(piexlmax 6a028e13cb Merge pull request #303 from tingfeng-key/patch-4
修复提示权限不足和图片显示问题
2020-12-04 08:50:28 -06:00
听风 176e9d09b6 修复提示权限不足和图片显示问题
修复提示权限不足和图片显示问题
2020-12-04 22:35:25 +08:00
听风 7ddcf97efd 添加自动填充功能
添加自动填充功能。field字段填充json、数据库表,中文填充数据库表字段描述字段
2020-12-04 22:33:12 +08:00
听风 e19bda949b Update image.vue 2020-12-03 19:05:26 +08:00
听风 b09d142091 Update image.vue
修复上传图片组件bug
2020-12-03 18:16:03 +08:00
QM303176530 e102f820c1 修复了流程终止依然显示进行中的bug 2020-11-29 22:12:51 +08:00
QM303176530 36627e4ca5 操作人参数错误 2020-11-28 19:24:08 +08:00
QM303176530 9c6e6ca1b2 Merge branch 'master' of https://github.com/flipped-aurora/gin-vue-admin 2020-11-28 19:04:19 +08:00
QM303176530 f32fdbf543 增加自审批节点,修改待办查询bug,修改角色查询bug 2020-11-28 18:59:02 +08:00
奇淼(piexlmax 7342788339 Update README.md 2020-11-28 11:58:51 +08:00
QM303176530 15d6ff0144 Merge branches 'develop' and 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2020-11-28 11:47:18 +08:00
QM303176530 9718b16e39 增加首页教学入口 2020-11-28 11:43:54 +08:00
QM303176530 e80842207f 更新版本号 2020-11-28 11:07:54 +08:00
QM303176530 58585afdf6 默认丢出false 防止前端warnning 2020-11-28 11:06:44 +08:00
QM303176530 a3eee91cef 修复几个模板错误 2020-11-28 10:34:30 +08:00
QM303176530 9098eaf22e Merge branches 'gva_gormv2_dev' and 'gva_workflow' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2020-11-28 10:10:48 +08:00
pixel 2d3b039f71 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into develop 2020-11-25 17:18:35 +08:00
pixel 864c468440 命名修复 2020-11-25 17:18:07 +08:00
pixel cc295fad32 文件名更改 2020-11-25 17:11:11 +08:00
奇淼(piexlmax b4e0dc800d Merge pull request #290 from songzhibin97/develop
优化基础库的一些错误处理
2020-11-25 03:09:50 -06:00
奇淼(piexlmax 5e7078e3a6 Merge branch 'develop' into develop 2020-11-25 02:55:43 -06:00
songzhibin97 2829d7b653 优化基础库的一些错误处理 2020-11-25 16:24:20 +08:00
songzhibin97 ba834592a7 修改了zipfiles.go中ZipFiles函数可能会造成的goroutine泄露 2020-11-25 15:50:28 +08:00
奇淼(piexlmax 1607e6a0a9 Merge pull request #284 from xiaopenggithub/master
前端发布优化,部分组件使用cdn资源,不打包
2020-11-24 23:21:00 -06:00
奇淼(piexlmax f936029d59 Merge pull request #283 from SliverHorn/sliverhorn_dev
gorm日志收集进log功能
2020-11-24 23:09:16 -06:00
曾阿牛 9f1552f508 前端发布优化,部分组件使用cdn资源,不打包 2020-11-25 02:38:39 +08:00
SliverHorn c00d465709 新增切片越界的检查 2020-11-24 21:17:07 +08:00
SliverHorn c2a55931bb 自定义gorm的logger 2020-11-24 19:27:16 +08:00
SliverHorn e957e5ebc9 Merge branch 'master' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev 2020-11-24 19:10:21 +08:00
1319612909 1357e22330 手机端ui 2020-11-24 18:11:32 +08:00
pixel 8a282cd743 增加工作流步骤查看 2020-11-24 18:07:14 +08:00
1319612909 6ca7f62ce6 手机端ui 2020-11-24 17:20:12 +08:00
pixel 6ee7ad8069 隐藏0.01未完成功能 2020-11-24 16:59:31 +08:00
pixel 307b1bf496 工作流前端垃圾代码剔除 2020-11-24 16:08:40 +08:00
pixel 61f50980e1 增加自动化产生的工作流form页面 2020-11-24 16:07:55 +08:00
pixel 5293222ac0 包容网关 流转参数模式设定 2020-11-24 14:57:30 +08:00
奇淼(piexlmax 411a21d0f7 Merge pull request #282 from golyu/master
[utils/zipfiles.go]: 解决for循环中使用defer可能会造成的内存泄露问题
2020-11-23 21:46:11 -06:00
pixel 8a5d788e73 增加排他网关和包容网关 2020-11-24 11:33:16 +08:00
golyu 3e48fa55c7 [utils/zipfiles.go]: 解决for循环中使用defer可能会造成的内存泄露问题 2020-11-23 20:45:15 +08:00
pixel cd735e727e 普通工作流流动完成 2020-11-23 18:15:51 +08:00
pixel 1eb69c696a 普通工作流流动完成 2020-11-23 18:15:23 +08:00
pixel 8208ccf5a3 Merge branch 'master' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow
 Conflicts:
	server/initialize/router.go
	server/router/sys_workflow.go
2020-11-23 18:14:43 +08:00
pixel 1591944756 普通工作流流动完成 2020-11-23 18:13:46 +08:00
songzhibin97 8e87ae55a9 Revert "pointChange"
This reverts commit fb4dba1616.
2020-11-23 12:02:18 +08:00
songzhibin97 1ddd6dac4f pointChange 2020-11-22 18:05:51 +08:00
pixel a487266f5b 数据动态查找以及动态赋值方法变更 2020-11-19 17:24:05 +08:00
pixel 0286d56e9c 增加获取工作流详细页面信息的接口和对应调用 2020-11-18 18:06:31 +08:00
pixel 5bb840c1ce 调整初始化数据 2020-11-17 18:05:22 +08:00
pixel 8f221b6b0b Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow
 Conflicts:
	server/cmd/datas/init.go
2020-11-17 17:41:12 +08:00
pixel ac4398873b 增加初始化参数 2020-11-17 17:35:23 +08:00
pixel 2fad9035d3 增加工作流使用方法 接口
增加工作流通用完成方法
增加查询待办
查询我发起的工作流功能
增加测试示例
2020-11-17 16:41:43 +08:00
pixel 4863b2c5be 添加流转接口 设计流转表 2020-11-12 18:21:03 +08:00
pixel 86afc0ddf4 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow 2020-11-11 11:34:19 +08:00
pixel f4709f00ab 工作流起始接口以及动态获取view功能 2020-11-10 17:39:29 +08:00
pixel b12bbc74ff 更新workflow函数说明 清理无用workflow文件 2020-11-10 11:50:24 +08:00
pixel d3dbca0e00 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow
 Conflicts:
	server/api/v1/sys_work_flow.go
	server/service/sys_workflow.go
2020-11-10 11:43:56 +08:00
QM303176530 4828dc3dae 增加节点视图配置 2020-10-31 14:00:12 +08:00
QM303176530 8413f0e8d3 Merge branches 'gva_gormv2_dev' and 'gva_workflow' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow 2020-10-31 00:11:55 +08:00
QM303176530 5bfc5563b3 工作流增删改查功能完善 2020-10-31 00:04:42 +08:00
QM303176530 d6bc0572c2 工作流增删改查功能完善 2020-10-31 00:03:49 +08:00
QM303176530 32abd69c16 Merge branches 'gva_gormv2_dev', 'gva_workflow' and 'master' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow
 Conflicts:
	server/cmd/datas/init.go
2020-10-29 22:30:04 +08:00
pixel 02f155f497 整体结构变更 新增方法数据错乱问题修复 2020-10-29 17:57:29 +08:00
pixel c570c095b9 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow
 Conflicts:
	server/cmd/datas/apis.go
	server/cmd/datas/menus.go
	server/model/sys_workflow.go
	server/model/sys_workflow_process.go
2020-10-29 11:41:38 +08:00
pixel 0e1a820c3a 工作流入库功能 2020-10-29 09:37:02 +08:00
pixel bf21fec50e 工作流录入 根据id查询方法增加 2020-10-27 18:59:51 +08:00
pixel 4e514dc83e 自动化接口填充以及初始化数据制作 2020-10-27 17:38:13 +08:00
pixel 3f52783b30 Merge branch 'gva_workflow' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow 2020-10-27 16:39:56 +08:00
pixel 16bab848e1 增加description 2020-10-27 16:39:48 +08:00
QM303176530 b710f6a5df 增加快捷键复制粘贴 2020-10-26 20:57:48 +08:00
QM303176530 840723c592 Merge branch 'gva_workflow' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow 2020-10-26 20:45:28 +08:00
QM303176530 6f63290e74 取消无用节点 2020-10-26 20:44:55 +08:00
pixel 10b009bb7e 增加ctrl+z ctrl+y 2020-10-26 18:52:41 +08:00
pixel 8350dfe2c9 增加delete删除node功能 2020-10-26 18:21:01 +08:00
pixel e9c5ac6ec0 修改 workflow数据结构 2020-10-26 16:51:24 +08:00
pixel 247487529b 设计workflow数据结构 2020-10-26 13:37:55 +08:00
pixel 5ef5af4723 侧边更新 2020-10-26 13:31:11 +08:00
pixel 2188f79e77 Merge branch 'master' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow 2020-10-26 12:44:43 +08:00
pixel dc1cc2ec10 前端添加默认数据 2020-10-26 11:19:04 +08:00
QM303176530 e394a3afdf 忽略某些js文件的eslint 2020-10-25 11:27:38 +08:00
QM303176530 28dbad6c1f Merge branches 'gva_gormv2_dev' and 'gva_workflow' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow 2020-10-24 17:05:13 +08:00
QM303176530 84e35753cf 工作流插件参与进入项目本体 2020-10-24 17:04:04 +08:00
pixel cebb9b3002 修改默认数据 2020-10-23 14:29:09 +08:00
pixel 4abcbeb420 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow 2020-10-23 14:02:47 +08:00
pixel 77aea09d5f 修改目录结构 2020-10-23 13:58:48 +08:00
pixel c56e0416f2 Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow
 Conflicts:
	server/gva/init_data/init_data.go
2020-10-23 13:27:06 +08:00
QM303176530 9865d53ea7 Merge branches 'gva_workflow' and 'master' of https://github.com/flipped-aurora/gin-vue-admin into gva_workflow
 Conflicts:
	web/package.json
2020-10-11 12:24:11 +08:00
QM303176530 213d1a700f 更新gva-wfd的前端版本 2020-10-10 20:29:58 +08:00
pixel e18f0cae1a 修改工作流基础功能 2020-10-09 17:42:11 +08:00
pixel 973da4df7e Merge branch 'gva_gormv2_dev' of https://github.com/piexlmax/QMPlus into gva_workflow 2020-10-09 16:16:36 +08:00
pixel b9f7783878 增加工作流前端页面 2020-10-09 16:11:46 +08:00
258 changed files with 12632 additions and 2805 deletions
+4 -1
View File
@@ -10,6 +10,8 @@ cat>"${filename}"<<EOF
# jwt configuration
jwt:
signing-key: 'qmPlus'
expires-time: 604800
buffer-time: 86400
# zap logger configuration
zap:
@@ -65,8 +67,9 @@ mysql:
username: 'root'
password: 'Aa@6447985'
max-idle-conns: 10
max-open-conns: 10
max-open-conns: 100
log-mode: false
log-zap: ""
# local configuration
local:
+1 -1
View File
@@ -2,7 +2,7 @@
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
open_collective: gin-vue-admin
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+8 -4
View File
@@ -12,8 +12,11 @@
[English](./README-en.md) | 简体中文
[gitee地址](https://gitee.com/pixelmax/gin-vue-admin)|
[github地址](https://github.com/flipped-aurora/gin-vue-admin)
[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)
[vue3版本分支地址:https://github.com/flipped-aurora/gin-vue-admin/tree/vue3Develop](https://github.com/flipped-aurora/gin-vue-admin/tree/vue3Develop)
# 项目文档
[在线文档](https://www.gin-vue-admin.com/) : https://www.gin-vue-admin.com/
@@ -72,7 +75,7 @@ Gin-vue-admin 的成长离不开大家的支持,如果你愿意为 gin-vue-adm
- node版本 > v8.6.0
- golang版本 >= v1.14
- IDE推荐:Goland
- gormv2版本初始化数据库可以利用批量创建功能,这里已经写好初始化代码,需要在main.go内打开 initialize.Data() 的注释即可
- 初始化项目: 不同版本数据库初始化不通 参见https://www.gin-vue-admin.com/docs/server#1-%E5%88%9D%E5%A7%8B%E5%8C%96server%E9%A1%B9%E7%9B%AE
- 替换掉项目中的七牛云公钥,私钥,仓名和默认url地址,以免发生测试文件数据错乱
```
@@ -160,6 +163,8 @@ npm run serve
### 2.2 server端
使用 goland等编辑工具,打开server目录,不可以打开 gin-vue-admin跟目录
```bash
# 使用 go.mod
@@ -320,7 +325,6 @@ swag init
- [ ] 导入,导出Excel
- [ ] Echart图表支持
- [ ] 工作流,任务交接功能开发
- [ ] 单独前端使用模式以及数据模拟
## 7. 知识库
-43
View File
@@ -1,43 +0,0 @@
.PHONY: all build run gotool clean help
BINARY="server"
GVA = "gva"
all: check gva initdb run
gva:
go build -o ${GVA} cmd/main.go
initdb:
@if [ -f ${GVA} ] ; then ./gva initdb && rm ${GVA} ; fi
linux-build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
windows-build:
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ${BINARY}.exe
mac-build:
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o ${BINARY}
run:
@go run main.go
check:
go fmt ./
go vet ./
clean:
@if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi
@if [ -f ${GVA} ] ; then rm ${GVA} ; fi
help:
@echo "make - 构建gva终端工具并初始化数据,初始化数据后删除gva终端工具,启动server项目"
@echo "make gva - 构建gva终端工具"
@echo "make initdb - 如果有gva终端工具就初始化数据,初始化数据后删除gva终端工具,没有则不会执行"
@echo "make linux-build - 编译 Go 代码, 生成Linux系统的二进制文件"
@echo "make windows-build - 编译 Go 代码, 生成Windows系统的exe文件"
@echo "make mac-build - 编译 Go 代码, 生成Mac系统的二进制文件"
@echo "make run - 直接运行 main.go"
@echo "make clean - 移除二进制文件"
@echo "make check - 运行 Go 工具 'fmt' and 'vet'"
+99
View File
@@ -0,0 +1,99 @@
package v1
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"gin-vue-admin/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// /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 model.ExcelInfo true "导出Excel文件信息"
// @Success 200
// @Router /excel/exportExcel [post]
func ExportExcel(c *gin.Context) {
var excelInfo model.ExcelInfo
_ = c.ShouldBindJSON(&excelInfo)
filePath := global.GVA_CONFIG.Excel.Dir + excelInfo.FileName
err := service.ParseInfoList2Excel(excelInfo.InfoList, filePath)
if err != nil {
global.GVA_LOG.Error("转换Excel失败!", zap.Any("err", 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 ImportExcel(c *gin.Context) {
_, header, err := c.Request.FormFile("file")
if err != nil {
global.GVA_LOG.Error("接收文件失败!", zap.Any("err", 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 LoadExcel(c *gin.Context) {
menus, err := service.ParseExcel2InfoList()
if err != nil {
global.GVA_LOG.Error("加载数据失败", zap.Any("err", 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 fileName true "模板名称"
// @Success 200
// @Router /excel/downloadTemplate [get]
func 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.Any("err", err))
response.FailWithMessage("文件不存在", c)
return
}
c.Writer.Header().Add("success", "true")
c.File(filePath)
}
+1 -1
View File
@@ -75,6 +75,6 @@ func GetFileList(c *gin.Context) {
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
},"获取成功", c)
}, "获取成功", c)
}
}
+28 -3
View File
@@ -1,19 +1,44 @@
package v1
import (
"errors"
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"gin-vue-admin/utils"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"go.uber.org/zap"
"net/url"
"os"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// @Tags AutoCode
// @Summary 预览创建后的代码
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.AutoCodeStruct true "预览创建代码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/preview [post]
func PreviewTemp(c *gin.Context) {
var a model.AutoCodeStruct
_ = c.ShouldBindJSON(&a)
if err := utils.Verify(a, utils.AutoCodeVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
autoCode, err := service.PreviewTemp(a)
if err != nil {
global.GVA_LOG.Error("预览失败!", zap.Any("err", err))
response.FailWithMessage("预览失败", c)
} else {
response.OkWithDetailed(gin.H{"autoCode": autoCode}, "预览成功", c)
}
}
// @Tags AutoCode
// @Summary 自动代码模板
// @Security ApiKeyAuth
+58
View File
@@ -0,0 +1,58 @@
package v1
import (
"gin-vue-admin/global"
"gin-vue-admin/model/request"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"go.uber.org/zap"
"github.com/gin-gonic/gin"
)
// @Tags InitDB
// @Summary 初始化用户数据库
// @Produce application/json
// @Param data body request.InitDB true "初始化数据库参数"
// @Success 200 {string} string "{"code":0,"data":{},"msg":"自动创建数据库成功"}"
// @Router /init/initdb [post]
func InitDB(c *gin.Context) {
if global.GVA_DB != nil {
global.GVA_LOG.Error("非法访问")
response.FailWithMessage("非法访问", c)
return
}
var dbInfo request.InitDB
if err := c.ShouldBindJSON(&dbInfo); err != nil {
global.GVA_LOG.Error("参数校验不通过", zap.Any("err", err))
response.FailWithMessage("参数校验不通过", c)
return
}
if err := service.InitDB(dbInfo); err != nil {
global.GVA_LOG.Error("自动创建数据库失败", zap.Any("err", err))
response.FailWithMessage("自动创建数据库失败,请查看后台日志", c)
return
}
response.OkWithData("自动创建数据库成功", c)
}
// @Tags CheckDB
// @Summary 初始化用户数据库
// @Produce application/json
// @Success 200 {string} string "{"code":0,"data":{},"msg":"探测完成"}"
// @Router /init/checkdb [post]
func CheckDB(c *gin.Context) {
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
}
}
+18 -9
View File
@@ -5,6 +5,11 @@ import (
"gin-vue-admin/model"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"os"
"os/exec"
"runtime"
"strconv"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
@@ -42,23 +47,27 @@ func SetSystemConfig(c *gin.Context) {
}
}
// 本方法开发中 开发者windows系统 缺少linux系统所需的包 因此搁置
// @Tags System
// @Summary 重启系统
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body model.System true "重启系统"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"重启系统成功"}"
// @Router /system/ReloadSystem [post]
// @Success 200 {string} string "{"code":0,"data":{},"msg":"重启系统成功"}"
// @Router /system/reloadSystem [post]
func ReloadSystem(c *gin.Context) {
var sys model.System
_ = c.ShouldBindJSON(&sys)
if err := service.SetSystemConfig(sys); err != nil {
if runtime.GOOS == "windows" {
response.FailWithMessage("系统不支持", c)
return
}
pid := os.Getpid()
cmd := exec.Command("kill", "-1", strconv.Itoa(pid))
err := cmd.Run()
if err != nil {
global.GVA_LOG.Error("重启系统失败!", zap.Any("err", err))
response.FailWithMessage("重启系统失败", c)
} else {
response.OkWithMessage("重启系统成功", c)
return
}
response.OkWithMessage("重启系统成功", c)
return
}
// @Tags System
+5 -5
View File
@@ -50,11 +50,11 @@ func tokenNext(c *gin.Context, user model.SysUser) {
NickName: user.NickName,
Username: user.Username,
AuthorityId: user.AuthorityId,
BufferTime: 60 * 60 * 24, // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
BufferTime: global.GVA_CONFIG.JWT.BufferTime, // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
StandardClaims: jwt.StandardClaims{
NotBefore: time.Now().Unix() - 1000, // 签名生效时间
ExpiresAt: time.Now().Unix() + 60*60*24*7, // 过期时间 7天
Issuer: "qmPlus", // 签名的发行者
NotBefore: time.Now().Unix() - 1000, // 签名生效时间
ExpiresAt: time.Now().Unix() + global.GVA_CONFIG.JWT.ExpiresTime, // 过期时间 7天 配置文件
Issuer: "qmPlus", // 签名的发行者
},
}
token, err := j.CreateToken(claims)
@@ -240,7 +240,7 @@ func DeleteUser(c *gin.Context) {
func SetUserInfo(c *gin.Context) {
var user model.SysUser
_ = c.ShouldBindJSON(&user)
if err := utils.Verify(user, utils.SetUserVerify); err != nil {
if err := utils.Verify(user, utils.IdVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
-32
View File
@@ -1,32 +0,0 @@
package v1
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"gin-vue-admin/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// @Tags workflow
// @Summary 注册工作流
// @Produce application/json
// @Param data body model.SysWorkflow true "注册工作流接口"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"注册成功"}"
// @Router /workflow/createWorkFlow [post]
func CreateWorkFlow(c *gin.Context) {
var wk model.SysWorkflow
_ = c.ShouldBindJSON(&wk)
if err := utils.Verify(wk, utils.WorkFlowVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := service.Create(wk); err != nil {
global.GVA_LOG.Error("注册失败!", zap.Any("err", err))
response.FailWithMessage("注册失败", c)
} else {
response.OkWithMessage("注册成功", c)
}
}
+258
View File
@@ -0,0 +1,258 @@
package v1
import (
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"github.com/gin-gonic/gin"
)
// @Tags WorkflowProcess
// @Summary 创建WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "创建WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/createWorkflowProcess [post]
func CreateWorkflowProcess(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindJSON(&workflowProcess)
err := service.CreateWorkflowProcess(workflowProcess)
if err != nil {
response.FailWithMessage(fmt.Sprintf("创建失败,%v", err), c)
} else {
response.OkWithMessage("创建成功", c)
}
}
// @Tags WorkflowProcess
// @Summary 删除WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "删除WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /workflowProcess/deleteWorkflowProcess [delete]
func DeleteWorkflowProcess(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindJSON(&workflowProcess)
err := service.DeleteWorkflowProcess(workflowProcess)
if err != nil {
response.FailWithMessage(fmt.Sprintf("删除失败,%v", err), c)
} else {
response.OkWithMessage("删除成功", c)
}
}
// @Tags WorkflowProcess
// @Summary 批量删除WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /workflowProcess/deleteWorkflowProcessByIds [delete]
func DeleteWorkflowProcessByIds(c *gin.Context) {
var IDS request.IdsReq
_ = c.ShouldBindJSON(&IDS)
err := service.DeleteWorkflowProcessByIds(IDS)
if err != nil {
response.FailWithMessage(fmt.Sprintf("删除失败,%v", err), c)
} else {
response.OkWithMessage("删除成功", c)
}
}
// @Tags WorkflowProcess
// @Summary 更新WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "更新WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /workflowProcess/updateWorkflowProcess [put]
func UpdateWorkflowProcess(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindJSON(&workflowProcess)
err := service.UpdateWorkflowProcess(&workflowProcess)
if err != nil {
response.FailWithMessage(fmt.Sprintf("更新失败,%v", err), c)
} else {
response.OkWithMessage("更新成功", c)
}
}
// @Tags WorkflowProcess
// @Summary 用id查询WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "用id查询WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /workflowProcess/findWorkflowProcess [get]
func FindWorkflowProcess(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindQuery(&workflowProcess)
err, reworkflowProcess := service.GetWorkflowProcess(workflowProcess.ID)
if err != nil {
response.FailWithMessage(fmt.Sprintf("查询失败,%v", err), c)
} else {
response.OkWithData(gin.H{"reworkflowProcess": reworkflowProcess}, c)
}
}
// @Tags WorkflowProcess
// @Summary 用id查询工作流步骤
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "用id查询WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /workflowProcess/findWorkflowStep [get]
func FindWorkflowStep(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindQuery(&workflowProcess)
err, workflow := service.FindWorkflowStep(workflowProcess.ID)
if err != nil {
response.FailWithMessage(fmt.Sprintf("查询失败,%v", err), c)
} else {
response.OkWithData(gin.H{"workflow": workflow}, c)
}
}
// @Tags WorkflowProcess
// @Summary 分页获取WorkflowProcess列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.WorkflowProcessSearch true "分页获取WorkflowProcess列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getWorkflowProcessList [get]
func GetWorkflowProcessList(c *gin.Context) {
var pageInfo request.WorkflowProcessSearch
_ = c.ShouldBindQuery(&pageInfo)
err, list, total := service.GetWorkflowProcessInfoList(pageInfo)
if err != nil {
response.FailWithMessage(fmt.Sprintf("获取数据失败,%v", err), c)
} else {
response.OkWithData(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, c)
}
}
// @Tags WorkflowProcess
// @Summary 开启工作流
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/startWorkflow [post]
func StartWorkflow(c *gin.Context) {
business := c.Query("businessType")
wfInfo := model.WorkflowBusinessStruct[business]()
c.ShouldBindJSON(wfInfo)
err := service.StartWorkflow(wfInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithMessage("启动成功", c)
}
// @Tags WorkflowProcess
// @Summary 提交工作流
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/completeWorkflowMove [post]
func CompleteWorkflowMove(c *gin.Context) {
business := c.Query("businessType")
wfInfo := model.WorkflowBusinessStruct[business]()
c.ShouldBindJSON(wfInfo)
err := service.CompleteWorkflowMove(wfInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithMessage("启动成功", c)
}
// @Tags WorkflowProcess
// @Summary 我发起的工作流
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getMyStated [get]
func GetMyStated(c *gin.Context) {
if claims, exists := c.Get("claims"); !exists {
errStr := "从Gin的Context中获取从jwt解析出来的用户ID失败, 请检查路由是否使用jwt中间件"
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
} else {
waitUse := claims.(*request.CustomClaims)
err, wfms := service.GetMyStated(waitUse.ID)
if err != nil {
errStr := err.Error()
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
return
}
response.OkWithData(gin.H{"wfms": wfms}, c)
}
}
// @Tags WorkflowProcess
// @Summary 我的待办
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getMyNeed [get]
func GetMyNeed(c *gin.Context) {
if claims, exists := c.Get("claims"); !exists {
errStr := "从Gin的Context中获取从jwt解析出来的用户ID失败, 请检查路由是否使用jwt中间件"
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
} else {
waitUse := claims.(*request.CustomClaims)
err, wfms := service.GetMyNeed(waitUse.ID, waitUse.AuthorityId)
if err != nil {
errStr := err.Error()
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
return
}
response.OkWithData(gin.H{"wfms": wfms}, c)
}
}
// @Tags WorkflowProcess
// @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 /workflowProcess/getWorkflowMoveByID [get]
func GetWorkflowMoveByID(c *gin.Context) {
var req request.GetById
_ = c.ShouldBindQuery(&req)
err, move, moves, business := service.GetWorkflowMoveByID(req.Id)
if err != nil {
errStr := err.Error()
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
return
}
response.OkWithData(gin.H{"move": move, "moves": moves, "business": business}, c)
}
-14
View File
@@ -1,14 +0,0 @@
package datas
import (
"github.com/gookit/color"
"gorm.io/gorm"
)
func InitAuthorityMenu(db *gorm.DB) {
if err := db.Exec("CREATE ALGORITHM = UNDEFINED SQL SECURITY DEFINER VIEW `authority_menu` AS select `sys_base_menus`.`id` AS `id`,`sys_base_menus`.`created_at` AS `created_at`, `sys_base_menus`.`updated_at` AS `updated_at`, `sys_base_menus`.`deleted_at` AS `deleted_at`, `sys_base_menus`.`menu_level` AS `menu_level`,`sys_base_menus`.`parent_id` AS `parent_id`,`sys_base_menus`.`path` AS `path`,`sys_base_menus`.`name` AS `name`,`sys_base_menus`.`hidden` AS `hidden`,`sys_base_menus`.`component` AS `component`, `sys_base_menus`.`title` AS `title`,`sys_base_menus`.`icon` AS `icon`,`sys_base_menus`.`sort` AS `sort`,`sys_authority_menus`.`sys_authority_authority_id` AS `authority_id`,`sys_authority_menus`.`sys_base_menu_id` AS `menu_id`,`sys_base_menus`.`keep_alive` AS `keep_alive`,`sys_base_menus`.`default_menu` AS `default_menu` from (`sys_authority_menus` join `sys_base_menus` on ((`sys_authority_menus`.`sys_base_menu_id` = `sys_base_menus`.`id`)))").Error; err != nil {
color.Danger.Println("authority_menu视图已存在!")
return
}
color.Info.Println("authority_menu视图创建成功!")
}
-32
View File
@@ -1,32 +0,0 @@
package datas
import (
"github.com/gookit/color"
"os"
"time"
"gin-vue-admin/model"
"gorm.io/gorm"
)
var Authorities = []model.SysAuthority{
{CreatedAt: time.Now(), UpdatedAt: time.Now(), AuthorityId: "888", AuthorityName: "普通用户", ParentId: "0"},
{CreatedAt: time.Now(), UpdatedAt: time.Now(), AuthorityId: "8881", AuthorityName: "普通用户子角色", ParentId: "888"},
{CreatedAt: time.Now(), UpdatedAt: time.Now(), AuthorityId: "9528", AuthorityName: "测试角色", ParentId: "0"},
}
func InitSysAuthority(db *gorm.DB) {
if err := db.Transaction(func(tx *gorm.DB) error {
if tx.Where("authority_id IN ? ", []string{"888", "9528"}).Find(&[]model.SysAuthority{}).RowsAffected == 2 {
color.Danger.Println("sys_authorities表的初始数据已存在!")
return nil
}
if err := tx.Create(&Authorities).Error; err != nil { // 遇到错误时回滚事务
return err
}
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> sys_authorities 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
}
-36
View File
@@ -1,36 +0,0 @@
package datas
import (
"github.com/gookit/color"
"gorm.io/gorm"
"os"
)
type SysDataAuthorityId struct {
SysAuthorityAuthorityId string
DataAuthorityIdAuthorityId string
}
var DataAuthorityId = []SysDataAuthorityId{
{"888", "888"},
{"888", "8881"},
{"888", "9528"},
{"9528", "8881"},
{"9528", "9528"},
}
func InitSysDataAuthorityId(db *gorm.DB) {
if err := db.Table("sys_data_authority_id").Transaction(func(tx *gorm.DB) error {
if tx.Where("sys_authority_authority_id IN ?", []string{"888", "9528"}).Find(&[]SysDataAuthorityId{}).RowsAffected == 5 {
color.Danger.Println("sys_data_authority_id表的初始数据已存在!")
return nil
}
if err := tx.Create(&DataAuthorityId).Error; err != nil { // 遇到错误时回滚事务
return err
}
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> sys_data_authority_id 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
}
-84
View File
@@ -1,84 +0,0 @@
package datas
import (
"github.com/gookit/color"
"gorm.io/gorm"
"os"
)
type SysAuthorityMenus struct {
SysAuthorityAuthorityId string
SysBaseMenuId uint
}
var AuthorityMenus = []SysAuthorityMenus{
{"888", 1},
{"888", 2},
{"888", 3},
{"888", 4},
{"888", 5},
{"888", 6},
{"888", 7},
{"888", 8},
{"888", 9},
{"888", 10},
{"888", 11},
{"888", 12},
{"888", 13},
{"888", 14},
{"888", 15},
{"888", 16},
{"888", 17},
{"888", 18},
{"888", 19},
{"888", 20},
{"888", 21},
{"888", 22},
{"888", 23},
{"888", 24},
{"888", 25},
{"888", 26},
{"888", 27},
{"8881", 1},
{"8881", 2},
{"8881", 8},
{"8881", 17},
{"8881", 18},
{"8881", 19},
{"8881", 20},
{"9528", 1},
{"9528", 2},
{"9528", 3},
{"9528", 4},
{"9528", 5},
{"9528", 6},
{"9528", 7},
{"9528", 8},
{"9528", 9},
{"9528", 10},
{"9528", 11},
{"9528", 12},
{"9528", 13},
{"9528", 14},
{"9528", 15},
{"9528", 17},
{"9528", 18},
{"9528", 19},
{"9528", 20},
}
func InitSysAuthorityMenus(db *gorm.DB) {
if err := db.Table("sys_authority_menus").Transaction(func(tx *gorm.DB) error {
if tx.Where("sys_authority_authority_id IN ?", []string{"888", "8881", "9528"}).Find(&[]SysAuthorityMenus{}).RowsAffected == 53 {
color.Danger.Println("sys_authority_menus表的初始数据已存在!")
return nil
}
if err := tx.Create(&AuthorityMenus).Error; err != nil { // 遇到错误时回滚事务
return err
}
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> sys_authority_menus 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
}
-31
View File
@@ -1,31 +0,0 @@
package datas
import (
"gin-vue-admin/global"
"github.com/gookit/color"
"os"
"time"
"gin-vue-admin/model"
"gorm.io/gorm"
)
var Customers = []model.ExaCustomer{
{GVA_MODEL: global.GVA_MODEL{ID: 1, CreatedAt: time.Now(), UpdatedAt: time.Now()}, CustomerName: "测试客户", CustomerPhoneData: "1761111111", SysUserID: 1, SysUserAuthorityID: "888"},
}
func InitExaCustomer(db *gorm.DB) {
if err := db.Transaction(func(tx *gorm.DB) error {
if tx.Where("id IN ? ", []int{1}).Find(&[]model.ExaCustomer{}).RowsAffected == 1 {
color.Danger.Println("exa_customers表的初始数据已存在!")
return nil
}
if err := tx.Create(&Customers).Error; err != nil { // 遇到错误时回滚事务
return err
}
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> exa_customers 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
}
-54
View File
@@ -1,54 +0,0 @@
package datas
import (
"gin-vue-admin/model"
gormadapter "github.com/casbin/gorm-adapter/v3"
"github.com/gookit/color"
"gorm.io/gorm"
"os"
)
func InitMysqlData(db *gorm.DB) {
InitSysApi(db)
InitSysUser(db)
InitExaCustomer(db)
InitCasbinModel(db)
InitSysAuthority(db)
InitSysBaseMenus(db)
InitAuthorityMenu(db)
InitSysDictionary(db)
InitSysAuthorityMenus(db)
InitSysDataAuthorityId(db)
InitSysDictionaryDetail(db)
InitExaFileUploadAndDownload(db)
}
func InitMysqlTables(db *gorm.DB) {
var err error
if !db.Migrator().HasTable("casbin_rule") {
err = db.Migrator().CreateTable(&gormadapter.CasbinRule{})
}
err = db.AutoMigrate(
model.SysApi{},
model.SysUser{},
model.ExaFile{},
model.ExaCustomer{},
model.SysBaseMenu{},
model.SysWorkflow{},
model.SysAuthority{},
model.JwtBlacklist{},
model.ExaFileChunk{},
model.SysDictionary{},
model.ExaSimpleUploader{},
model.SysOperationRecord{},
model.SysWorkflowStepInfo{},
model.SysDictionaryDetail{},
model.SysBaseMenuParameter{},
model.ExaFileUploadAndDownload{},
)
if err != nil {
color.Warn.Printf("[Mysql]-->初始化数据表失败,err: %v\n", err)
os.Exit(0)
}
color.Info.Println("[Mysql]-->初始化数据表成功")
}
-74
View File
@@ -1,74 +0,0 @@
/*
Copyright © 2020 SliverHorn
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gva
import (
"gin-vue-admin/cmd/datas"
"gin-vue-admin/core"
"gin-vue-admin/initialize"
"github.com/gookit/color"
_ "gin-vue-admin/core"
"gin-vue-admin/global"
"github.com/spf13/cobra"
)
// initdbCmd represents the initdb command
var initdbCmd = &cobra.Command{
Use: "initdb",
Short: "gin-vue-admin初始化数据",
Long: `gin-vue-admin初始化数据适配数据库情况:
1. mysql完美适配,
2. postgresql不能保证完美适配,
3. sqlite未适配,
4. sqlserver未适配`,
Run: func(cmd *cobra.Command, args []string) {
path, _ := cmd.Flags().GetString("path")
global.GVA_VP = core.Viper(path)
global.GVA_LOG = core.Zap() // 初始化zap日志库
db := initialize.GormMysql()
switch global.GVA_CONFIG.System.DbType {
case "mysql":
datas.InitMysqlTables(db)
datas.InitMysqlData(db)
case "postgresql":
color.Info.Println("postgresql功能开发中")
case "sqlite":
color.Info.Println("sqlite功能开发中")
case "sqlserver":
color.Info.Println("sqlserver功能开发中")
default:
datas.InitMysqlTables(db)
datas.InitMysqlData(db)
}
frame, _ := cmd.Flags().GetString("frame")
if frame == "gf" {
color.Info.Println("gf功能开发中")
return
} else {
return
}
},
}
func init() {
rootCmd.AddCommand(initdbCmd)
initdbCmd.Flags().StringP("path", "p", "./config.yaml", "自定配置文件路径(绝对路径)")
initdbCmd.Flags().StringP("frame", "f", "gin", "可选参数为gin,gf")
initdbCmd.Flags().StringP("type", "t", "mysql", "可选参数为mysql,postgresql,sqlite,sqlserver")
}
-94
View File
@@ -1,94 +0,0 @@
/*
Copyright © 2020 SliverHorn
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gva
import (
"github.com/mitchellh/go-homedir"
"os"
"github.com/gookit/color"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "gva",
Short: "这是一款amazing的终端工具",
Long: `欢迎使用gva终端工具
________ ____ ____ _____
/ _____/ \ \ / / / _ \
/ \ ___ \ Y / / /_\ \
\ \_\ \ \ / / | \
\______ / \___/ \____|__ /
\/ \/
`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
color.Warn.Println(err)
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.gva.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
color.Warn.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".gva" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".gva")
}
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
color.Warn.Println("Using config file:", viper.ConfigFileUsed())
}
}
-53
View File
@@ -1,53 +0,0 @@
/*
Copyright © 2020 NAME HERE <EMAIL ADDRESS>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gva
import (
"gin-vue-admin/utils"
"github.com/spf13/cobra"
"os"
)
// runCmd represents the run command
var runCmd = &cobra.Command{
Use: "run",
Short: "running go codes with hot-compiled-like feature",
Long: `
The "run" command is used for running go codes with hot-compiled-like feature,
which compiles and runs the go codes asynchronously when codes change.
`,
Run: func(cmd *cobra.Command, args []string) {
w := utils.NewWatch()
t := utils.NewT()
path, _ := os.Getwd()
go w.Watch(path, t)
t.RunTask()
},
}
func init() {
rootCmd.AddCommand(runCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// runCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// runCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
-36
View File
@@ -1,36 +0,0 @@
/*
Copyright © 2020 SliverHorn
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gva
import (
"github.com/gookit/color"
"github.com/spf13/cobra"
)
// versionCmd represents the version command
var versionCmd = &cobra.Command{
Use: "version",
Short: "版本信息",
Long: `版本的长信息`,
Run: func(cmd *cobra.Command, args []string) {
color.Green.Println("v0.0.3")
},
}
func init() {
rootCmd.AddCommand(versionCmd)
}
-22
View File
@@ -1,22 +0,0 @@
/*
Copyright © 2020 SliverHorn
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import "gin-vue-admin/cmd/gva"
func main() {
gva.Execute()
}
+32 -7
View File
@@ -3,6 +3,8 @@
# jwt configuration
jwt:
signing-key: 'qmPlus'
expires-time: 604800
buffer-time: 86400
# zap logger configuration
zap:
@@ -41,7 +43,7 @@ system:
env: 'public' # Change to "develop" to skip authentication for development mode
addr: 8888
db-type: 'mysql'
oss-type: 'local'
oss-type: 'local' # 控制oss选择走本期还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置
use-multipoint: false
# captcha configuration
@@ -52,14 +54,15 @@ captcha:
# mysql connect configuration
mysql:
path: '127.0.0.1:3306'
config: 'charset=utf8mb4&parseTime=True&loc=Local'
db-name: 'qmPlus'
username: 'root'
password: 'Aa@6447985'
path: ''
config: ''
db-name: ''
username: ''
password: ''
max-idle-conns: 10
max-open-conns: 100
log-mode: false
log-zap: ""
# local configuration
local:
@@ -73,4 +76,26 @@ qiniu:
use-https: false
access-key: '25j8dYBZ2wuiy0yhwShytjZDTX662b8xiFguwxzZ'
secret-key: 'pgdbqEsf7ooZh7W3xokP833h3dZ_VecFXPDeG5JY'
use-cdn-domains: false
use-cdn-domains: false
# aliyun oss configuration
aliyun-oss:
endpoint: 'yourEndpoint'
access-key-id: 'yourAccessKeyId'
access-key-secret: 'yourAccessKeySecret'
bucket-name: 'yourBucketName'
bucket-url: 'yourBucketUrl'
# 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: 'gin-vue-admin'
# excel configuration
excel:
dir: './resource/excel/'
+6 -3
View File
@@ -9,8 +9,11 @@ type Server struct {
System System `mapstructure:"system" json:"system" yaml:"system"`
Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
// gorm
Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
// oss
Local Local `mapstructure:"local" json:"local" yaml:"local"`
Qiniu Qiniu `mapstructure:"qiniu" json:"qiniu" yaml:"qiniu"`
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"`
TencentCOS TencentCOS `mapstructure:"tencent-cos" json:"tencentCOS" yaml:"tencent-cos"`
Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"`
}
+5
View File
@@ -0,0 +1,5 @@
package config
type Excel struct {
Dir string `mapstructure:"dir" json:"dir" yaml:"dir"`
}
+5
View File
@@ -9,4 +9,9 @@ type Mysql struct {
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 bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"`
LogZap string `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"`
}
func (m *Mysql) Dsn() string {
return m.Username + ":" + m.Password + "@tcp(" + m.Path + ")/" + m.Dbname + "?" + m.Config
}
+3 -1
View File
@@ -1,5 +1,7 @@
package config
type JWT struct {
SigningKey string `mapstructure:"signing-key" json:"signingKey" yaml:"signing-key"`
SigningKey string `mapstructure:"signing-key" json:"signingKey" yaml:"signing-key"`
ExpiresTime int64 `mapstructure:"expires-time" json:"expiresTime" yaml:"expires-time"`
BufferTime int64 `mapstructure:"buffer-time" json:"bufferTime" yaml:"buffer-time"`
}
+16
View File
@@ -13,3 +13,19 @@ type Qiniu struct {
SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`
UseCdnDomains bool `mapstructure:"use-cdn-domains" json:"useCdnDomains" yaml:"use-cdn-domains"`
}
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"`
}
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"`
}
+19
View File
@@ -0,0 +1,19 @@
package constant
//定义clazz常量
const (
USER_TASK string = "userTask" // 审批节点
//SCRIPT_TASK string = "scriptTask" //脚本节点
//RECEIVE_TASK string = "receiveTask"
//MAIL_TASK string = "mailTask" //邮件节点
//TIMER_START string = "timerStart" // 定时节点
//MESSAGE_START string = "messageStart" // 消息节点
EXCLUSIVE_GATEWAY string = "exclusiveGateway" // 排他网关
INCLUSIVE_GATEWAY string = "inclusiveGateway" // 包容网关
PARELLEL_GATEWAY string = "parallelGateway" // 并行网关
FLOW string = "flow" // 连线
START string = "start" // 开始节点
END string = "end" // 结束节点
//PROCESS string = "process" // 基础节点
)
+3 -1
View File
@@ -17,6 +17,7 @@ func RunWindowsServer() {
// 初始化redis服务
initialize.Redis()
}
initialize.InitWkMode()
Router := initialize.Routers()
Router.Static("/form-generator", "./resource/page")
@@ -29,7 +30,8 @@ func RunWindowsServer() {
fmt.Printf(`
欢迎使用 Gin-Vue-Admin
当前版本:V2.3.7
当前版本:V2.4.0
加群方式:微信号:shouzi_1994 QQ群:622360840
默认自动化文档地址:http://127.0.0.1%s/swagger/index.html
默认前端文件运行地址:http://127.0.0.1:8080
如果项目让您获得了收益,希望您能请团队喝杯可乐:https://www.gin-vue-admin.com/docs/coffee
+9 -6
View File
@@ -3,8 +3,11 @@ module gin-vue-admin
go 1.14
require (
github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.2
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/casbin/casbin v1.9.1
github.com/casbin/casbin/v2 v2.11.0
github.com/casbin/gorm-adapter/v3 v3.0.2
@@ -33,10 +36,10 @@ require (
github.com/onsi/ginkgo v1.7.0 // indirect
github.com/onsi/gomega v1.4.3 // indirect
github.com/pelletier/go-toml v1.6.0 // indirect
github.com/pkg/errors v0.9.1
github.com/pkg/errors v0.9.1 // indirect
github.com/qiniu/api.v7/v7 v7.4.1
github.com/satori/go.uuid v1.2.0
github.com/shirou/gopsutil v2.20.8+incompatible
github.com/shirou/gopsutil v3.21.1+incompatible
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.1.1
@@ -45,16 +48,16 @@ require (
github.com/swaggo/gin-swagger v1.2.0
github.com/swaggo/swag v1.6.7
github.com/tebeka/strftime v0.1.3 // indirect
github.com/tencentyun/cos-go-sdk-v5 v0.7.19
github.com/unrolled/secure v1.0.7
go.uber.org/zap v1.10.0
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect
golang.org/x/sys v0.0.0-20200610111108-226ff32320da // indirect
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
golang.org/x/tools v0.0.0-20200324003944-a576cf524670 // indirect
google.golang.org/protobuf v1.24.0 // indirect
gopkg.in/ini.v1 v1.55.0 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
gorm.io/driver/mysql v0.3.0
gorm.io/gorm v1.20.5
gorm.io/gorm v1.20.9
)
replace github.com/casbin/gorm-adapter/v3 => github.com/casbin/gorm-adapter/v3 v3.0.2
replace github.com/casbin/gorm-adapter/v3 => github.com/casbin/gorm-adapter/v3 v3.0.2
-12
View File
@@ -1,12 +0,0 @@
@echo ##########Formatting code#########################################
go fmt ./ && go vet ./
@echo ##########Format the code successfully############################
@echo ##########Compiling gva.exe#######################################
go build -o gva.exe cmd/main.go
@echo ##########Successfully compiled gva.exe###########################
@echo ##########Initializing data using gva.exe#########################
gva.exe initdb
@echo ##########Use gva.exe to initialize data successfully#############
@echo ##########Deleting gva.exe########################################
del gva.exe
@echo ##########Deleting gva.exe successfully###########################
+58 -19
View File
@@ -2,15 +2,21 @@ package initialize
import (
"gin-vue-admin/global"
"gin-vue-admin/initialize/internal"
"gin-vue-admin/model"
"os"
"go.uber.org/zap"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"os"
)
// Gorm 初始化数据库并产生数据库全局变量
//@author: SliverHorn
//@function: Gorm
//@description: 初始化数据库并产生数据库全局变量
//@return: *gorm.DB
func Gorm() *gorm.DB {
switch global.GVA_CONFIG.System.DbType {
case "mysql":
@@ -20,7 +26,12 @@ func Gorm() *gorm.DB {
}
}
// MysqlTables 注册数据库表专用
// MysqlTables
//@author: SliverHorn
//@function: MysqlTables
//@description: 注册数据库表专用
//@param: db *gorm.DB
func MysqlTables(db *gorm.DB) {
err := db.AutoMigrate(
model.SysUser{},
@@ -29,8 +40,6 @@ func MysqlTables(db *gorm.DB) {
model.SysBaseMenu{},
model.SysBaseMenuParameter{},
model.JwtBlacklist{},
model.SysWorkflow{},
model.SysWorkflowStepInfo{},
model.SysDictionary{},
model.SysDictionaryDetail{},
model.ExaFileUploadAndDownload{},
@@ -39,6 +48,13 @@ func MysqlTables(db *gorm.DB) {
model.ExaSimpleUploader{},
model.ExaCustomer{},
model.SysOperationRecord{},
model.WorkflowProcess{},
model.WorkflowNode{},
model.WorkflowEdge{},
model.WorkflowStartPoint{},
model.WorkflowEndPoint{},
model.WorkflowMove{},
model.ExaWfLeave{},
)
if err != nil {
global.GVA_LOG.Error("register table failed", zap.Any("err", err))
@@ -47,9 +63,17 @@ func MysqlTables(db *gorm.DB) {
global.GVA_LOG.Info("register table success")
}
// GormMysql 初始化Mysql数据库
//
//@author: SliverHorn
//@function: GormMysql
//@description: 初始化Mysql数据库
//@return: *gorm.DB
func GormMysql() *gorm.DB {
m := global.GVA_CONFIG.Mysql
if m.Dbname == "" {
return nil
}
dsn := m.Username + ":" + m.Password + "@tcp(" + m.Path + ")/" + m.Dbname + "?" + m.Config
mysqlConfig := mysql.Config{
DSN: dsn, // DSN data source name
@@ -60,8 +84,9 @@ func GormMysql() *gorm.DB {
SkipInitializeWithVersion: false, // 根据版本自动配置
}
if db, err := gorm.Open(mysql.New(mysqlConfig), gormConfig(m.LogMode)); err != nil {
global.GVA_LOG.Error("MySQL启动异常", zap.Any("err", err))
os.Exit(0)
//global.GVA_LOG.Error("MySQL启动异常", zap.Any("err", err))
//os.Exit(0)
//return nil
return nil
} else {
sqlDB, _ := db.DB()
@@ -71,17 +96,31 @@ func GormMysql() *gorm.DB {
}
}
// gormConfig 根据配置决定是否开启日志
//@author: SliverHorn
//@function: gormConfig
//@description: 根据配置决定是否开启日志
//@param: mod bool
//@return: *gorm.Config
func gormConfig(mod bool) *gorm.Config {
if mod {
return &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
DisableForeignKeyConstraintWhenMigrating: true,
}
} else {
return &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
DisableForeignKeyConstraintWhenMigrating: true,
var config = &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}
switch global.GVA_CONFIG.Mysql.LogZap {
case "silent", "Silent":
config.Logger = internal.Default.LogMode(logger.Silent)
case "error", "Error":
config.Logger = internal.Default.LogMode(logger.Error)
case "warn", "Warn":
config.Logger = internal.Default.LogMode(logger.Warn)
case "info", "Info":
config.Logger = internal.Default.LogMode(logger.Info)
case "zap", "Zap":
config.Logger = internal.Default.LogMode(logger.Info)
default:
if mod {
config.Logger = internal.Default.LogMode(logger.Info)
break
}
config.Logger = internal.Default.LogMode(logger.Silent)
}
}
return config
}
+182
View File
@@ -0,0 +1,182 @@
package internal
import (
"context"
"fmt"
"gin-vue-admin/global"
"go.uber.org/zap"
"gorm.io/gorm/logger"
"gorm.io/gorm/utils"
"io/ioutil"
"log"
"os"
"time"
)
// writer log writer interface
type writer interface {
Printf(string, ...interface{})
}
type config struct {
SlowThreshold time.Duration
Colorful bool
LogLevel logger.LogLevel
}
var (
Discard = New(log.New(ioutil.Discard, "", log.LstdFlags), config{})
Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Warn,
Colorful: true,
})
Recorder = traceRecorder{Interface: Default, BeginAt: time.Now()}
)
func New(writer writer, config config) logger.Interface {
var (
infoStr = "%s\n[info] "
warnStr = "%s\n[warn] "
errStr = "%s\n[error] "
traceStr = "%s\n[%.3fms] [rows:%v] %s"
traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s"
traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s"
)
if config.Colorful {
infoStr = logger.Green + "%s\n" + logger.Reset + logger.Green + "[info] " + logger.Reset
warnStr = logger.BlueBold + "%s\n" + logger.Reset + logger.Magenta + "[warn] " + logger.Reset
errStr = logger.Magenta + "%s\n" + logger.Reset + logger.Red + "[error] " + logger.Reset
traceStr = logger.Green + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s"
traceWarnStr = logger.Green + "%s " + logger.Yellow + "%s\n" + logger.Reset + logger.RedBold + "[%.3fms] " + logger.Yellow + "[rows:%v]" + logger.Magenta + " %s" + logger.Reset
traceErrStr = logger.RedBold + "%s " + logger.MagentaBold + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s"
}
return &customLogger{
writer: writer,
config: config,
infoStr: infoStr,
warnStr: warnStr,
errStr: errStr,
traceStr: traceStr,
traceWarnStr: traceWarnStr,
traceErrStr: traceErrStr,
}
}
type customLogger struct {
writer
config
infoStr, warnStr, errStr string
traceStr, traceErrStr, traceWarnStr string
}
// LogMode log mode
func (c *customLogger) LogMode(level logger.LogLevel) logger.Interface {
newLogger := *c
newLogger.LogLevel = level
return &newLogger
}
// Info print info
func (c *customLogger) Info(ctx context.Context, message string, data ...interface{}) {
if c.LogLevel >= logger.Info {
c.Printf(c.infoStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Warn print warn messages
func (c *customLogger) Warn(ctx context.Context, message string, data ...interface{}) {
if c.LogLevel >= logger.Warn {
c.Printf(c.warnStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Error print error messages
func (c *customLogger) Error(ctx context.Context, message string, data ...interface{}) {
if c.LogLevel >= logger.Error {
c.Printf(c.errStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Trace print sql message
func (c *customLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
if c.LogLevel > 0 {
elapsed := time.Since(begin)
switch {
case err != nil && c.LogLevel >= logger.Error:
sql, rows := fc()
if rows == -1 {
c.Printf(c.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql)
} else {
c.Printf(c.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql)
}
case elapsed > c.SlowThreshold && c.SlowThreshold != 0 && c.LogLevel >= logger.Warn:
sql, rows := fc()
slowLog := fmt.Sprintf("SLOW SQL >= %v", c.SlowThreshold)
if rows == -1 {
c.Printf(c.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql)
} else {
c.Printf(c.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql)
}
case c.LogLevel >= logger.Info:
sql, rows := fc()
if rows == -1 {
c.Printf(c.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql)
} else {
c.Printf(c.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql)
}
}
}
}
func (c *customLogger) Printf(message string, data ...interface{}) {
if global.GVA_CONFIG.Mysql.LogZap != "" {
switch len(data) {
case 0:
global.GVA_LOG.Info(message)
case 1:
global.GVA_LOG.Info("gorm", zap.Any("src", data[0]))
case 2:
global.GVA_LOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]))
case 3:
global.GVA_LOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]), zap.Any("rows", data[2]))
case 4:
global.GVA_LOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]), zap.Any("rows", data[2]), zap.Any("sql", data[3]))
}
return
}
switch len(data) {
case 0:
c.writer.Printf(message, "")
case 1:
c.writer.Printf(message, data[0])
case 2:
c.writer.Printf(message, data[0], data[1])
case 3:
c.writer.Printf(message, data[0], data[1], data[2])
case 4:
c.writer.Printf(message, data[0], data[1], data[2], data[3])
case 5:
c.writer.Printf(message, data[0], data[1], data[2], data[3], data[4])
}
}
type traceRecorder struct {
logger.Interface
BeginAt time.Time
SQL string
RowsAffected int64
Err error
}
func (t traceRecorder) New() *traceRecorder {
return &traceRecorder{Interface: t.Interface, BeginAt: time.Now()}
}
func (t *traceRecorder) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
t.BeginAt = begin
t.SQL, t.RowsAffected = fc()
t.Err = err
}
+6 -3
View File
@@ -5,10 +5,11 @@ import (
"gin-vue-admin/global"
"gin-vue-admin/middleware"
"gin-vue-admin/router"
"net/http"
"github.com/gin-gonic/gin"
"github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
"net/http"
)
// 初始化总路由
@@ -19,7 +20,7 @@ func Routers() *gin.Engine {
// Router.Use(middleware.LoadTls()) // 打开就能玩https了
global.GVA_LOG.Info("use middleware logger")
// 跨域
Router.Use(middleware.Cors())
//Router.Use(middleware.Cors()) // 如需跨域可以打开
global.GVA_LOG.Info("use middleware cors")
Router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
global.GVA_LOG.Info("register swagger handler")
@@ -27,6 +28,7 @@ func Routers() *gin.Engine {
PublicGroup := Router.Group("")
{
router.InitBaseRouter(PublicGroup) // 注册基础功能路由 不做鉴权
router.InitInitRouter(PublicGroup) // 自动初始化相关
}
PrivateGroup := Router.Group("")
PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
@@ -38,7 +40,6 @@ func Routers() *gin.Engine {
router.InitEmailRouter(PrivateGroup) // 邮件相关路由
router.InitSystemRouter(PrivateGroup) // system相关路由
router.InitCasbinRouter(PrivateGroup) // 权限相关路由
router.InitWorkflowRouter(PrivateGroup) // 工作流相关路由
router.InitCustomerRouter(PrivateGroup) // 客户路由
router.InitAutoCodeRouter(PrivateGroup) // 创建自动化代码
router.InitAuthorityRouter(PrivateGroup) // 注册角色路由
@@ -47,6 +48,8 @@ func Routers() *gin.Engine {
router.InitSysOperationRecordRouter(PrivateGroup) // 操作记录
router.InitSysDictionaryDetailRouter(PrivateGroup) // 字典详情管理
router.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由
router.InitWorkflowProcessRouter(PrivateGroup) // 工作流相关接口
router.InitExcelRouter(PrivateGroup) // 表格导入导出
}
global.GVA_LOG.Info("router register success")
return Router
+22
View File
@@ -0,0 +1,22 @@
package initialize
import "gin-vue-admin/model"
func initWorkflowModel() {
model.WorkflowBusinessStruct = make(map[string]func() model.GVA_Workflow)
model.WorkflowBusinessStruct["leave"] = func() model.GVA_Workflow {
return new(model.ExaWfLeaveWorkflow)
}
}
func initWorkflowTable() {
model.WorkflowBusinessTable = make(map[string]func() interface{})
model.WorkflowBusinessTable["leave"] = func() interface{} {
return new(model.ExaWfLeave)
}
}
func InitWkMode() {
initWorkflowModel()
initWorkflowTable()
}
+9 -8
View File
@@ -14,13 +14,14 @@ import (
// @name x-token
// @BasePath /
func main() {
global.GVA_VP = core.Viper() // 初始化Viper
global.GVA_LOG = core.Zap() // 初始化zap日志库
global.GVA_DB = initialize.Gorm() // gorm连接数据库
initialize.MysqlTables(global.GVA_DB) // 初始化表
// 程序结束前关闭数据库链接
db, _ := global.GVA_DB.DB()
defer db.Close()
global.GVA_VP = core.Viper() // 初始化Viper
global.GVA_LOG = core.Zap() // 初始化zap日志库
global.GVA_DB = initialize.Gorm() // gorm连接数据库
if global.GVA_DB != nil {
initialize.MysqlTables(global.GVA_DB) // 初始化表
// 程序结束前关闭数据库链接
db, _ := global.GVA_DB.DB()
defer db.Close()
}
core.RunWindowsServer()
}
+1 -1
View File
@@ -47,7 +47,7 @@ func JWTAuth() gin.HandlerFunc {
c.Abort()
}
if claims.ExpiresAt-time.Now().Unix() < claims.BufferTime {
claims.ExpiresAt = time.Now().Unix() + 60*60*24*7
claims.ExpiresAt = time.Now().Unix() + global.GVA_CONFIG.JWT.ExpiresTime
newToken, _ := j.CreateToken(*claims)
newClaims, _ := j.ParseToken(newToken)
c.Header("new-token", newToken)
+22
View File
@@ -0,0 +1,22 @@
package middleware
import (
"gin-vue-admin/global"
"gin-vue-admin/model/response"
"github.com/gin-gonic/gin"
)
// 处理跨域请求,支持options访问
func NeedInit() gin.HandlerFunc {
return func(c *gin.Context) {
if global.GVA_DB == nil {
response.OkWithDetailed(gin.H{
"needInit": true,
}, "前往初始化数据库", c)
c.Abort()
} else {
c.Next()
}
// 处理请求
}
}
+6
View File
@@ -0,0 +1,6 @@
package model
type ExcelInfo struct {
FileName string `json:"fileName"`
InfoList []SysBaseMenu `json:"infoList"`
}
+25
View File
@@ -0,0 +1,25 @@
// 自动生成模板ExaWfLeave
package model
import (
"gin-vue-admin/global"
"time"
)
// 如果含有time.Time 请自行import time包
type ExaWfLeave struct {
global.GVA_MODEL
Cause string `json:"cause" form:"cause" gorm:"column:cause;comment:"`
StartTime time.Time `json:"startTime" form:"startTime" gorm:"column:start_time;comment:"`
EndTime time.Time `json:"endTime" form:"endTime" gorm:"column:end_time;comment:"`
}
type ExaWfLeaveWorkflow struct {
// 工作流操作结构体
WorkflowBase `json:"wf"`
ExaWfLeave `json:"business"`
}
func (ExaWfLeave) TableName() string {
return "exa_wf_leaves"
}
+1 -1
View File
@@ -20,4 +20,4 @@ type GetAuthorityId struct {
AuthorityId string
}
type Empty struct {}
type Empty struct{}
+9
View File
@@ -0,0 +1,9 @@
package request
type InitDB struct {
Host string `json:"host"`
Port string `json:"port"`
UserName string `json:"userName" binding:"required"`
Password string `json:"password"`
DBName string `json:"dbName" binding:"required"`
}
+8
View File
@@ -0,0 +1,8 @@
package request
import "gin-vue-admin/model"
type WorkflowProcessSearch struct {
model.WorkflowProcess
PageInfo
}
+1
View File
@@ -14,4 +14,5 @@ type SysAuthority struct {
DataAuthorityId []SysAuthority `json:"dataAuthorityId" gorm:"many2many:sys_data_authority_id"`
Children []SysAuthority `json:"children" gorm:"-"`
SysBaseMenus []SysBaseMenu `json:"menus" gorm:"many2many:sys_authority_menus;"`
DefaultRouter string `json:"defaultRouter" gorm:"comment:默认菜单;default:dashboard"`
}
+1
View File
@@ -24,6 +24,7 @@ type Meta struct {
DefaultMenu bool `json:"defaultMenu" gorm:"comment:是否是基础路由(开发中)"`
Title string `json:"title" gorm:"comment:菜单名"`
Icon string `json:"icon" gorm:"comment:菜单图标"`
CloseTab bool `json:"closeTab" gorm:"comment:自动关闭tab"`
}
type SysBaseMenuParameter struct {
+5
View File
@@ -0,0 +1,5 @@
package model
type InitDBFunc interface {
Init() (err error)
}
+145 -15
View File
@@ -2,24 +2,154 @@ package model
import (
"gin-vue-admin/global"
"gorm.io/gorm"
"time"
)
// 工作流属性表
type SysWorkflow struct {
global.GVA_MODEL
WorkflowNickName string `json:"workflowNickName" gorm:"comment:工作流中文名称"` // 工作流名称
WorkflowName string `json:"workflowName" gorm:"comment:工作流英文名称"` // 工作流英文id
WorkflowDescription string `json:"workflowDescription" gorm:"comment:工作流描述"` // 工作流描述
WorkflowStepInfo []SysWorkflowStepInfo `json:"workflowStep" gorm:"comment:工作流步骤"` // 工作流步骤
var WorkflowBusinessStruct map[string]func() GVA_Workflow
var WorkflowBusinessTable map[string]func() interface{}
type GVA_Workflow interface {
CreateWorkflowMove() *WorkflowMove
GetBusinessType() string
GetBusinessID() uint
GetWorkflowBase() WorkflowBase
}
// 工作流状态表
type SysWorkflowStepInfo struct {
type WorkflowBase struct {
WorkflowMoveID uint `json:"workflowMoveID" gorm:"-"`
BusinessID uint `json:"businessID" gorm:"<-:false;column:id"` // 业务对应ID(businessID)的返回
BusinessType string `json:"businessType" gorm:"-"`
PromoterID uint `json:"promoterID" gorm:"-"`
OperatorID uint `json:"operatorID" gorm:"-"`
WorkflowProcessID string `json:"workflowProcessID" gorm:"-"`
WorkflowNodeID string `json:"workflowNodeID" gorm:"-"`
Param string `json:"param" gorm:"-"`
Action string `json:"action" gorm:"-"`
}
func (w WorkflowBase) CreateWorkflowMove() (businessModel *WorkflowMove) {
return &WorkflowMove{
GVA_MODEL: global.GVA_MODEL{ID: w.WorkflowMoveID},
BusinessType: w.BusinessType,
PromoterID: w.PromoterID,
OperatorID: w.OperatorID,
Param: w.Param,
WorkflowProcessID: w.WorkflowProcessID,
WorkflowNodeID: w.WorkflowNodeID,
BusinessID: w.BusinessID,
Action: w.Action,
IsActive: true,
}
}
func (w WorkflowBase) GetBusinessType() (businessType string) {
return w.BusinessType
}
func (w WorkflowBase) GetBusinessID() (businessID uint) {
return w.BusinessID
}
func (w WorkflowBase) GetWorkflowBase() (workflowBase WorkflowBase) {
return w
}
type WorkflowMove struct {
global.GVA_MODEL
SysWorkflowID uint `json:"workflowID" gorm:"comment:所属工作流ID"` // 所属工作流ID
IsStart bool `json:"isStart" gorm:"comment:是否是开始流节点"` // 是否是开始流节点
StepName string `json:"stepName" gorm:"comment:工作流节点名称"` // 工作流名称
StepNo float64 `json:"stepNo" gorm:"comment:步骤id (第几步)"` // 步骤id (第几步)
StepAuthorityID string `json:"stepAuthorityID" gorm:"comment:操作者级别id"` // 操作者级别id
IsEnd bool `json:"isEnd" gorm:"comment:是否是完结流节点"` // 是否是完结流节点
WorkflowProcessID string `json:"workflowProcessID" gorm:"comment:工作流模板ID"`
WorkflowProcess WorkflowProcess `gorm:"<-:false" json:"workflowProcess" gorm:"comment:工作流模板具体信息"`
WorkflowNodeID string `json:"workflowNodeID" gorm:"comment:工作流节点ID"`
WorkflowNode WorkflowNode `gorm:"<-:false" json:"workflowNode" gorm:"comment:工作流节点具体信息"`
BusinessType string `json:"businessType" gorm:"comment:业务标记"`
BusinessID uint `json:"businessID" gorm:"comment:业务ID"`
PromoterID uint `json:"promoterID" gorm:"comment:当前流转发起人"`
Promoter SysUser `gorm:"<-:false" json:"promoter" gorm:"comment:当前流转发起人信息"`
OperatorID uint `json:"operatorID" gorm:"comment:当前流转操作人"`
Operator SysUser `gorm:"<-:false" json:"operator" gorm:"comment:当前流转操作人信息"`
Action string `json:"action" gorm:"comment:工作流驱动事件"`
Param string `json:"param" gorm:"comment:工作流驱动参数"`
IsActive bool `json:"isActive" gorm:"comment:是否是活跃节点 "`
}
type WorkflowProcess struct {
ID string `json:"id" form:"id" gorm:"comment:流程标识;primaryKey;unique;not null"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
Name string `json:"name" gorm:"comment:流程名称"`
Category string `json:"category" gorm:"comment:分类"`
Clazz string `json:"clazz" gorm:"comment:类型"`
Label string `json:"label" gorm:"comment:流程标题"`
HideIcon bool `json:"hideIcon" gorm:"comment:是否隐藏图标"`
Description string `json:"description" gorm:"comment:详细介绍"`
View string `json:"view" gorm:"comment:前端视图文件"`
Nodes []WorkflowNode `json:"nodes"` // 流程节点数据
Edges []WorkflowEdge `json:"edges"` // 流程链接数据
}
type WorkflowNode struct {
ID string `json:"id" form:"id" gorm:"comment:节点id;primaryKey;unique;not null"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
WorkflowProcessID string `json:"workflowProcessID" gorm:"comment:流程标识"`
Clazz string `json:"clazz" gorm:"comment:节点类型"`
Label string `json:"label" gorm:"comment:节点名称"`
Type string `json:"type" gorm:"comment:图标类型"`
Shape string `json:"shape" gorm:"comment:形状"`
Description string `json:"description" gorm:"comment:详细介绍"`
View string `json:"view" gorm:"comment:前端视图文件"`
X float64 `json:"y" gorm:"comment:x位置"`
Y float64 `json:"x" gorm:"comment:y位置"`
WaitState string `json:"waitState" gorm:"comment:等待属性"`
StateValue string `json:"stateValue" gorm:"comment:等待值"`
To string `json:"to" gorm:"comment:收件人"`
Subject string `json:"subject" gorm:"comment:标题"`
Content string `json:"content" gorm:"comment:内容"`
Cycle string `json:"cycle" gorm:"comment:循环时间"`
Duration string `json:"duration" gorm:"comment:持续时间"`
HideIcon bool `json:"hideIcon" gorm:"comment:是否隐藏图标"`
DueDate *time.Time `json:"dueDate" gorm:"comment:到期时间"`
AssignType string `json:"assignType" gorm:"comment:审批类型"`
AssignValue string `json:"assignValue" gorm:"comment:审批类型值"`
Success bool `json:"success" gorm:"comment:是否成功"`
}
type WorkflowEdge struct {
ID string `json:"id" form:"id" gorm:"comment:唯一标识;primaryKey;unique;not null"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
WorkflowProcessID string `json:"-" gorm:"comment:流程标识"`
Clazz string `json:"clazz" gorm:"comment:类型(线)"`
Source string `json:"source" gorm:"comment:起点节点"`
Target string `json:"target" gorm:"comment:目标节点"`
SourceAnchor int `json:"sourceAnchor" gorm:"comment:起点"`
TargetAnchor int `json:"targetAnchor" gorm:"comment:目标点"`
Description string `json:"description" gorm:"comment:详细介绍"`
Shape string `json:"shape" gorm:"comment:形状"`
StartPoint WorkflowStartPoint `json:"startPoint"` // 起点信息
EndPoint WorkflowEndPoint `json:"endPoint"` // 终点信息
Label string `json:"label" gorm:"comment:标题"`
HideIcon bool `json:"hideIcon" gorm:"comment:隐藏图标"`
ConditionExpression string `json:"conditionExpression" gorm:"comment:条件标识"`
Seq string `json:"seq" gorm:"comment:序号"`
Reverse bool `json:"reverse" gorm:"comment:是否反向"`
}
type WorkflowStartPoint struct {
WorkflowEdgeID string
global.GVA_MODEL
X float64 `json:"x"`
Y float64 `json:"y"`
Index int `json:"index"`
}
type WorkflowEndPoint struct {
WorkflowEdgeID string
global.GVA_MODEL
X float64 `json:"x"`
Y float64 `json:"y"`
Index int `json:"index"`
}
-16
View File
@@ -1,16 +0,0 @@
package model
import (
"gin-vue-admin/global"
)
// 工作流流转表
type SysWorkFlowProcess struct {
global.GVA_MODEL
ApplicationID uint `json:"applicationID" gorm:"comment:当前工作流所属申请的ID"` // 当前工作流所属申请的ID
CurrentNode string `json:"currentNode" gorm:"comment:当前进度节点"` // 当前进度节点
HistoricalNode string `json:"historicalNode" gorm:"comment:上一个进度节点"` // 上一个进度节点
CurrentUser string `json:"currentUser" gorm:"comment:当前进度操作人"` // 当前进度操作人
HistoricalUser string `json:"historicalUser" gorm:"comment:上一个进度的操作人"` // 上一个进度的操作人
State bool `json:"state" gorm:"comment:是否是正在进行的状态"` // 状态 是否是正在进行的状态
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -78,7 +78,7 @@ func Delete{{.StructName}}ByIds(c *gin.Context) {
func Update{{.StructName}}(c *gin.Context) {
var {{.Abbreviation}} model.{{.StructName}}
_ = c.ShouldBindJSON(&{{.Abbreviation}})
if err := service.Update{{.StructName}}(&{{.Abbreviation}}); err != nil {
if err := service.Update{{.StructName}}({{.Abbreviation}}); err != nil {
global.GVA_LOG.Error("更新失败!", zap.Any("err", err))
response.FailWithMessage("更新失败", c)
} else {
+24 -1
View File
@@ -19,4 +19,27 @@ type {{.StructName}} struct {
func ({{.StructName}}) TableName() string {
return "{{.TableName}}"
}
{{ end }}
{{ end }}
// 如果使用工作流功能 需要打开下方注释 并到initialize的workflow中进行注册 且必须指定TableName
// type {{.StructName}}Workflow struct {
// // 工作流操作结构体
// WorkflowBase `json:"wf"`
// {{.StructName}} `json:"business"`
// }
// func ({{.StructName}}) TableName() string {
// return "{{.TableName}}"
// }
// 工作流注册代码
// initWorkflowModel内部注册
// model.WorkflowBusinessStruct["{{.Abbreviation}}"] = func() model.GVA_Workflow {
// return new(model.{{.StructName}}Workflow)
// }
// initWorkflowTable内部注册
// model.WorkflowBusinessTable["{{.Abbreviation}}"] = func() interface{} {
// return new(model.{{.StructName}})
// }
@@ -7,7 +7,7 @@ import (
)
func Init{{.StructName}}Router(Router *gin.RouterGroup) {
{{.StructName}}Router := Router.Group("{{.Abbreviation}}").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler()).Use(middleware.OperationRecord())
{{.StructName}}Router := Router.Group("{{.Abbreviation}}").Use(middleware.OperationRecord())
{
{{.StructName}}Router.POST("create{{.StructName}}", v1.Create{{.StructName}}) // 新建{{.StructName}}
{{.StructName}}Router.DELETE("delete{{.StructName}}", v1.Delete{{.StructName}}) // 删除{{.StructName}}
@@ -24,7 +24,7 @@ func Create{{.StructName}}({{.Abbreviation}} model.{{.StructName}}) (err error)
//@return: err error
func Delete{{.StructName}}({{.Abbreviation}} model.{{.StructName}}) (err error) {
err = global.GVA_DB.Delete({{.Abbreviation}}).Error
err = global.GVA_DB.Delete(&{{.Abbreviation}}).Error
return err
}
@@ -45,8 +45,8 @@ func Delete{{.StructName}}ByIds(ids request.IdsReq) (err error) {
//@param: {{.Abbreviation}} *model.{{.StructName}}
//@return: err error
func Update{{.StructName}}({{.Abbreviation}} *model.{{.StructName}}) (err error) {
err = global.GVA_DB.Save({{.Abbreviation}}).Error
func Update{{.StructName}}({{.Abbreviation}} model.{{.StructName}}) (err error) {
err = global.GVA_DB.Save(&{{.Abbreviation}}).Error
return err
}
+17 -11
View File
@@ -68,14 +68,7 @@
<el-table-column label="按钮组">
<template slot-scope="scope">
<el-button class="table-button" @click="update{{.StructName}}(scope.row)" size="small" type="primary" icon="el-icon-edit">变更</el-button>
<el-popover placement="top" width="160" v-model="scope.row.visible">
<p>确定要删除吗?</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="scope.row.visible = false">取消</el-button>
<el-button type="primary" size="mini" @click="delete{{.StructName}}(scope.row)">确定</el-button>
</div>
<el-button type="danger" icon="el-icon-delete" size="mini" slot="reference">删除</el-button>
</el-popover>
<el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -145,7 +138,6 @@ export default {
return {
listApi: get{{ .StructName }}List,
dialogFormVisible: false,
visible: false,
type: "",
deleteVisible: false,
multipleSelection: [],
@@ -208,6 +200,15 @@ export default {
handleSelectionChange(val) {
this.multipleSelection = val
},
deleteRow(row){
this.$confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.delete{{.StructName}}(row);
});
},
async onDelete() {
const ids = []
if(this.multipleSelection.length == 0){
@@ -227,6 +228,9 @@ export default {
type: 'success',
message: '删除成功'
})
if (this.tableData.length == ids.length) {
this.page--;
}
this.deleteVisible = false
this.getTableData()
}
@@ -262,13 +266,15 @@ export default {
};
},
async delete{{.StructName}}(row) {
this.visible = false;
const res = await delete{{.StructName}}({ ID: row.ID });
if (res.code == 0) {
this.$message({
type: "success",
message: "删除成功"
});
if (this.tableData.length == 1) {
this.page--;
}
this.getTableData();
}
},
@@ -311,4 +317,4 @@ export default {
</script>
<style>
</style>
</style>
@@ -0,0 +1,183 @@
<template>
<div>
<el-form :model="formData" label-position="right" label-width="80px">
{{- range .Fields}}
<el-form-item label="{{.FieldDesc}}:">
{{- if eq .FieldType "bool" }}
<el-switch active-color="#13ce66" inactive-color="#ff4949" active-text="是" inactive-text="否" v-model="formData.{{.FieldJson}}" clearable ></el-switch>
{{ end -}}
{{- if eq .FieldType "string" }}
<el-input v-model="formData.{{.FieldJson}}" clearable placeholder="请输入" ></el-input>
{{ end -}}
{{- if eq .FieldType "int" }}
{{- if .DictType}}
<el-select v-model="formData.{{ .FieldJson }}" placeholder="请选择" clearable>
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value"></el-option>
</el-select>
{{ else -}}
<el-input v-model.number="formData.{{ .FieldJson }}" clearable placeholder="请输入"></el-input>
{{ end -}}
{{ end -}}
{{- if eq .FieldType "time.Time" }}
<el-date-picker type="date" placeholder="选择日期" v-model="formData.{{ .FieldJson }}" clearable></el-date-picker>
{{ end -}}
{{- if eq .FieldType "float64" }}
<el-input-number v-model="formData.{{ .FieldJson }}" :precision="2" clearable></el-input-number>
{{ end -}}
</el-form-item>
{{ end -}}
<el-form-item>
<el-button v-if="this.wf.clazz == 'start'" @click="start" type="primary">启动</el-button>
<!-- complete传入流转参数 决定下一步会流转到什么位置 此处可以设置多个按钮来做不同的流转 -->
<el-button v-if="canShow" @click="complete('yes')" type="primary">提交</el-button>
<el-button v-if="showSelfNode" @click="complete('')" type="primary">确认</el-button>
<el-button @click="back" type="primary">返回</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import {
startWorkflow,
completeWorkflowMove
} from "@/api/workflowProcess";
import infoList from "@/mixins/infoList";
import { mapGetters } from "vuex";
export default {
name: "{{.StructName}}",
mixins: [infoList],
props:{
business:{
type:Object,
default:function(){return null}
},
wf:{
type:Object,
default:function(){return{}}
},
move:{
type:Object,
default:function(){return{}}
},
workflowMoveID:{
type:[Number,String],
default:0
}
},
data() {
return {
{{- range .Fields}}
{{- if .DictType }}
{{ .DictType }}Options:[],
{{ end -}}
{{end -}}
formData: {
{{range .Fields}}
{{- if eq .FieldType "bool" -}}
{{.FieldJson}}:false,
{{ end -}}
{{- if eq .FieldType "string" -}}
{{.FieldJson}}:"",
{{ end -}}
{{- if eq .FieldType "int" -}}
{{.FieldJson}}:0,
{{ end -}}
{{- if eq .FieldType "time.Time" -}}
{{.FieldJson}}:new Date(),
{{ end -}}
{{- if eq .FieldType "float64" -}}
{{.FieldJson}}:0,
{{ end -}}
{{ end }}
}
};
},
computed:{
showSelfNode(){
if(this.wf.assignType == "self" && this.move.promoterID == this.userInfo.ID){
return true
}else{
return false
}
},
canShow(){
if(this.wf.assignType == "user"){
if(this.wf.assignValue.indexOf(","+this.userInfo.ID+",")>-1 && this.wf.clazz == 'userTask'){
return true
}else{
return false
}
}else if(this.wf.assign_type == "authority"){
if(this.wf.assignValue.indexOf(","+this.userInfo.authorityId+",")>-1 && this.wf.clazz == 'userTask'){
return true
}else{
return false
}
}
},
...mapGetters("user", ["userInfo"])
},
methods: {
async start() {
const res = await startWorkflow({
business:this.formData,
wf:{
workflowMoveID:this.workflowMoveID,
businessId:0,
businessType:"{{.Abbreviation}}",
workflowProcessID:this.wf.workflowProcessID,
workflowNodeID:this.wf.id,
promoterID:this.userInfo.ID,
operatorID:this.userInfo.ID,
action:"create",
param:""
}
});
if (res.code == 0) {
this.$message({
type:"success",
message:"启动成功"
})
this.back()
}
},
async complete(param){
const res = await completeWorkflowMove({
business:this.formData,
wf:{
workflowMoveID:this.workflowMoveID,
businessID:this.formData.ID,
businessType:"{{.Abbreviation}}",
workflowProcessID:this.wf.workflowProcessID,
workflowNodeID:this.wf.id,
promoterID:this.userInfo.ID,
operatorID:this.userInfo.ID,
action:"complete",
param:param
}
})
if(res.code == 0){
this.$message({
type:"success",
message:"提交成功"
})
this.back()
}
},
back(){
this.$router.go(-1)
}
},
async created() {
if(this.business){
this.formData = this.business
}
}
};
</script>
<style>
</style>
+16
View File
@@ -0,0 +1,16 @@
package router
import (
"gin-vue-admin/api/v1"
"github.com/gin-gonic/gin"
)
func InitExcelRouter(Router *gin.RouterGroup) {
FileUploadAndDownloadGroup := Router.Group("excel")
{
FileUploadAndDownloadGroup.POST("/importExcel", v1.ImportExcel) // 导入Excel
FileUploadAndDownloadGroup.GET("/loadExcel", v1.LoadExcel) // 加载Excel数据
FileUploadAndDownloadGroup.POST("/exportExcel", v1.ExportExcel) // 导出Excel
FileUploadAndDownloadGroup.GET("/downloadTemplate", v1.DownloadTemplate) // 下载模板文件
}
}
+1
View File
@@ -8,6 +8,7 @@ import (
func InitAutoCodeRouter(Router *gin.RouterGroup) {
AutoCodeRouter := Router.Group("autoCode")
{
AutoCodeRouter.POST("preview", v1.PreviewTemp) // 获取自动创建代码预览
AutoCodeRouter.POST("createTemp", v1.CreateTemp) // 创建自动化代码
AutoCodeRouter.GET("getTables", v1.GetTables) // 获取对应数据库的表
AutoCodeRouter.GET("getDB", v1.GetDB) // 获取数据库
+2 -1
View File
@@ -2,11 +2,12 @@ package router
import (
"gin-vue-admin/api/v1"
"gin-vue-admin/middleware"
"github.com/gin-gonic/gin"
)
func InitBaseRouter(Router *gin.RouterGroup) (R gin.IRoutes) {
BaseRouter := Router.Group("base")
BaseRouter := Router.Group("base").Use(middleware.NeedInit())
{
BaseRouter.POST("login", v1.Login)
BaseRouter.POST("captcha", v1.Captcha)
+14
View File
@@ -0,0 +1,14 @@
package router
import (
"gin-vue-admin/api/v1"
"github.com/gin-gonic/gin"
)
func InitInitRouter(Router *gin.RouterGroup) {
ApiRouter := Router.Group("init")
{
ApiRouter.POST("initdb", v1.InitDB) // 创建Api
ApiRouter.POST("checkdb", v1.CheckDB) // 创建Api
}
}
+1
View File
@@ -12,5 +12,6 @@ func InitSystemRouter(Router *gin.RouterGroup) {
SystemRouter.POST("getSystemConfig", v1.GetSystemConfig) // 获取配置文件内容
SystemRouter.POST("setSystemConfig", v1.SetSystemConfig) // 设置配置文件内容
SystemRouter.POST("getServerInfo", v1.GetServerInfo) // 获取服务器信息
SystemRouter.POST("reloadSystem", v1.ReloadSystem) // 重启服务
}
}
+14 -3
View File
@@ -6,9 +6,20 @@ import (
"github.com/gin-gonic/gin"
)
func InitWorkflowRouter(Router *gin.RouterGroup) {
WorkflowRouter := Router.Group("workflow").Use(middleware.OperationRecord())
func InitWorkflowProcessRouter(Router *gin.RouterGroup) {
WorkflowProcessRouter := Router.Group("workflowProcess").Use(middleware.OperationRecord())
{
WorkflowRouter.POST("createWorkFlow", v1.CreateWorkFlow) // 创建工作流
WorkflowProcessRouter.POST("createWorkflowProcess", v1.CreateWorkflowProcess) // 新建WorkflowProcess
WorkflowProcessRouter.DELETE("deleteWorkflowProcess", v1.DeleteWorkflowProcess) // 删除WorkflowProcess
WorkflowProcessRouter.DELETE("deleteWorkflowProcessByIds", v1.DeleteWorkflowProcessByIds) // 批量删除WorkflowProcess
WorkflowProcessRouter.PUT("updateWorkflowProcess", v1.UpdateWorkflowProcess) // 更新WorkflowProcess
WorkflowProcessRouter.GET("findWorkflowProcess", v1.FindWorkflowProcess) // 根据ID获取WorkflowProcess
WorkflowProcessRouter.GET("findWorkflowStep", v1.FindWorkflowStep) // 根据ID获取工作流步骤
WorkflowProcessRouter.GET("getWorkflowProcessList", v1.GetWorkflowProcessList) // 获取WorkflowProcess列表
WorkflowProcessRouter.POST("startWorkflow", v1.StartWorkflow) // 开启工作流
WorkflowProcessRouter.POST("completeWorkflowMove", v1.CompleteWorkflowMove) // 提交工作流
WorkflowProcessRouter.GET("getMyStated", v1.GetMyStated) // 获取我发起的工作流
WorkflowProcessRouter.GET("getMyNeed", v1.GetMyNeed) // 获取我的待办
WorkflowProcessRouter.GET("getWorkflowMoveByID", v1.GetWorkflowMoveByID) // 获取我的待办
}
}
+1 -1
View File
@@ -24,7 +24,7 @@ func CreateExaCustomer(e model.ExaCustomer) (err error) {
//@return: err error
func DeleteExaCustomer(e model.ExaCustomer) (err error) {
err = global.GVA_DB.Delete(e).Error
err = global.GVA_DB.Delete(&e).Error
return err
}
+91
View File
@@ -0,0 +1,91 @@
package service
import (
"errors"
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model"
"github.com/360EntSecGroup-Skylar/excelize/v2"
"strconv"
)
func ParseInfoList2Excel(infoList []model.SysBaseMenu, filePath string) error {
excel := excelize.NewFile()
excel.SetSheetRow("Sheet1","A1",&[]string{"ID","路由Name","路由Path","是否隐藏","父节点","排序","文件名称"})
for i, menu := range infoList {
axis := fmt.Sprintf("A%d",i+2)
excel.SetSheetRow("Sheet1",axis,&[]interface{}{
menu.ID,
menu.Name,
menu.Path,
menu.Hidden,
menu.ParentId,
menu.Sort,
menu.Component,
})
}
excel.SaveAs(filePath)
return nil
}
func ParseExcel2InfoList() ([]model.SysBaseMenu, error) {
skipHeader := true
fixedHeader := []string{"ID","路由Name","路由Path","是否隐藏","父节点","排序","文件名称"}
file, err := excelize.OpenFile(global.GVA_CONFIG.Excel.Dir+"ExcelImport.xlsx")
if err != nil {
return nil, err
}
menus := make([]model.SysBaseMenu, 0)
rows, err := file.Rows("Sheet1")
if err != nil {
return nil, err
}
for rows.Next() {
row, err := rows.Columns()
if err != nil {
return nil, err
}
if skipHeader {
if compareStrSlice(row, fixedHeader) {
skipHeader = false
continue
} else {
return nil, errors.New("Excel格式错误")
}
}
if len(row) != len(fixedHeader) {
continue
}
id, _ := strconv.Atoi(row[0])
hidden, _ := strconv.ParseBool(row[3])
sort, _ := strconv.Atoi(row[5])
menu := model.SysBaseMenu{
GVA_MODEL: global.GVA_MODEL{
ID: uint(id),
},
Name: row[1],
Path: row[2],
Hidden: hidden,
ParentId: row[4],
Sort: sort,
Component: row[6],
}
menus = append(menus, menu)
}
return menus, nil
}
func compareStrSlice(a, b []string) bool {
if len(a) != len(b) {
return false
}
if (b == nil) != (a == nil) {
return false
}
for key, value := range a {
if value != b[key] {
return false
}
}
return true
}
+2 -2
View File
@@ -42,10 +42,10 @@ func DeleteFile(file model.ExaFileUploadAndDownload) (err error) {
var fileFromDb model.ExaFileUploadAndDownload
err, fileFromDb = FindFile(file.ID)
oss := upload.NewOss()
if err = oss.DeleteFile(fileFromDb.Key); err != nil{
if err = oss.DeleteFile(fileFromDb.Key); err != nil {
return errors.New("文件删除失败")
}
err = global.GVA_DB.Where("id = ?", file.ID).Unscoped().Delete(file).Error
err = global.GVA_DB.Where("id = ?", file.ID).Unscoped().Delete(&file).Error
return err
}
+6 -3
View File
@@ -51,7 +51,12 @@ func MergeFileMd5(md5 string, fileName string) (err error) {
rd, err := ioutil.ReadDir(dir)
_ = os.MkdirAll(finishDir, os.ModePerm)
//创建目标文件
fd, _ := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
fd, err := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
return
}
//关闭文件
defer fd.Close()
//将切片文件按照顺序写入
for k := range rd {
content, _ := ioutil.ReadFile(dir + "/" + fileName + strconv.Itoa(k+1))
@@ -60,8 +65,6 @@ func MergeFileMd5(md5 string, fileName string) (err error) {
_ = os.Remove(finishDir + fileName)
}
}
//关闭文件
defer fd.Close()
if err != nil {
return err
+1 -1
View File
@@ -49,7 +49,7 @@ func GetRedisJWT(userName string) (err error, redisJWT string) {
func SetRedisJWT(jwt string, userName string) (err error) {
// 此处过期时间等于jwt过期时间
timer := 60 * 60 * 24 * 7 * time.Second
timer := time.Duration(global.GVA_CONFIG.JWT.ExpiresTime) * time.Second
err = global.GVA_REDIS.Set(userName, jwt, timer).Err()
return err
}
+1 -1
View File
@@ -28,7 +28,7 @@ func CreateApi(api model.SysApi) (err error) {
//@return: err error
func DeleteApi(api model.SysApi) (err error) {
err = global.GVA_DB.Delete(api).Error
err = global.GVA_DB.Delete(&api).Error
ClearCasbin(1, api.Path, api.Method)
return err
}
+140 -55
View File
@@ -7,12 +7,18 @@ import (
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gin-vue-admin/utils"
"gorm.io/gorm"
"io/ioutil"
"os"
"path/filepath"
"strings"
"text/template"
"gorm.io/gorm"
)
const (
autoPath = "autoCode/"
basePath = "resource/template"
)
type tplData struct {
@@ -22,6 +28,71 @@ type tplData struct {
autoMoveFilePath string
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: PreviewTemp
//@description: 预览创建代码
//@param: model.AutoCodeStruct
//@return: map[string]string, error
func PreviewTemp(autoCode model.AutoCodeStruct) (map[string]string, error) {
dataList, _, needMkdir, err := getNeedList(&autoCode)
if err != nil {
return nil, err
}
// 写入文件前,先创建文件夹
if err = utils.CreateDir(needMkdir...); err != nil {
return nil, err
}
// 创建map
ret := make(map[string]string)
// 生成map
for _, value := range dataList {
ext := ""
if ext = filepath.Ext(value.autoCodePath); ext == ".txt" {
continue
}
f, err := os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_WRONLY, 0755)
if err != nil {
return nil, err
}
if err = value.template.Execute(f, autoCode); err != nil {
return nil, err
}
_ = f.Close()
f, err = os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_RDONLY, 0755)
if err != nil {
return nil, err
}
builder := strings.Builder{}
builder.WriteString("```")
if ext != "" && strings.Contains(ext, ".") {
builder.WriteString(strings.Replace(ext, ".", "", -1))
}
builder.WriteString("\n\n")
data, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
builder.Write(data)
builder.WriteString("\n\n```")
pathArr := strings.Split(value.autoCodePath, string(os.PathSeparator))
ret[pathArr[1]+"-"+pathArr[3]] = builder.String()
_ = f.Close()
}
defer func() { // 移除中间文件
if err := os.RemoveAll(autoPath); err != nil {
return
}
}()
return ret, nil
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateTemp
//@description: 创建代码
@@ -29,52 +100,10 @@ type tplData struct {
//@return: error
func CreateTemp(autoCode model.AutoCodeStruct) (err error) {
basePath := "resource/template"
// 获取 basePath 文件夹下所有tpl文件
tplFileList, err := GetAllTplFile(basePath, nil)
dataList, fileList, needMkdir, err := getNeedList(&autoCode)
if err != nil {
return err
}
dataList := make([]tplData, 0, len(tplFileList))
fileList := make([]string, 0, len(tplFileList))
needMkdir := make([]string, 0, len(tplFileList)) // 当文件夹下存在多个tpl文件时,改为map更合理
// 根据文件路径生成 tplData 结构体,待填充数据
for _, value := range tplFileList {
dataList = append(dataList, tplData{locationPath: value})
}
// 生成 *Template, 填充 template 字段
for index, value := range dataList {
dataList[index].template, err = template.ParseFiles(value.locationPath)
if err != nil {
return err
}
}
// 生成文件路径,填充 autoCodePath 字段,readme.txt.tpl不符合规则,需要特殊处理
// resource/template/web/api.js.tpl -> autoCode/web/autoCode.PackageName/api/autoCode.PackageName.js
// resource/template/readme.txt.tpl -> autoCode/readme.txt
autoPath := "autoCode/"
for index, value := range dataList {
trimBase := strings.TrimPrefix(value.locationPath, basePath+"/")
if trimBase == "readme.txt.tpl" {
dataList[index].autoCodePath = autoPath + "readme.txt"
continue
}
if lastSeparator := strings.LastIndex(trimBase, "/"); lastSeparator != -1 {
origFileName := strings.TrimSuffix(trimBase[lastSeparator+1:], ".tpl")
firstDot := strings.Index(origFileName, ".")
if firstDot != -1 {
dataList[index].autoCodePath = autoPath + trimBase[:lastSeparator] + "/" + autoCode.PackageName + "/" +
origFileName[:firstDot] + "/" + autoCode.PackageName + origFileName[firstDot:]
}
}
if lastSeparator := strings.LastIndex(dataList[index].autoCodePath, "/"); lastSeparator != -1 {
needMkdir = append(needMkdir, dataList[index].autoCodePath[:lastSeparator])
}
}
// 写入文件前,先创建文件夹
if err = utils.CreateDir(needMkdir...); err != nil {
return err
@@ -82,7 +111,6 @@ func CreateTemp(autoCode model.AutoCodeStruct) (err error) {
// 生成文件
for _, value := range dataList {
fileList = append(fileList, value.autoCodePath)
f, err := os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_WRONLY, 0755)
if err != nil {
return err
@@ -186,24 +214,31 @@ func GetColumn(tableName string, dbName string) (err error, Columns []request.Co
func addAutoMoveFile(data *tplData) {
dir := filepath.Base(filepath.Dir(data.autoCodePath))
base := filepath.Base(data.autoCodePath)
if strings.Contains(data.autoCodePath, "server") {
if strings.Contains(data.autoCodePath, "router") {
fileSlice := strings.Split(data.autoCodePath, string(os.PathSeparator))
n := len(fileSlice)
if n <= 2 {
return
}
if strings.Contains(fileSlice[1], "server") {
if strings.Contains(fileSlice[n-2], "router") {
data.autoMoveFilePath = filepath.Join(dir, base)
} else if strings.Contains(data.autoCodePath, "api") {
} else if strings.Contains(fileSlice[n-2], "api") {
data.autoMoveFilePath = filepath.Join(dir, "v1", base)
} else if strings.Contains(data.autoCodePath, "service") {
} else if strings.Contains(fileSlice[n-2], "service") {
data.autoMoveFilePath = filepath.Join(dir, base)
} else if strings.Contains(data.autoCodePath, "model") {
} else if strings.Contains(fileSlice[n-2], "model") {
data.autoMoveFilePath = filepath.Join(dir, base)
} else if strings.Contains(data.autoCodePath, "request") {
} else if strings.Contains(fileSlice[n-2], "request") {
data.autoMoveFilePath = filepath.Join("model", dir, base)
}
} else if strings.Contains(data.autoCodePath, "web") {
if strings.Contains(data.autoCodePath, "js") {
} else if strings.Contains(fileSlice[1], "web") {
if strings.Contains(fileSlice[n-1], "js") {
data.autoMoveFilePath = filepath.Join("../", "web", "src", dir, base)
} else if strings.Contains(data.autoCodePath, "form") {
} else if strings.Contains(fileSlice[n-2], "workflowForm") {
data.autoMoveFilePath = filepath.Join("../", "web", "src", "view", filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), strings.TrimSuffix(base, filepath.Ext(base))+"WorkflowForm.vue")
} else if strings.Contains(fileSlice[n-2], "form") {
data.autoMoveFilePath = filepath.Join("../", "web", "src", "view", filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), strings.TrimSuffix(base, filepath.Ext(base))+"Form.vue")
} else if strings.Contains(data.autoCodePath, "table") {
} else if strings.Contains(fileSlice[n-2], "table") {
data.autoMoveFilePath = filepath.Join("../", "web", "src", "view", filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), base)
}
}
@@ -268,3 +303,53 @@ func AutoCreateApi(a *model.AutoCodeStruct) (err error) {
})
return err
}
func getNeedList(autoCode *model.AutoCodeStruct) (dataList []tplData, fileList []string, needMkdir []string, err error) {
// 获取 basePath 文件夹下所有tpl文件
tplFileList, err := GetAllTplFile(basePath, nil)
if err != nil {
return nil, nil, nil, err
}
dataList = make([]tplData, 0, len(tplFileList))
fileList = make([]string, 0, len(tplFileList))
needMkdir = make([]string, 0, len(tplFileList)) // 当文件夹下存在多个tpl文件时,改为map更合理
// 根据文件路径生成 tplData 结构体,待填充数据
for _, value := range tplFileList {
dataList = append(dataList, tplData{locationPath: value})
}
// 生成 *Template, 填充 template 字段
for index, value := range dataList {
dataList[index].template, err = template.ParseFiles(value.locationPath)
if err != nil {
return nil, nil, nil, err
}
}
// 生成文件路径,填充 autoCodePath 字段,readme.txt.tpl不符合规则,需要特殊处理
// resource/template/web/api.js.tpl -> autoCode/web/autoCode.PackageName/api/autoCode.PackageName.js
// resource/template/readme.txt.tpl -> autoCode/readme.txt
autoPath := "autoCode/"
for index, value := range dataList {
trimBase := strings.TrimPrefix(value.locationPath, basePath+"/")
if trimBase == "readme.txt.tpl" {
dataList[index].autoCodePath = autoPath + "readme.txt"
continue
}
if lastSeparator := strings.LastIndex(trimBase, "/"); lastSeparator != -1 {
origFileName := strings.TrimSuffix(trimBase[lastSeparator+1:], ".tpl")
firstDot := strings.Index(origFileName, ".")
if firstDot != -1 {
dataList[index].autoCodePath = filepath.Join(autoPath, trimBase[:lastSeparator], autoCode.PackageName,
origFileName[:firstDot], autoCode.PackageName+origFileName[firstDot:])
}
}
if lastSeparator := strings.LastIndex(dataList[index].autoCodePath, string(os.PathSeparator)); lastSeparator != -1 {
needMkdir = append(needMkdir, dataList[index].autoCodePath[:lastSeparator])
}
}
for _, value := range dataList {
fileList = append(fileList, value.autoCodePath)
}
return dataList, fileList, needMkdir, err
}
+1 -1
View File
@@ -29,7 +29,7 @@ func CreateSysDictionary(sysDictionary model.SysDictionary) (err error) {
//@return: err error
func DeleteSysDictionary(sysDictionary model.SysDictionary) (err error) {
err = global.GVA_DB.Delete(sysDictionary).Delete(&sysDictionary.SysDictionaryDetails).Error
err = global.GVA_DB.Delete(&sysDictionary).Delete(&sysDictionary.SysDictionaryDetails).Error
return err
}
+1 -1
View File
@@ -24,7 +24,7 @@ func CreateSysDictionaryDetail(sysDictionaryDetail model.SysDictionaryDetail) (e
//@return: err error
func DeleteSysDictionaryDetail(sysDictionaryDetail model.SysDictionaryDetail) (err error) {
err = global.GVA_DB.Delete(sysDictionaryDetail).Error
err = global.GVA_DB.Delete(&sysDictionaryDetail).Error
return err
}
+156
View File
@@ -0,0 +1,156 @@
package service
import (
"database/sql"
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gin-vue-admin/source"
"github.com/spf13/viper"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: writeConfig
//@description: 回写配置
//@param:
//@return: error
func writeConfig(viper *viper.Viper, conf map[string]interface{}) error {
for k, v := range conf {
viper.Set(k, v)
}
return viper.WriteConfig()
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: createTable
//@description: 创建数据库(mysql)
//@param: dsn string, driver string, createSql
//@return: error
func createTable(dsn string, driver string, createSql string) error {
db, err := sql.Open(driver, dsn)
if err != nil {
return err
}
defer db.Close()
if err = db.Ping(); err != nil {
return err
}
_, err = db.Exec(createSql)
return err
}
func initDB(InitDBFunctions ...model.InitDBFunc) (err error) {
for _, v := range InitDBFunctions {
err = v.Init()
if err != nil {
return err
}
}
return nil
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: InitDB
//@description: 创建数据库并初始化
//@param: authorityId string
//@return: err error, treeMap map[string][]model.SysMenu
func InitDB(conf request.InitDB) error {
if conf.Host == "" {
conf.Host = "127.0.0.1"
}
if conf.Port == "" {
conf.Port = "3306"
}
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/", conf.UserName, conf.Password, conf.Host, conf.Port)
fmt.Println(dsn)
createSql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;", conf.DBName)
if err := createTable(dsn, "mysql", createSql); err != nil {
return err
}
setting := map[string]interface{}{
"mysql.path": fmt.Sprintf("%s:%s", conf.Host, conf.Port),
"mysql.db-name": conf.DBName,
"mysql.username": conf.UserName,
"mysql.password": conf.Password,
"mysql.config": "charset=utf8mb4&parseTime=True&loc=Local",
}
if err := writeConfig(global.GVA_VP, setting); err != nil {
return err
}
m := global.GVA_CONFIG.Mysql
if m.Dbname == "" {
return nil
}
linkDns := m.Username + ":" + m.Password + "@tcp(" + m.Path + ")/" + m.Dbname + "?" + m.Config
mysqlConfig := mysql.Config{
DSN: linkDns, // DSN data source name
DefaultStringSize: 191, // string 类型字段的默认长度
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
SkipInitializeWithVersion: false, // 根据版本自动配置
}
if db, err := gorm.Open(mysql.New(mysqlConfig), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}); err != nil {
//global.GVA_LOG.Error("MySQL启动异常", zap.Any("err", err))
//os.Exit(0)
//return nil
return nil
} else {
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(m.MaxIdleConns)
sqlDB.SetMaxOpenConns(m.MaxOpenConns)
global.GVA_DB = db
}
err := global.GVA_DB.AutoMigrate(
model.SysUser{},
model.SysAuthority{},
model.SysApi{},
model.SysBaseMenu{},
model.SysBaseMenuParameter{},
model.JwtBlacklist{},
model.SysDictionary{},
model.SysDictionaryDetail{},
model.ExaFileUploadAndDownload{},
model.ExaFile{},
model.ExaFileChunk{},
model.ExaSimpleUploader{},
model.ExaCustomer{},
model.SysOperationRecord{},
model.WorkflowProcess{},
model.WorkflowNode{},
model.WorkflowEdge{},
model.WorkflowStartPoint{},
model.WorkflowEndPoint{},
model.WorkflowMove{},
model.ExaWfLeave{},
)
if err != nil {
return err
}
err = initDB(
source.Admin,
source.Api,
source.AuthorityMenu,
source.Authority,
source.AuthoritiesMenus,
source.Casbin,
source.DataAuthorities,
source.Dictionary,
source.DictionaryDetail,
source.File,
source.BaseMenu,
source.Workflow)
if err != nil {
return err
}
return nil
}
+3 -4
View File
@@ -89,12 +89,11 @@ func getBaseChildrenList(menu *model.SysBaseMenu, treeMap map[string][]model.Sys
//@param: menu model.SysBaseMenu
//@return: err error
func AddBaseMenu(menu model.SysBaseMenu) (err error) {
func AddBaseMenu(menu model.SysBaseMenu) error {
if !errors.Is(global.GVA_DB.Where("name = ?", menu.Name).First(&model.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) {
err = errors.New("存在重复name,请修改name")
return errors.New("存在重复name,请修改name")
}
err = global.GVA_DB.Create(&menu).Error
return err
return global.GVA_DB.Create(&menu).Error
}
//@author: [piexlmax](https://github.com/piexlmax)
+1 -1
View File
@@ -36,7 +36,7 @@ func DeleteSysOperationRecordByIds(ids request.IdsReq) (err error) {
//@return: err error
func DeleteSysOperationRecord(sysOperationRecord model.SysOperationRecord) (err error) {
err = global.GVA_DB.Delete(sysOperationRecord).Error
err = global.GVA_DB.Delete(&sysOperationRecord).Error
return err
}
+435 -7
View File
@@ -1,17 +1,445 @@
package service
import (
"errors"
"fmt"
"gin-vue-admin/constant"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gorm.io/gorm"
"gorm.io/gorm/schema"
"strconv"
)
//@author: [piexlmax](https://github.com/piexlmax)
//@function: Create
//@description: 创建工作流
//@param: wk model.SysWorkflow
//@return: error
func getTable(businessType string) interface{} {
return model.WorkflowBusinessTable[businessType]()
}
func Create(wk model.SysWorkflow) error {
err := global.GVA_DB.Create(&wk).Error
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateWorkflowProcess
//@description: 创建工作流相关信息
//@param: workflowProcess model.WorkflowProcess
//@return: err error
func CreateWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
err = global.GVA_DB.Create(&workflowProcess).Error
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: DeleteWorkflowProcess
//@description: 删除工作流相关信息
//@param: workflowProcess model.WorkflowProcess
//@return: err error
func DeleteWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
txErr = tx.Delete(&workflowProcess).Error
if txErr != nil {
return txErr
}
var edges []model.WorkflowEdge
txErr = tx.Delete(&model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
if txErr != nil {
return txErr
}
txErr = tx.Find(&edges, "workflow_process_id = ?", workflowProcess.ID).Error
if txErr != nil {
return txErr
}
if len(edges) > 0 {
txErr = tx.Select("StartPoint", "EndPoint").Delete(&edges).Error
}
if txErr != nil {
return txErr
}
return nil
})
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateWorkflowProcess
//@description: 批量删除工作流信息(暂未启用)
//@param: ids request.IdsReq
//@return: err error
func DeleteWorkflowProcessByIds(ids request.IdsReq) (err error) {
err = global.GVA_DB.Delete(&[]model.WorkflowProcess{}, "id in ?", ids.Ids).Error
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: UpdateWorkflowProcess
//@description: 更新工作流相关信息
//@param: workflowProcess *model.WorkflowProcess
//@return: err error
func UpdateWorkflowProcess(workflowProcess *model.WorkflowProcess) (err error) {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
var edges []model.WorkflowEdge
var edgesIds []string
txErr = tx.Unscoped().Delete(workflowProcess).Error
if txErr != nil {
return txErr
}
txErr = tx.Unscoped().Delete(&model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
if txErr != nil {
return txErr
}
txErr = tx.Unscoped().Find(&edges, "workflow_process_id = ?", workflowProcess.ID).Error
if txErr != nil {
return txErr
}
txErr = tx.Unscoped().Delete(&edges).Error
if txErr != nil {
return txErr
}
for _, v := range edges {
edgesIds = append(edgesIds, v.ID)
}
txErr = tx.Unscoped().Delete(&model.WorkflowStartPoint{}, "workflow_edge_id in ?", edgesIds).Error
if txErr != nil {
return txErr
}
txErr = tx.Unscoped().Delete(&model.WorkflowEndPoint{}, "workflow_edge_id in ?", edgesIds).Error
if txErr != nil {
return txErr
}
txErr = tx.Create(&workflowProcess).Error
if txErr != nil {
return txErr
}
return nil
})
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetWorkflowProcess
//@description: 获取工作流相关信息
//@param: id string
//@return: err error,workflowProcess model.WorkflowProcess
func GetWorkflowProcess(id string) (err error, workflowProcess model.WorkflowProcess) {
err = global.GVA_DB.Preload("Nodes").Preload("Edges").Where("id = ?", id).First(&workflowProcess).Error
return
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetWorkflowCreateStep
//@description: 获取工作流步骤信息
//@param: id string
//@return: err error, workflowNodes []model.WorkflowNode
func FindWorkflowStep(id string) (err error, workflowNode model.WorkflowProcess) {
err = global.GVA_DB.Preload("Nodes", "clazz = ?", constant.START).Where("id = ?", id).First(&workflowNode).Error
return
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetWorkflowProcessInfoList
//@description: 获取工作流列表
//@param: info request.WorkflowProcessSearch
//@return: err error, list interface{}, total int64
func GetWorkflowProcessInfoList(info request.WorkflowProcessSearch) (err error, list interface{}, total int64) {
limit := info.PageSize
offset := info.PageSize * (info.Page - 1)
// 创建db
db := global.GVA_DB.Model(&model.WorkflowProcess{})
var workflowProcesss []model.WorkflowProcess
// 如果有条件搜索 下方会自动创建搜索语句
if info.Name != "" {
db = db.Where("`name` LIKE ?", "%"+info.Name+"%")
}
if info.Label != "" {
db = db.Where("`label` LIKE ?", "%"+info.Label+"%")
}
err = db.Count(&total).Error
err = db.Limit(limit).Offset(offset).Find(&workflowProcesss).Error
return err, workflowProcesss, total
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: StartWorkflow
//@description: 开启一个工作流
//@param: wfInterface model.GVA_Workflow
//@return: err error
func StartWorkflow(wfInterface model.GVA_Workflow) (err error) {
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
tableName := getTable(wfInterface.GetBusinessType()).(schema.Tabler).TableName()
txErr = tx.Table(tableName).Create(wfInterface).Error
if txErr != nil {
return txErr
}
wfm := wfInterface.CreateWorkflowMove()
txErr = tx.Create(wfm).Error
if txErr != nil {
return txErr
}
txErr = complete(tx, wfm)
if txErr != nil {
return txErr
}
return nil
})
return err
}
func CompleteWorkflowMove(wfInterface model.GVA_Workflow) (err error) {
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
tableName := getTable(wfInterface.GetBusinessType()).(schema.Tabler).TableName()
txErr = tx.Table(tableName).Where("id = ?", wfInterface.GetBusinessID()).Updates(wfInterface).Error
if txErr != nil {
return txErr
}
nowWorkflowMove := wfInterface.CreateWorkflowMove()
txErr = complete(tx, nowWorkflowMove)
if txErr != nil {
return txErr
}
return nil
})
return err
}
func complete(tx *gorm.DB, wfm *model.WorkflowMove) (err error) {
var returnWfm model.WorkflowMove
var nodeInfo model.WorkflowNode
var Edges []model.WorkflowEdge
txErr := tx.First(&returnWfm, "id = ? AND is_active = ?", wfm.ID, true).Error
if txErr != nil {
return txErr
}
txErr = tx.First(&nodeInfo, "id = ?", wfm.WorkflowNodeID).Error
if txErr != nil {
return txErr
}
if nodeInfo.Clazz == constant.START || nodeInfo.Clazz == constant.USER_TASK {
txErr = tx.Find(&Edges, "workflow_process_id = ? and source = ?", wfm.WorkflowProcessID, wfm.WorkflowNodeID).Error
if txErr != nil {
return txErr
}
if len(Edges) == 0 {
return errors.New("不存在当前节点为起点的后续流程")
}
if len(Edges) == 1 {
txErr = tx.Model(&returnWfm).Update("param", wfm.Param).Update("is_active", false).Update("action", wfm.Action).Update("operator_id", wfm.OperatorID).Error
if txErr != nil {
return txErr
}
txErr, newWfm := createNewWorkflowMove(tx, &returnWfm, Edges[0].Target)
if txErr != nil {
return txErr
}
if len(newWfm) > 0 {
txErr = tx.Create(&newWfm).Error
if txErr != nil {
return txErr
}
}
// 当target为自动节点时候 需要做一些事情 这里暂时先不处理 后续慢慢完善
}
if len(Edges) > 1 {
var needUseTargetNodeID string
txErr = tx.Model(&returnWfm).Update("param", wfm.Param).Update("is_active", false).Update("action", wfm.Action).Update("operator_id", wfm.OperatorID).Error
if txErr != nil {
return txErr
}
for _, v := range Edges {
if v.ConditionExpression == wfm.Param {
needUseTargetNodeID = v.Target
break
}
}
if needUseTargetNodeID == "" {
return errors.New("未发现流转参数,流转失败")
}
txErr, newWfm := createNewWorkflowMove(tx, &returnWfm, needUseTargetNodeID)
if txErr != nil {
return txErr
}
if len(newWfm) > 0 {
txErr = tx.Create(&newWfm).Error
if txErr != nil {
return txErr
}
}
}
} else if nodeInfo.Clazz == constant.EXCLUSIVE_GATEWAY {
return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
} else if nodeInfo.Clazz == constant.INCLUSIVE_GATEWAY {
return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
} else if nodeInfo.Clazz == constant.PARELLEL_GATEWAY {
return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
} else {
return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
}
return nil
}
func createNewWorkflowMove(tx *gorm.DB, oldWfm *model.WorkflowMove, targetNodeID string) (err error, newWfm []model.WorkflowMove) {
// 以下所有非 default的节点的下一步流转均应该处理为递归形式
var nodeInfo model.WorkflowNode
var edge model.WorkflowEdge
var edges []model.WorkflowEdge
var wfms []model.WorkflowMove
txErr := tx.First(&nodeInfo, "id = ?", targetNodeID).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
switch nodeInfo.Clazz {
case constant.EXCLUSIVE_GATEWAY:
// 当为排他网关时候 选择一个参数进行排他线路选择
txErr := tx.First(&edge, "workflow_process_id = ? and source = ? and condition_expression = ?", oldWfm.WorkflowProcessID, nodeInfo.ID, oldWfm.Param).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
newWfm = append(newWfm, model.WorkflowMove{
BusinessID: oldWfm.BusinessID,
BusinessType: oldWfm.BusinessType,
PromoterID: oldWfm.PromoterID,
OperatorID: 0,
WorkflowNodeID: edge.Target,
WorkflowProcessID: oldWfm.WorkflowProcessID,
Param: "",
Action: "",
IsActive: true})
return nil, newWfm
case constant.INCLUSIVE_GATEWAY:
// 当为包容网关时,需要等待其他网关执行结束才进行创建
txErr := tx.Find(&edges, "workflow_process_id = ? and target = ?", oldWfm.WorkflowProcessID, nodeInfo.ID).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
var sourceIds []string
for _, v := range edges {
sourceIds = append(sourceIds, v.Source)
}
txErr = tx.Find(&wfms, "workflow_process_id = ? and business_id = ? and workflow_node_id in (?) and is_active = ?", oldWfm.WorkflowProcessID, oldWfm.BusinessID, sourceIds, false).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
if len(wfms) != len(edges) {
return nil, []model.WorkflowMove{}
}
if len(wfms) == len(edges) {
params := make(map[string]int)
var param string
var temp int
for _, v := range wfms {
params[v.Param]++
}
for k, v := range params {
if temp < v {
temp = v
param = k
}
}
//参数携带模式暂时未定 暂时为少数服从多数原则 后续会增加原则配置 (少数服从多数,仅一关键字即为关键字,所有关键字才为关键字 三种方案)
txErr := tx.First(&edge, "workflow_process_id = ? and source = ? and condition_expression = ?", oldWfm.WorkflowProcessID, nodeInfo.ID, param).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
newWfm = append(newWfm, model.WorkflowMove{
BusinessID: oldWfm.BusinessID,
BusinessType: oldWfm.BusinessType,
PromoterID: oldWfm.PromoterID,
OperatorID: 0,
WorkflowNodeID: edge.Target,
WorkflowProcessID: oldWfm.WorkflowProcessID,
Param: "",
Action: "",
IsActive: true})
}
return nil, newWfm
case constant.PARELLEL_GATEWAY:
// 当为并行网关时候 找出所有线路创建并行节点
txErr := tx.Find(&edges, "workflow_process_id = ? and source = ?", oldWfm.WorkflowProcessID, nodeInfo.ID).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
for _, v := range edges {
newWfm = append(newWfm, model.WorkflowMove{
BusinessID: oldWfm.BusinessID,
BusinessType: oldWfm.BusinessType,
PromoterID: oldWfm.PromoterID,
OperatorID: 0,
WorkflowNodeID: v.Target,
WorkflowProcessID: oldWfm.WorkflowProcessID,
Param: "",
Action: "",
IsActive: true})
}
return nil, newWfm
case constant.END:
newWfm = append(newWfm, model.WorkflowMove{
BusinessID: oldWfm.BusinessID,
BusinessType: oldWfm.BusinessType,
PromoterID: oldWfm.PromoterID,
OperatorID: oldWfm.OperatorID,
WorkflowNodeID: targetNodeID,
WorkflowProcessID: oldWfm.WorkflowProcessID,
Param: "",
Action: "",
IsActive: false})
return nil, newWfm
default:
newWfm = append(newWfm, model.WorkflowMove{
BusinessID: oldWfm.BusinessID,
BusinessType: oldWfm.BusinessType,
PromoterID: oldWfm.PromoterID,
OperatorID: 0,
WorkflowNodeID: targetNodeID,
WorkflowProcessID: oldWfm.WorkflowProcessID,
Param: "",
Action: "",
IsActive: true})
return nil, newWfm
}
}
func GetMyStated(userID uint) (err error, wfms []model.WorkflowMove) {
err = global.GVA_DB.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Joins("INNER JOIN workflow_nodes as node ON workflow_moves.workflow_node_id = node.id").Find(&wfms, "promoter_id = ? and ( is_active = ? OR node.clazz = ?)", userID, true, "end").Error
return err, wfms
}
func GetMyNeed(userID uint, AuthorityID string) (err error, wfms []model.WorkflowMove) {
user := "%," + strconv.Itoa(int(userID)) + ",%"
auth := "%," + AuthorityID + ",%"
err = global.GVA_DB.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Joins("INNER JOIN workflow_nodes as node ON workflow_moves.workflow_node_id = node.id").Where("is_active = ? AND ((node.assign_type = ? AND node.assign_value LIKE ? ) OR (node.assign_type = ? AND node.assign_value LIKE ? ) OR (node.assign_type = ? AND promoter_id = ? ))", true, "user", user, "authority", auth, "self", userID).Find(&wfms).Error
return err, wfms
}
func GetWorkflowMoveByID(id float64) (err error, move model.WorkflowMove, moves []model.WorkflowMove, business interface{}) {
var result interface{}
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
txErr = tx.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").First(&move, "id = ?", id).Error
if txErr != nil {
return txErr
}
txErr = tx.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Find(&moves, "business_id = ? AND business_type = ?", move.BusinessID, move.BusinessType).Error
if txErr != nil {
return txErr
}
result = getTable(move.BusinessType)
fmt.Println(result)
txErr = tx.First(result, "id = ?", move.BusinessID).Error
if txErr != nil {
return txErr
}
return nil
})
return err, move, moves, result
}
@@ -1,33 +1,36 @@
package datas
package source
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"github.com/gookit/color"
"os"
"time"
"gin-vue-admin/model"
uuid "github.com/satori/go.uuid"
"gorm.io/gorm"
)
var Users = []model.SysUser{
var Admin = new(admin)
type admin struct{}
var admins = []model.SysUser{
{GVA_MODEL: global.GVA_MODEL{ID: 1, CreatedAt: time.Now(), UpdatedAt: time.Now()}, UUID: uuid.NewV4(), Username: "admin", Password: "e10adc3949ba59abbe56e057f20f883e", NickName: "超级管理员", HeaderImg: "http://qmplusimg.henrongyi.top/gva_header.jpg", AuthorityId: "888"},
{GVA_MODEL: global.GVA_MODEL{ID: 2, CreatedAt: time.Now(), UpdatedAt: time.Now()}, UUID: uuid.NewV4(), Username: "a303176530", Password: "3ec063004a6f31642261936a379fde3d", NickName: "QMPlusUser", HeaderImg: "http://qmplusimg.henrongyi.top/1572075907logo.png", AuthorityId: "9528"},
}
func InitSysUser(db *gorm.DB) {
if err := db.Transaction(func(tx *gorm.DB) error {
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: sys_users 表数据初始化
func (a *admin) Init() error {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if tx.Where("id IN ?", []int{1, 2}).Find(&[]model.SysUser{}).RowsAffected == 2 {
color.Danger.Println("sys_users表的初始数据已存在!")
color.Danger.Println("\n[Mysql] --> sys_users 表的初始数据已存在!")
return nil
}
if err := tx.Create(&Users).Error; err != nil { // 遇到错误时回滚事务
if err := tx.Create(&admins).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> sys_users 表初始数据成功!")
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> sys_users 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
})
}
@@ -1,16 +1,19 @@
package datas
package source
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"github.com/gookit/color"
"os"
"time"
"gorm.io/gorm"
)
var Apis = []model.SysApi{
var Api = new(api)
type api struct{}
var apis = []model.SysApi{
{global.GVA_MODEL{ID: 1, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/base/login", "用户登录", "base", "POST"},
{global.GVA_MODEL{ID: 2, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/register", "用户注册", "user", "POST"},
{global.GVA_MODEL{ID: 3, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/api/createApi", "创建api", "api", "POST"},
@@ -39,7 +42,7 @@ var Apis = []model.SysApi{
{global.GVA_MODEL{ID: 27, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/casbin/updateCasbin", "更改角色api权限", "casbin", "POST"},
{global.GVA_MODEL{ID: 28, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/casbin/getPolicyPathByAuthorityId", "获取权限列表", "casbin", "POST"},
{global.GVA_MODEL{ID: 29, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/fileUploadAndDownload/deleteFile", "删除文件", "fileUploadAndDownload", "POST"},
{global.GVA_MODEL{ID: 30, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/jwt/jsonInBlacklist", "jwt加入黑名单", "jwt", "POST"},
{global.GVA_MODEL{ID: 30, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/jwt/jsonInBlacklist", "jwt加入黑名单(退出)", "jwt", "POST"},
{global.GVA_MODEL{ID: 31, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/authority/setDataAuthority", "设置角色资源权限", "authority", "POST"},
{global.GVA_MODEL{ID: 32, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/system/getSystemConfig", "获取配置文件内容", "system", "POST"},
{global.GVA_MODEL{ID: 33, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/system/setSystemConfig", "设置配置文件内容", "system", "POST"},
@@ -77,20 +80,37 @@ var Apis = []model.SysApi{
{global.GVA_MODEL{ID: 65, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/setUserInfo", "设置用户信息", "user", "PUT"},
{global.GVA_MODEL{ID: 66, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/system/getServerInfo", "获取服务器信息", "system", "POST"},
{global.GVA_MODEL{ID: 67, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/email/emailTest", "发送测试邮件", "email", "POST"},
{global.GVA_MODEL{ID: 68, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/createWorkflowProcess", "新建工作流", "workflowProcess", "POST"},
{global.GVA_MODEL{ID: 69, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/deleteWorkflowProcess", "删除工作流", "workflowProcess", "DELETE"},
{global.GVA_MODEL{ID: 70, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/deleteWorkflowProcessByIds", "批量删除工作流", "workflowProcess", "DELETE"},
{global.GVA_MODEL{ID: 71, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/updateWorkflowProcess", "更新工作流", "workflowProcess", "PUT"},
{global.GVA_MODEL{ID: 72, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/findWorkflowProcess", "根据ID获取工作流", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 73, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getWorkflowProcessList", "获取工作流", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 74, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/findWorkflowStep", "获取工作流步骤", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 75, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/startWorkflow", "启动工作流", "workflowProcess", "POST"},
{global.GVA_MODEL{ID: 76, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getMyStated", "获取我发起的工作流", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 77, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getMyNeed", "获取我的待办", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 78, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getWorkflowMoveByID", "根据id获取当前节点详情和历史", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 79, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/completeWorkflowMove", "提交工作流", "workflowProcess", "POST"},
{global.GVA_MODEL{ID: 80, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/autoCode/preview", "预览自动化代码", "autoCode", "POST"},
{global.GVA_MODEL{ID: 81, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/excel/importExcel", "导入excel", "excel", "POST"},
{global.GVA_MODEL{ID: 82, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/excel/loadExcel", "下载excel", "excel", "GET"},
{global.GVA_MODEL{ID: 83, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/excel/exportExcel", "导出excel", "excel", "POST"},
{global.GVA_MODEL{ID: 84, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/excel/downloadTemplate", "下载excel模板", "excel", "GET"},
}
func InitSysApi(db *gorm.DB) {
if err := db.Transaction(func(tx *gorm.DB) error {
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: sys_apis 表数据初始化
func (a *api) Init() error {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if tx.Where("id IN ?", []int{1, 67}).Find(&[]model.SysApi{}).RowsAffected == 2 {
color.Danger.Println("sys_apis表的初始数据已存在!")
color.Danger.Println("\n[Mysql] --> sys_apis 表的初始数据已存在!")
return nil
}
if err := tx.Create(&Apis).Error; err != nil { // 遇到错误时回滚事务
if err := tx.Create(&apis).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> sys_apis 表初始数据成功!")
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> sys_apis 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
})
}
+83
View File
@@ -0,0 +1,83 @@
package source
import (
"gin-vue-admin/global"
"github.com/gookit/color"
"gorm.io/gorm"
)
var AuthoritiesMenus = new(authoritiesMenus)
type authoritiesMenus struct{}
type AuthorityMenus struct {
AuthorityId string `gorm:"column:sys_authority_authority_id"`
BaseMenuId uint `gorm:"column:sys_base_menu_id"`
}
var authorityMenus = []AuthorityMenus{
{"888", 1},
{"888", 2},
{"888", 3},
{"888", 4},
{"888", 5},
{"888", 6},
{"888", 7},
{"888", 8},
{"888", 9},
{"888", 10},
{"888", 11},
{"888", 12},
{"888", 13},
{"888", 14},
{"888", 15},
{"888", 16},
{"888", 17},
{"888", 18},
{"888", 19},
{"888", 20},
{"888", 21},
{"888", 22},
{"888", 23},
{"888", 24},
{"888", 25},
{"888", 26},
{"888", 27},
{"888", 28},
{"888", 29},
{"8881", 1},
{"8881", 2},
{"8881", 8},
{"9528", 1},
{"9528", 2},
{"9528", 3},
{"9528", 4},
{"9528", 5},
{"9528", 6},
{"9528", 7},
{"9528", 8},
{"9528", 9},
{"9528", 10},
{"9528", 11},
{"9528", 12},
{"9528", 14},
{"9528", 15},
{"9528", 16},
{"9528", 17},
}
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: sys_authority_menus 表数据初始化
func (a *authoritiesMenus) Init() error {
return global.GVA_DB.Table("sys_authority_menus").Transaction(func(tx *gorm.DB) error {
if tx.Where("sys_authority_authority_id IN ('888', '8881', '9528')").Find(&[]AuthorityMenus{}).RowsAffected == 48 {
color.Danger.Println("\n[Mysql] --> sys_authority_menus 表的初始数据已存在!")
return nil
}
if err := tx.Create(&authorityMenus).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> sys_authority_menus 表初始数据成功!")
return nil
})
}
+36
View File
@@ -0,0 +1,36 @@
package source
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"github.com/gookit/color"
"time"
"gorm.io/gorm"
)
var Authority = new(authority)
type authority struct{}
var authorities = []model.SysAuthority{
{CreatedAt: time.Now(), UpdatedAt: time.Now(), AuthorityId: "888", AuthorityName: "普通用户", ParentId: "0", DefaultRouter: "dashboard"},
{CreatedAt: time.Now(), UpdatedAt: time.Now(), AuthorityId: "8881", AuthorityName: "普通用户子角色", ParentId: "888", DefaultRouter: "dashboard"},
{CreatedAt: time.Now(), UpdatedAt: time.Now(), AuthorityId: "9528", AuthorityName: "测试角色", ParentId: "0", DefaultRouter: "dashboard"},
}
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: sys_authorities 表数据初始化
func (a *authority) Init() error {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if tx.Where("authority_id IN ? ", []string{"888", "9528"}).Find(&[]model.SysAuthority{}).RowsAffected == 2 {
color.Danger.Println("\n[Mysql] --> sys_authorities 表的初始数据已存在!")
return nil
}
if err := tx.Create(&authorities).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> sys_authorities 表初始数据成功!")
return nil
})
}
+25
View File
@@ -0,0 +1,25 @@
package source
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"github.com/gookit/color"
)
var AuthorityMenu = new(authorityMenu)
type authorityMenu struct{}
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: authority_menu 视图数据初始化
func (a *authorityMenu) Init() error {
if global.GVA_DB.Find(&[]model.SysMenu{}).RowsAffected > 0 {
color.Danger.Println("\n[Mysql] --> authority_menu 视图已存在!")
return nil
}
if err := global.GVA_DB.Exec("CREATE ALGORITHM = UNDEFINED SQL SECURITY DEFINER VIEW `authority_menu` AS select `sys_base_menus`.`id` AS `id`,`sys_base_menus`.`created_at` AS `created_at`, `sys_base_menus`.`updated_at` AS `updated_at`, `sys_base_menus`.`deleted_at` AS `deleted_at`, `sys_base_menus`.`menu_level` AS `menu_level`,`sys_base_menus`.`parent_id` AS `parent_id`,`sys_base_menus`.`path` AS `path`,`sys_base_menus`.`name` AS `name`,`sys_base_menus`.`hidden` AS `hidden`,`sys_base_menus`.`component` AS `component`, `sys_base_menus`.`title` AS `title`,`sys_base_menus`.`icon` AS `icon`,`sys_base_menus`.`sort` AS `sort`,`sys_authority_menus`.`sys_authority_authority_id` AS `authority_id`,`sys_authority_menus`.`sys_base_menu_id` AS `menu_id`,`sys_base_menus`.`keep_alive` AS `keep_alive`,`sys_base_menus`.`default_menu` AS `default_menu` from (`sys_authority_menus` join `sys_base_menus` on ((`sys_authority_menus`.`sys_base_menu_id` = `sys_base_menus`.`id`)))").Error; err != nil {
return err
}
color.Info.Println("\n[Mysql] --> authority_menu 视图创建成功!")
return nil
}
@@ -1,13 +1,17 @@
package datas
package source
import (
"gin-vue-admin/global"
gormadapter "github.com/casbin/gorm-adapter/v3"
"github.com/gookit/color"
"gorm.io/gorm"
"os"
)
var Carbines = []gormadapter.CasbinRule{
var Casbin = new(casbin)
type casbin struct{}
var carbines = []gormadapter.CasbinRule{
{PType: "p", V0: "888", V1: "/base/login", V2: "POST"},
{PType: "p", V0: "888", V1: "/user/register", V2: "POST"},
{PType: "p", V0: "888", V1: "/api/createApi", V2: "POST"},
@@ -51,6 +55,7 @@ var Carbines = []gormadapter.CasbinRule{
{PType: "p", V0: "888", V1: "/customer/customer", V2: "GET"},
{PType: "p", V0: "888", V1: "/customer/customerList", V2: "GET"},
{PType: "p", V0: "888", V1: "/autoCode/createTemp", V2: "POST"},
{PType: "p", V0: "888", V1: "/autoCode/preview", V2: "POST"},
{PType: "p", V0: "888", V1: "/autoCode/getTables", V2: "GET"},
{PType: "p", V0: "888", V1: "/autoCode/getDB", V2: "GET"},
{PType: "p", V0: "888", V1: "/autoCode/getColumn", V2: "GET"},
@@ -75,6 +80,22 @@ var Carbines = []gormadapter.CasbinRule{
{PType: "p", V0: "888", V1: "/simpleUploader/upload", V2: "POST"},
{PType: "p", V0: "888", V1: "/simpleUploader/checkFileMd5", V2: "GET"},
{PType: "p", V0: "888", V1: "/simpleUploader/mergeFileMd5", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/createWorkflowProcess", V2: "POST"},
{PType: "p", V0: "888", V1: "/workflowProcess/deleteWorkflowProcess", V2: "DELETE"},
{PType: "p", V0: "888", V1: "/workflowProcess/deleteWorkflowProcessByIds", V2: "DELETE"},
{PType: "p", V0: "888", V1: "/workflowProcess/updateWorkflowProcess", V2: "PUT"},
{PType: "p", V0: "888", V1: "/workflowProcess/findWorkflowProcess", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/getWorkflowProcessList", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/findWorkflowStep", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/startWorkflow", V2: "POST"},
{PType: "p", V0: "888", V1: "/workflowProcess/completeWorkflowMove", V2: "POST"},
{PType: "p", V0: "888", V1: "/workflowProcess/getMyStated", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/getMyNeed", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/getWorkflowMoveByID", V2: "GET"},
{PType: "p", V0: "888", V1: "/excel/importExcel", V2: "POST"},
{PType: "p", V0: "888", V1: "/excel/loadExcel", V2: "GET"},
{PType: "p", V0: "888", V1: "/excel/exportExcel", V2: "POST"},
{PType: "p", V0: "888", V1: "/excel/downloadTemplate", V2: "GET"},
{PType: "p", V0: "8881", V1: "/base/login", V2: "POST"},
{PType: "p", V0: "8881", V1: "/user/register", V2: "POST"},
{PType: "p", V0: "8881", V1: "/api/createApi", V2: "POST"},
@@ -152,18 +173,19 @@ var Carbines = []gormadapter.CasbinRule{
{PType: "p", V0: "9528", V1: "/autoCode/createTemp", V2: "POST"},
}
func InitCasbinModel(db *gorm.DB) {
if err := db.Transaction(func(tx *gorm.DB) error {
if tx.Where("p_type = ? AND v0 IN ?", "p", []string{"888", "8881", "9528"}).Find(&[]gormadapter.CasbinRule{}).RowsAffected == 142 {
color.Danger.Println("casbin_rule表的初始数据已存在!")
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: casbin_rule 表数据初始化
func (c *casbin) Init() error {
global.GVA_DB.AutoMigrate(gormadapter.CasbinRule{})
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if tx.Find(&[]gormadapter.CasbinRule{}).RowsAffected == 154 {
color.Danger.Println("\n[Mysql] --> casbin_rule 表的初始数据已存在!")
return nil
}
if err := tx.Create(&Carbines).Error; err != nil { // 遇到错误时回滚事务
if err := tx.Create(&carbines).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> casbin_rule 表初始数据成功!")
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> casbin_rule 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
})
}
+41
View File
@@ -0,0 +1,41 @@
package source
import (
"gin-vue-admin/global"
"github.com/gookit/color"
"gorm.io/gorm"
)
var DataAuthorities = new(dataAuthorities)
type dataAuthorities struct{}
type DataAuthority struct {
AuthorityId string `gorm:"column:sys_authority_authority_id"`
DataAuthority string `gorm:"column:data_authority_id_authority_id"`
}
var infos = []DataAuthority{
{"888", "888"},
{"888", "8881"},
{"888", "9528"},
{"9528", "8881"},
{"9528", "9528"},
}
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: sys_data_authority_id 表数据初始化
func (d *dataAuthorities) Init() error {
return global.GVA_DB.Table("sys_data_authority_id").Transaction(func(tx *gorm.DB) error {
if tx.Where("sys_authority_authority_id IN ('888', '9528') ").Find(&[]DataAuthority{}).RowsAffected == 5 {
color.Danger.Println("\n[Mysql] --> sys_data_authority_id 表初始数据已存在!")
return nil
}
if err := tx.Create(&infos).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> sys_data_authority_id 表初始数据成功!")
return nil
})
}
@@ -1,19 +1,25 @@
package datas
package source
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"github.com/gookit/color"
"os"
"time"
"gin-vue-admin/model"
"gorm.io/gorm"
)
func InitSysDictionary(db *gorm.DB) {
var status = new(bool)
var Dictionary = new(dictionary)
type dictionary struct{}
var status = new(bool)
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: sys_dictionaries 表数据初始化
func (d *dictionary) Init() error {
*status = true
Dictionaries := []model.SysDictionary{
var dictionaries = []model.SysDictionary{
{GVA_MODEL: global.GVA_MODEL{ID: 1, CreatedAt: time.Now(), UpdatedAt: time.Now()}, Name: "性别", Type: "sex", Status: status, Desc: "性别字典"},
{GVA_MODEL: global.GVA_MODEL{ID: 2, CreatedAt: time.Now(), UpdatedAt: time.Now()}, Name: "数据库int类型", Type: "int", Status: status, Desc: "int类型对应的数据库类型"},
{GVA_MODEL: global.GVA_MODEL{ID: 3, CreatedAt: time.Now(), UpdatedAt: time.Now()}, Name: "数据库时间日期类型", Type: "time.Time", Status: status, Desc: "数据库时间日期类型"},
@@ -21,17 +27,15 @@ func InitSysDictionary(db *gorm.DB) {
{GVA_MODEL: global.GVA_MODEL{ID: 5, CreatedAt: time.Now(), UpdatedAt: time.Now()}, Name: "数据库字符串", Type: "string", Status: status, Desc: "数据库字符串"},
{GVA_MODEL: global.GVA_MODEL{ID: 6, CreatedAt: time.Now(), UpdatedAt: time.Now()}, Name: "数据库bool类型", Type: "bool", Status: status, Desc: "数据库bool类型"},
}
if err := db.Transaction(func(tx *gorm.DB) error {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if tx.Where("id IN ?", []int{1, 6}).Find(&[]model.SysDictionary{}).RowsAffected == 2 {
color.Danger.Println("sys_dictionaries表的初始数据已存在!")
color.Danger.Println("\n[Mysql] --> sys_dictionaries 表初始数据已存在!")
return nil
}
if err := tx.Create(&Dictionaries).Error; err != nil { // 遇到错误时回滚事务
if err := tx.Create(&dictionaries).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> sys_dictionaries 表初始数据成功!")
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> sys_dictionaries 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
}
})
}
@@ -1,19 +1,22 @@
package datas
package source
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"github.com/gookit/color"
"os"
"time"
"gin-vue-admin/model"
"gorm.io/gorm"
)
func InitSysDictionaryDetail(db *gorm.DB) {
status := new(bool)
*status = true
DictionaryDetail := []model.SysDictionaryDetail{
var DictionaryDetail = new(dictionaryDetail)
type dictionaryDetail struct{}
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: dictionary_details 表数据初始化
func (d *dictionaryDetail) Init() error {
var details = []model.SysDictionaryDetail{
{global.GVA_MODEL{ID: 1, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "smallint", 1, status, 1, 2},
{global.GVA_MODEL{ID: 2, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "mediumint", 2, status, 2, 2},
{global.GVA_MODEL{ID: 3, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "int", 3, status, 3, 2},
@@ -38,17 +41,15 @@ func InitSysDictionaryDetail(db *gorm.DB) {
{global.GVA_MODEL{ID: 22, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "longtext", 9, status, 9, 5},
{global.GVA_MODEL{ID: 23, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "tinyint", 0, status, 0, 6},
}
if err := db.Transaction(func(tx *gorm.DB) error {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if tx.Where("id IN ?", []int{1, 23}).Find(&[]model.SysDictionaryDetail{}).RowsAffected == 2 {
color.Danger.Println("sys_dictionary_details表的初始数据已存在!")
color.Danger.Println("\n[Mysql] --> sys_dictionary_details 表的初始数据已存在!")
return nil
}
if err := tx.Create(&DictionaryDetail).Error; err != nil { // 遇到错误时回滚事务
if err := tx.Create(&details).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> sys_dictionary_details 表初始数据成功!")
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> sys_dictionary_details 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
})
}
@@ -1,33 +1,34 @@
package datas
package source
import (
"gin-vue-admin/global"
"github.com/gookit/color"
"os"
"time"
"gin-vue-admin/model"
"github.com/gookit/color"
"gorm.io/gorm"
"time"
)
var Files = []model.ExaFileUploadAndDownload{
var File = new(file)
type file struct{}
var files = []model.ExaFileUploadAndDownload{
{global.GVA_MODEL{ID: 1, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "10.png", "http://qmplusimg.henrongyi.top/gvalogo.png", "png", "158787308910.png"},
{global.GVA_MODEL{ID: 2, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "logo.png", "http://qmplusimg.henrongyi.top/1576554439myAvatar.png", "png", "1587973709logo.png"},
}
func InitExaFileUploadAndDownload(db *gorm.DB) {
if err := db.Transaction(func(tx *gorm.DB) error {
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: exa_file_upload_and_downloads 表初始化数据
func (f *file) Init() error {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if tx.Where("id IN ?", []int{1, 2}).Find(&[]model.ExaFileUploadAndDownload{}).RowsAffected == 2 {
color.Danger.Println("exa_file_upload_and_downloads表的初始数据已存在!")
color.Danger.Println("\n[Mysql] --> exa_file_upload_and_downloads 表初始数据已存在!")
return nil
}
if err := tx.Create(&Files).Error; err != nil { // 遇到错误时回滚事务
if err := tx.Create(&files).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("[Mysql]-->初始化数据成功")
color.Info.Println("\n[Mysql] --> exa_file_upload_and_downloads 表初始数据成功!")
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> exa_file_upload_and_downloads 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
}
})
}
@@ -1,16 +1,19 @@
package datas
package source
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"github.com/gookit/color"
"os"
"time"
"gin-vue-admin/model"
"gorm.io/gorm"
)
var BaseMenus = []model.SysBaseMenu{
var BaseMenu = new(menu)
type menu struct{}
var menus = []model.SysBaseMenu{
{GVA_MODEL: global.GVA_MODEL{ID: 1, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "dashboard", Name: "dashboard", Hidden: false, Component: "view/dashboard/index.vue", Sort: 1, Meta: model.Meta{Title: "仪表盘", Icon: "setting"}},
{GVA_MODEL: global.GVA_MODEL{ID: 2, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "0", Path: "about", Name: "about", Component: "view/about/index.vue", Sort: 7, Meta: model.Meta{Title: "关于我们", Icon: "info"}},
{GVA_MODEL: global.GVA_MODEL{ID: 3, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "0", Path: "admin", Name: "superAdmin", Component: "view/superAdmin/index.vue", Sort: 3, Meta: model.Meta{Title: "超级管理员", Icon: "user-solid"}},
@@ -20,38 +23,40 @@ var BaseMenus = []model.SysBaseMenu{
{GVA_MODEL: global.GVA_MODEL{ID: 7, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "3", Path: "user", Name: "user", Component: "view/superAdmin/user/user.vue", Sort: 4, Meta: model.Meta{Title: "用户管理", Icon: "coordinate"}},
{GVA_MODEL: global.GVA_MODEL{ID: 8, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: true, ParentId: "0", Path: "person", Name: "person", Component: "view/person/person.vue", Sort: 4, Meta: model.Meta{Title: "个人信息", Icon: "message-solid"}},
{GVA_MODEL: global.GVA_MODEL{ID: 9, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "0", Path: "example", Name: "example", Component: "view/example/index.vue", Sort: 6, Meta: model.Meta{Title: "示例文件", Icon: "s-management"}},
{GVA_MODEL: global.GVA_MODEL{ID: 10, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "table", Name: "table", Component: "view/example/table/table.vue", Sort: 1, Meta: model.Meta{Title: "表格示例", Icon: "s-order"}},
{GVA_MODEL: global.GVA_MODEL{ID: 11, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "form", Name: "form", Component: "view/example/form/form.vue", Sort: 2, Meta: model.Meta{Title: "表单示例", Icon: "document"}},
{GVA_MODEL: global.GVA_MODEL{ID: 12, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "rte", Name: "rte", Component: "view/example/rte/rte.vue", Sort: 3, Meta: model.Meta{Title: "富文本编辑器", Icon: "reading"}},
{GVA_MODEL: global.GVA_MODEL{ID: 13, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "excel", Name: "excel", Component: "view/example/excel/excel.vue", Sort: 4, Meta: model.Meta{Title: "excel导入导出", Icon: "s-marketing"}},
{GVA_MODEL: global.GVA_MODEL{ID: 14, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "upload", Name: "upload", Component: "view/example/upload/upload.vue", Sort: 5, Meta: model.Meta{Title: "上传下载", Icon: "upload"}},
{GVA_MODEL: global.GVA_MODEL{ID: 15, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "breakpoint", Name: "breakpoint", Component: "view/example/breakpoint/breakpoint.vue", Sort: 6, Meta: model.Meta{Title: "断点续传", Icon: "upload"}},
{GVA_MODEL: global.GVA_MODEL{ID: 16, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "customer", Name: "customer", Component: "view/example/customer/customer.vue", Sort: 7, Meta: model.Meta{Title: "客户列表(资源示例)", Icon: "s-custom"}},
{GVA_MODEL: global.GVA_MODEL{ID: 17, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "0", Path: "systemTools", Name: "systemTools", Component: "view/systemTools/index.vue", Sort: 5, Meta: model.Meta{Title: "系统工具", Icon: "s-cooperation"}},
{GVA_MODEL: global.GVA_MODEL{ID: 18, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "17", Path: "autoCode", Name: "autoCode", Component: "view/systemTools/autoCode/index.vue", Sort: 1, Meta: model.Meta{Title: "代码生成器", Icon: "cpu", KeepAlive: true}},
{GVA_MODEL: global.GVA_MODEL{ID: 19, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "17", Path: "formCreate", Name: "formCreate", Component: "view/systemTools/formCreate/index.vue", Sort: 2, Meta: model.Meta{Title: "表单生成器", Icon: "magic-stick", KeepAlive: true}},
{GVA_MODEL: global.GVA_MODEL{ID: 20, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "17", Path: "system", Name: "system", Component: "view/systemTools/system/system.vue", Sort: 3, Meta: model.Meta{Title: "系统配置", Icon: "s-operation"}},
{GVA_MODEL: global.GVA_MODEL{ID: 21, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "0", Path: "iconList", Name: "iconList", Component: "view/iconList/index.vue", Sort: 2, Meta: model.Meta{Title: "图标集合", Icon: "star-on"}},
{GVA_MODEL: global.GVA_MODEL{ID: 22, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "3", Path: "dictionary", Name: "dictionary", Component: "view/superAdmin/dictionary/sysDictionary.vue", Sort: 5, Meta: model.Meta{Title: "字典管理", Icon: "notebook-2"}},
{GVA_MODEL: global.GVA_MODEL{ID: 23, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: true, ParentId: "3", Path: "dictionaryDetail/:id", Name: "dictionaryDetail", Component: "view/superAdmin/dictionary/sysDictionaryDetail.vue", Sort: 1, Meta: model.Meta{Title: "字典详情", Icon: "s-order"}},
{GVA_MODEL: global.GVA_MODEL{ID: 24, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "3", Path: "operation", Name: "operation", Component: "view/superAdmin/operation/sysOperationRecord.vue", Sort: 6, Meta: model.Meta{Title: "操作历史", Icon: "time"}},
{GVA_MODEL: global.GVA_MODEL{ID: 25, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "simpleUploader", Name: "simpleUploader", Component: "view/example/simpleUploader/simpleUploader", Sort: 6, Meta: model.Meta{Title: "断点续传(插件版)", Icon: "upload"}},
{GVA_MODEL: global.GVA_MODEL{ID: 26, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "https://www.gin-vue-admin.com", Name: "https://www.gin-vue-admin.com", Hidden: false, Component: "/", Sort: 0, Meta: model.Meta{Title: "官方网站", Icon: "s-home"}},
{GVA_MODEL: global.GVA_MODEL{ID: 27, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "state", Name: "state", Hidden: false, Component: "view/system/state.vue", Sort: 6, Meta: model.Meta{Title: "服务器状态", Icon: "cloudy"}},
{GVA_MODEL: global.GVA_MODEL{ID: 10, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "excel", Name: "excel", Component: "view/example/excel/excel.vue", Sort: 4, Meta: model.Meta{Title: "excel导入导出", Icon: "s-marketing"}},
{GVA_MODEL: global.GVA_MODEL{ID: 11, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "upload", Name: "upload", Component: "view/example/upload/upload.vue", Sort: 5, Meta: model.Meta{Title: "媒体库(上传下载)", Icon: "upload"}},
{GVA_MODEL: global.GVA_MODEL{ID: 12, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "breakpoint", Name: "breakpoint", Component: "view/example/breakpoint/breakpoint.vue", Sort: 6, Meta: model.Meta{Title: "断点续传", Icon: "upload"}},
{GVA_MODEL: global.GVA_MODEL{ID: 13, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "customer", Name: "customer", Component: "view/example/customer/customer.vue", Sort: 7, Meta: model.Meta{Title: "客户列表(资源示例)", Icon: "s-custom"}},
{GVA_MODEL: global.GVA_MODEL{ID: 14, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "0", Path: "systemTools", Name: "systemTools", Component: "view/systemTools/index.vue", Sort: 5, Meta: model.Meta{Title: "系统工具", Icon: "s-cooperation"}},
{GVA_MODEL: global.GVA_MODEL{ID: 15, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "14", Path: "autoCode", Name: "autoCode", Component: "view/systemTools/autoCode/index.vue", Sort: 1, Meta: model.Meta{Title: "代码生成器", Icon: "cpu", KeepAlive: true}},
{GVA_MODEL: global.GVA_MODEL{ID: 16, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "14", Path: "formCreate", Name: "formCreate", Component: "view/systemTools/formCreate/index.vue", Sort: 2, Meta: model.Meta{Title: "表单生成器", Icon: "magic-stick", KeepAlive: true}},
{GVA_MODEL: global.GVA_MODEL{ID: 17, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "14", Path: "system", Name: "system", Component: "view/systemTools/system/system.vue", Sort: 3, Meta: model.Meta{Title: "系统配置", Icon: "s-operation"}},
{GVA_MODEL: global.GVA_MODEL{ID: 18, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "3", Path: "dictionary", Name: "dictionary", Component: "view/superAdmin/dictionary/sysDictionary.vue", Sort: 5, Meta: model.Meta{Title: "字典管理", Icon: "notebook-2"}},
{GVA_MODEL: global.GVA_MODEL{ID: 19, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: true, ParentId: "3", Path: "dictionaryDetail/:id", Name: "dictionaryDetail", Component: "view/superAdmin/dictionary/sysDictionaryDetail.vue", Sort: 1, Meta: model.Meta{Title: "字典详情", Icon: "s-order"}},
{GVA_MODEL: global.GVA_MODEL{ID: 20, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "3", Path: "operation", Name: "operation", Component: "view/superAdmin/operation/sysOperationRecord.vue", Sort: 6, Meta: model.Meta{Title: "操作历史", Icon: "time"}},
{GVA_MODEL: global.GVA_MODEL{ID: 21, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "simpleUploader", Name: "simpleUploader", Component: "view/example/simpleUploader/simpleUploader", Sort: 6, Meta: model.Meta{Title: "断点续传(插件版)", Icon: "upload"}},
{GVA_MODEL: global.GVA_MODEL{ID: 22, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "https://www.gin-vue-admin.com", Name: "https://www.gin-vue-admin.com", Hidden: false, Component: "/", Sort: 0, Meta: model.Meta{Title: "官方网站", Icon: "s-home"}},
{GVA_MODEL: global.GVA_MODEL{ID: 23, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "state", Name: "state", Hidden: false, Component: "view/system/state.vue", Sort: 6, Meta: model.Meta{Title: "服务器状态", Icon: "cloudy"}},
{GVA_MODEL: global.GVA_MODEL{ID: 24, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "workflow", Name: "workflow", Hidden: false, Component: "view/workflow/index.vue", Sort: 5, Meta: model.Meta{Title: "工作流功能", Icon: "phone"}},
{GVA_MODEL: global.GVA_MODEL{ID: 25, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "24", Path: "workflowCreate", Name: "workflowCreate", Hidden: false, Component: "view/workflow/workflowCreate/workflowCreate.vue", Sort: 0, Meta: model.Meta{Title: "工作流绘制", Icon: "circle-plus"}},
{GVA_MODEL: global.GVA_MODEL{ID: 26, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "24", Path: "workflowProcess", Name: "workflowProcess", Hidden: false, Component: "view/workflow/workflowProcess/workflowProcess.vue", Sort: 0, Meta: model.Meta{Title: "工作流列表", Icon: "s-cooperation"}},
{GVA_MODEL: global.GVA_MODEL{ID: 27, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "24", Path: "workflowUse", Name: "workflowUse", Hidden: true, Component: "view/workflow/workflowUse/workflowUse.vue", Sort: 0, Meta: model.Meta{Title: "使用工作流", Icon: "video-play"}},
{GVA_MODEL: global.GVA_MODEL{ID: 28, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "24", Path: "started", Name: "started", Hidden: false, Component: "view/workflow/userList/started.vue", Sort: 0, Meta: model.Meta{Title: "我发起的", Icon: "s-order"}},
{GVA_MODEL: global.GVA_MODEL{ID: 29, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "24", Path: "need", Name: "need", Hidden: false, Component: "view/workflow/userList/need.vue", Sort: 0, Meta: model.Meta{Title: "我的待办", Icon: "s-platform"}},
}
func InitSysBaseMenus(db *gorm.DB) {
if err := db.Transaction(func(tx *gorm.DB) error {
if tx.Where("id IN ?", []int{1, 27}).Find(&[]model.SysBaseMenu{}).RowsAffected == 2 {
color.Danger.Println("sys_base_menus表的初始数据已存在!")
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: sys_base_menus 表数据初始化
func (m *menu) Init() error {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if tx.Where("id IN ?", []int{1, 29}).Find(&[]model.SysBaseMenu{}).RowsAffected == 2 {
color.Danger.Println("\n[Mysql] --> sys_base_menus 表的初始数据已存在!")
return nil
}
if err := tx.Create(&BaseMenus).Error; err != nil { // 遇到错误时回滚事务
if err := tx.Create(&menus).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> sys_base_menus 表初始数据成功!")
return nil
}); err != nil {
color.Warn.Printf("[Mysql]--> sys_base_menus 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
})
}
+79
View File
@@ -0,0 +1,79 @@
package source
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"time"
"github.com/gookit/color"
"gorm.io/gorm"
)
var Workflow = new(workflow)
type workflow struct{}
var WorkflowProcess = []model.WorkflowProcess{
{ID: "leaveFlow", CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "leaveFlow", Clazz: "process", Label: "请假流程(演示)", HideIcon: false, Description: "请假流程演示", View: "view/iconList/index.vue"},
}
var WorkflowNodes = []model.WorkflowNode{
{ID: "end1603681358043", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "end", Label: "请假失败", Type: "end-node", Shape: "end-node", Description: "", View: "view/exa_wf_leave/exa_wf_leaveFrom.vue", X: 302, Y: 545.5, HideIcon: false, AssignType: "", AssignValue: "", Success: false},
{ID: "end1603681360882", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "end", Label: "请假成功", Type: "end-node", Shape: "end-node", Description: "请假完成,具体结果等待提交", View: "view/exa_wf_leave/exa_wf_leaveFrom.vue", X: 83.5, Y: 546, HideIcon: false, AssignType: "", AssignValue: "", Success: true},
{ID: "start1603681292875", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "start", Label: "发起请假", Type: "start-node", Shape: "start-node", Description: "发起一个请假流程", View: "view/exa_wf_leave/exa_wf_leaveFrom.vue", X: 201, Y: 109, HideIcon: false, AssignType: "", AssignValue: "", Success: false},
{ID: "userTask1603681299962", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "userTask", Label: "审批", Type: "user-task-node", Shape: "user-task-node", Description: "审批会签", View: "view/exa_wf_leave/exa_wf_leaveFrom.vue", X: 202, Y: 320.5, HideIcon: false, AssignType: "user", AssignValue: ",1,2,", Success: false},
}
var WorkflowEdge = []model.WorkflowEdge{
{ID: "flow1604985849039", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "flow", Source: "start1603681292875", Target: "userTask1603681299962", SourceAnchor: 1, TargetAnchor: 3, Shape: "flow-polyline-round", Label: "", HideIcon: false, ConditionExpression: "", Reverse: false},
{ID: "flow1604985879574", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "flow", Source: "userTask1603681299962", Target: "end1603681360882", SourceAnchor: 0, TargetAnchor: 2, Shape: "flow-polyline-round", Label: "同意", HideIcon: false, ConditionExpression: "yes", Reverse: false},
{ID: "flow1604985881207", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "flow", Source: "userTask1603681299962", Target: "end1603681358043", SourceAnchor: 2, TargetAnchor: 2, Shape: "flow-polyline-round", Label: "不同意", HideIcon: false, ConditionExpression: "no", Reverse: false},
}
var WorkflowStartPoint = []model.WorkflowStartPoint{
{WorkflowEdgeID: "flow1604985849039", GVA_MODEL: global.GVA_MODEL{ID: 31, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 137, Y: 201, Index: 1},
{WorkflowEdgeID: "flow1604985879574", GVA_MODEL: global.GVA_MODEL{ID: 32, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 320.5, Y: 174, Index: 0},
{WorkflowEdgeID: "flow1604985881207", GVA_MODEL: global.GVA_MODEL{ID: 33, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 320.5, Y: 230, Index: 2},
}
var WorkflowEndPoint = []model.WorkflowEndPoint{
{WorkflowEdgeID: "flow1604985849039", GVA_MODEL: global.GVA_MODEL{ID: 31, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 270, Y: 202, Index: 3},
{WorkflowEdgeID: "flow1604985879574", GVA_MODEL: global.GVA_MODEL{ID: 32, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 518, Y: 83.5, Index: 2},
{WorkflowEdgeID: "flow1604985881207", GVA_MODEL: global.GVA_MODEL{ID: 33, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 517.5, Y: 302, Index: 2},
}
//@author: [SliverHorn](https://github.com/SliverHorn)
//@description: 工作流相关 表数据初始化
func (w *workflow) Init() error {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if tx.Where("id IN ?", []string{"leaveFlow"}).Find(&[]model.WorkflowProcess{}).RowsAffected == 1 {
// continue
} else if err := tx.Create(&WorkflowProcess).Error; err != nil { // 遇到错误时回滚事务
return err
}
if tx.Where("id IN ?", []string{"end1603681358043", "end1603681360882", "start1603681292875", "userTask1603681299962"}).Find(&[]model.WorkflowNode{}).RowsAffected == 4 {
// continue
} else if err := tx.Create(&WorkflowNodes).Error; err != nil { // 遇到错误时回滚事务
return err
}
if tx.Where("id IN ?", []string{"flow1604985849039", "flow1604985879574", "flow1604985881207"}).Find(&[]model.WorkflowEdge{}).RowsAffected == 3 {
} else if err := tx.Create(&WorkflowEdge).Error; err != nil { // 遇到错误时回滚事务
return err
}
if tx.Where("workflow_edge_id IN ?", []string{"flow1604985849039", "flow1604985879574", "flow1604985881207"}).Find(&[]model.WorkflowStartPoint{}).RowsAffected == 3 {
} else if err := tx.Create(&WorkflowStartPoint).Error; err != nil { // 遇到错误时回滚事务
return err
}
if tx.Where("workflow_edge_id IN ?", []string{"flow1604985849039", "flow1604985879574", "flow1604985881207"}).Find(&[]model.WorkflowEndPoint{}).RowsAffected == 3 {
} else if err := tx.Create(&WorkflowEndPoint).Error; err != nil { // 遇到错误时回滚事务
return err
}
color.Info.Println("\n[Mysql] --> 工作流相关 表初始数据成功!")
return nil
})
}
+7 -3
View File
@@ -55,7 +55,6 @@ func CheckMd5(content []byte, chunkMd5 string) (CanUpload bool) {
func makeFileContent(content []byte, fileName string, FileDir string, contentNumber int) (error, string) {
path := FileDir + fileName + "_" + strconv.Itoa(contentNumber)
f, err := os.Create(path)
defer f.Close()
if err != nil {
return err, path
} else {
@@ -64,6 +63,7 @@ func makeFileContent(content []byte, fileName string, FileDir string, contentNum
return err, path
}
}
defer f.Close()
return nil, path
}
@@ -79,7 +79,11 @@ func MakeFile(fileName string, FileMd5 string) (error, string) {
return err, finishDir + fileName
}
_ = os.MkdirAll(finishDir, os.ModePerm)
fd, _ := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
fd, err := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
return err, finishDir + fileName
}
defer fd.Close()
for k := range rd {
content, _ := ioutil.ReadFile(breakpointDir + FileMd5 + "/" + fileName + "_" + strconv.Itoa(k))
_, err = fd.Write(content)
@@ -88,7 +92,7 @@ func MakeFile(fileName string, FileMd5 string) (error, string) {
return err, finishDir + fileName
}
}
defer fd.Close()
return nil, finishDir + fileName
}
-204
View File
@@ -1,204 +0,0 @@
package utils
import (
"bytes"
"context"
"fmt"
"io"
"os"
"os/exec"
"runtime"
"sync"
)
//@author: [songzhibin97](https://github.com/songzhibin97)
//@interface_name: RunTask
//@description: Task接口
type RunTask interface {
AddTask()
RunTask()
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@struct_name: T
//@description: Task任务
type T struct {
sync.Mutex
// 获取事件channel
ch chan struct{}
closeChan chan struct{}
// 记录process对象
p *os.Process
// 执行任务
f func(chan struct{}) error
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: NewT
//@description: T的实例化方法
//@return: *T
func NewT() *T {
return newT(nil)
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: newT
//@description:
//@param: f func(chan struct{}) error
//@return: *T
func newT(f func(chan struct{}) error) *T {
t := &T{
Mutex: sync.Mutex{},
ch: make(chan struct{}, 1),
closeChan: make(chan struct{}),
f: f,
}
if f == nil {
t.f = t.DefaultF
}
return t
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: *T
//@function: AddTask
//@description: 添加任务
func (t *T) AddTask() {
if len(t.ch) == 1 {
return
}
t.Lock()
defer t.Unlock()
if len(t.ch) == 1 {
// 代表已经有任务了
// 直接丢弃这次任务
return
}
t.ch <- struct{}{}
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: *T
//@function: RunTask
//@description: 启动任务
func (t *T) RunTask() {
fmt.Println("进入")
// 这里做的make 是用于关闭上一个执行的任务
ch := make(chan struct{})
// 先run服务
go t.f(ch)
for {
_, ok := <-t.ch
if !ok {
return
}
ch <- struct{}{}
// 等待上一个关闭
<-t.closeChan
go t.f(ch)
}
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: t *T
//@function: DefaultF
//@description: 默认的StartFunction
//@param: ch chan struct{}
//@return: error
func (t *T) DefaultF(ch chan struct{}) error {
var buildCmd *exec.Cmd
var cmd *exec.Cmd
// 检测系统是否有编译环境
_, err := exec.LookPath("go")
if err != nil {
return err
}
// build
switch runtime.GOOS {
case "windows":
buildCmd = exec.Command("go", "build", "-o", "server.exe", "main.go")
default:
buildCmd = exec.Command("go", "build", "-o", "server", "main.go")
}
//cmd = exec.Command("go", "run", "main.go")
err = buildCmd.Run()
if err != nil {
return err
}
fmt.Println("build 执行完成")
// 执行
switch runtime.GOOS {
case "windows":
cmd = exec.Command("server.exe")
default:
cmd = exec.Command("./server")
}
// 开始执行任务
ctx, cancel := context.WithCancel(context.Background())
err = t.echo(cmd, ctx)
<-ch
// 回收资源
fmt.Println("pid:", t.p.Pid, "->Kill")
err = t.p.Kill()
cancel()
// 发送关闭完成信号
t.closeChan <- struct{}{}
return err
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: t *T
//@function: echo
//@description: 封装回显
//@param: cmd *exec.Cmd, ctx context.Context
//@return: error
func (t *T) echo(cmd *exec.Cmd, ctx context.Context) error {
var stdoutBuf bytes.Buffer
stdoutIn, _ := cmd.StdoutPipe()
var errStdout error
stdout := io.MultiWriter(os.Stdout, &stdoutBuf)
err := cmd.Start()
if err != nil {
return err
}
go func(ctx context.Context) {
_, errStdout = io.Copy(stdout, stdoutIn)
select {
case <-ctx.Done():
return
default:
}
}(ctx)
t.p = cmd.Process
fmt.Println("pid", t.p.Pid)
go func() {
_ = cmd.Wait()
if errStdout != nil {
fmt.Printf("failed to capture stdout or stderr\n")
}
fmt.Printf("%s\n", string(stdoutBuf.Bytes()))
select {
case <-ctx.Done():
//_ = os.Stdout.Close()
return
default:
}
}()
return nil
}
-174
View File
@@ -1,174 +0,0 @@
package utils
import (
"errors"
"fmt"
"github.com/fsnotify/fsnotify"
"io/ioutil"
"os"
"path/filepath"
)
//@author: [songzhibin97](https://github.com/songzhibin97)
//@struct_name: Watch
//@description: 监控对象
type Watch struct {
*fsnotify.Watcher
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: NewWatch
//@description: Watch的实例化方法
//@return: *Watch
func NewWatch() *Watch {
obj, _ := fsnotify.NewWatcher()
return &Watch{obj}
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: w *Watch
//@function: Watch
//@description: 监控对象
//@param: path string, t *T
//@return: error
func (w *Watch) Watch(path string, t *T) error {
// 先转化为绝对路径
path, err := filepath.Abs(path)
if err != nil {
return err
}
// 判断是单个文件还是目录文件
fileInfo, err := os.Stat(path)
if err != nil {
return err
}
// 判断是否是目录 添加监控
if fileInfo.IsDir() {
// dir
err = w.watchDir(path)
} else {
err = w.watchFile(path)
}
if err != nil {
return err
}
c := make(chan error)
// 启动监控
go func() {
for {
select {
case even, ok := <-w.Events:
if !ok {
// close
fmt.Println("Errors close")
c <- errors.New("errors close")
return
}
// 判断事件
switch {
case even.Op&fsnotify.Create == fsnotify.Create:
//这里获取新创建文件的信息,如果是目录,则加入监控中
fmt.Println("创建文件 : ", even.Name)
//t.AddTask()
_ = w.Add(even.Name)
case even.Op&fsnotify.Write == fsnotify.Write:
fmt.Println("修改文件 : ", even.Name)
w.addTask(t, even.Name)
case even.Op&fsnotify.Remove == fsnotify.Remove || even.Op&fsnotify.Rename == fsnotify.Rename:
fmt.Println("删除或重命名文件 : ", even.Name)
_ = w.Remove(even.Name)
w.addTask(t, even.Name)
}
case err = <-w.Errors:
fmt.Println("even Error:", err)
c <- err
return
}
}
}()
return <-c
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: w *Watch
//@function: watchDir
//@description: 处理监控目录
//@param: path string
//@return: error
func (w *Watch) watchDir(path string) error {
// 先将自己添加到监控
err := w.Add(path)
if err != nil {
return err
}
fileSlice, err := ioutil.ReadDir(path)
if err != nil {
return err
}
for _, f := range fileSlice {
fPath := filepath.Join(path, f.Name())
if !f.IsDir() {
// 判断是否可监控的文件
if chickPower(fPath) {
err = w.watchFile(fPath)
if err != nil {
return err
}
}
} else {
err := w.watchDir(fPath)
if err != nil {
return err
}
}
}
return err
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: w *Watch
//@function: watchDir
//@description: 处理监控单文件
//@param: path string
//@return: error
func (w *Watch) watchFile(path string) error {
var err error
if chickPower(path) {
err = w.Add(path)
}
return err
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: chickPower
//@description: 判断是否在可控范围内
//@param: path string
//@return: error
func chickPower(name string) bool {
name = filepath.Ext(name)
return name == ".go" || name == ".yaml"
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: w *Watch
//@function: addTask
//@description: 偏函数 简化发送任务
//@param: path string
//@return: error
func (w *Watch) addTask(t *T, name string) {
if chickPower(name) {
fmt.Println("Add Task->>>>>>")
t.AddTask()
}
}
+74
View File
@@ -0,0 +1,74 @@
package upload
import (
"errors"
"gin-vue-admin/global"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"go.uber.org/zap"
"mime/multipart"
"path/filepath"
"time"
)
type AliyunOSS struct{}
func (*AliyunOSS) UploadFile(file *multipart.FileHeader) (string, string, error) {
bucket, err := NewBucket()
if err != nil {
global.GVA_LOG.Error("function AliyunOSS.NewBucket() Failed", zap.Any("err", err.Error()))
return "", "", errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error())
}
// 读取本地文件。
f, openError := file.Open()
if openError != nil {
global.GVA_LOG.Error("function file.Open() Failed", zap.Any("err", openError.Error()))
return "", "", errors.New("function file.Open() Failed, err:" + openError.Error())
}
//上传阿里云路径 文件名格式 自己可以改 建议保证唯一性
yunFileTmpPath := filepath.Join("uploads", time.Now().Format("2006-01-02")) + "/" + file.Filename
// 上传文件流。
err = bucket.PutObject(yunFileTmpPath, f)
if err != nil {
global.GVA_LOG.Error("function formUploader.Put() Failed", zap.Any("err", err.Error()))
return "", "", errors.New("function formUploader.Put() Failed, err:" + err.Error())
}
return global.GVA_CONFIG.AliyunOSS.BucketUrl + "/" + yunFileTmpPath, yunFileTmpPath, nil
}
func (*AliyunOSS) DeleteFile(key string) error {
bucket, err := NewBucket()
if err != nil {
global.GVA_LOG.Error("function AliyunOSS.NewBucket() Failed", zap.Any("err", err.Error()))
return errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error())
}
// 删除单个文件。objectName表示删除OSS文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
// 如需删除文件夹,请将objectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
err = bucket.DeleteObject(key)
if err != nil {
global.GVA_LOG.Error("function bucketManager.Delete() Filed", zap.Any("err", err.Error()))
return errors.New("function bucketManager.Delete() Filed, err:" + err.Error())
}
return nil
}
func NewBucket() (*oss.Bucket, error) {
// 创建OSSClient实例。
client, err := oss.New(global.GVA_CONFIG.AliyunOSS.Endpoint, global.GVA_CONFIG.AliyunOSS.AccessKeyId, global.GVA_CONFIG.AliyunOSS.AccessKeySecret)
if err != nil {
return nil, err
}
// 获取存储空间。
bucket, err := client.Bucket(global.GVA_CONFIG.AliyunOSS.BucketName)
if err != nil {
return nil, err
}
return bucket, nil
}
+59
View File
@@ -0,0 +1,59 @@
package upload
import (
"context"
"errors"
"fmt"
"gin-vue-admin/global"
"mime/multipart"
"net/http"
"net/url"
"time"
"github.com/tencentyun/cos-go-sdk-v5"
"go.uber.org/zap"
)
type TencentCOS struct{}
// UploadFile upload file to COS
func (*TencentCOS) UploadFile(file *multipart.FileHeader) (string, string, error) {
client := NewClient()
f, openError := file.Open()
if openError != nil {
global.GVA_LOG.Error("function file.Open() Filed", zap.Any("err", openError.Error()))
return "", "", errors.New("function file.Open() Filed, err:" + openError.Error())
}
fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename)
_, err := client.Object.Put(context.Background(), global.GVA_CONFIG.TencentCOS.PathPrefix+"/"+fileKey, f, nil)
if err != nil {
panic(err)
}
return global.GVA_CONFIG.TencentCOS.BaseURL + "/" + global.GVA_CONFIG.TencentCOS.PathPrefix + "/" + fileKey, fileKey, nil
}
// DeleteFile delete file form COS
func (*TencentCOS) DeleteFile(key string) error {
client := NewClient()
name := global.GVA_CONFIG.TencentCOS.PathPrefix + "/" + key
_, err := client.Object.Delete(context.Background(), name)
if err != nil {
global.GVA_LOG.Error("function bucketManager.Delete() Filed", zap.Any("err", err.Error()))
return errors.New("function bucketManager.Delete() Filed, err:" + err.Error())
}
return nil
}
// NewClient init COS client
func NewClient() *cos.Client {
urlStr, _ := url.Parse("https://" + global.GVA_CONFIG.TencentCOS.Bucket + ".cos." + global.GVA_CONFIG.TencentCOS.Region + ".myqcloud.com")
baseURL := &cos.BaseURL{BucketURL: urlStr}
client := cos.NewClient(baseURL, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: global.GVA_CONFIG.TencentCOS.SecretID,
SecretKey: global.GVA_CONFIG.TencentCOS.SecretKey,
},
})
return client
}
+5 -1
View File
@@ -28,7 +28,11 @@ func NewOss() OSS {
return &Local{}
case "qiniu":
return &Qiniu{}
case "tencent-cos":
return &TencentCOS{}
case "aliyun-oss":
return &AliyunOSS{}
default:
return &Local{}
}
}
}
-2
View File
@@ -6,12 +6,10 @@ var (
MenuVerify = Rules{"Path": {NotEmpty()}, "ParentId": {NotEmpty()}, "Name": {NotEmpty()}, "Component": {NotEmpty()}, "Sort": {Ge("0")}}
MenuMetaVerify = Rules{"Title": {NotEmpty()}}
LoginVerify = Rules{"CaptchaId": {NotEmpty()}, "Captcha": {NotEmpty()}, "Username": {NotEmpty()}, "Password": {NotEmpty()}}
SetUserVerify = Rules{"ID": {NotEmpty()}, "Username": {NotEmpty()}, "NickName": {NotEmpty()}, "HeaderImg": {NotEmpty()}}
RegisterVerify = Rules{"Username": {NotEmpty()}, "NickName": {NotEmpty()}, "Password": {NotEmpty()}, "AuthorityId": {NotEmpty()}}
PageInfoVerify = Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}}
CustomerVerify = Rules{"CustomerName": {NotEmpty()}, "CustomerPhoneData": {NotEmpty()}}
AutoCodeVerify = Rules{"Abbreviation": {NotEmpty()}, "StructName": {NotEmpty()}, "PackageName": {NotEmpty()}, "Fields": {NotEmpty()}}
WorkFlowVerify = Rules{"WorkflowNickName": {NotEmpty()}, "WorkflowName": {NotEmpty()}, "WorkflowDescription": {NotEmpty()}, "WorkflowStepInfo": {NotEmpty()}}
AuthorityVerify = Rules{"AuthorityId": {NotEmpty()}, "AuthorityName": {NotEmpty()}, "ParentId": {NotEmpty()}}
AuthorityIdVerify = Rules{"AuthorityId": {NotEmpty()}}
OldAuthorityVerify = Rules{"OldAuthorityId": {NotEmpty()}}
+40 -31
View File
@@ -13,51 +13,60 @@ import (
//@param: filename string, files []string, oldform, newform string
//@return: error
func ZipFiles(filename string, files []string, oldform, newform string) error {
func ZipFiles(filename string, files []string, oldForm, newForm string) error {
newZipFile, err := os.Create(filename)
if err != nil {
return err
}
defer newZipFile.Close()
defer func() {
_ = newZipFile.Close()
}()
zipWriter := zip.NewWriter(newZipFile)
defer zipWriter.Close()
defer func() {
_ = zipWriter.Close()
}()
// 把files添加到zip中
for _, file := range files {
zipfile, err := os.Open(file)
err = func(file string) error {
zipFile, err := os.Open(file)
if err != nil {
return err
}
defer zipFile.Close()
// 获取file的基础信息
info, err := zipFile.Stat()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
// 使用上面的FileInforHeader() 就可以把文件保存的路径替换成我们自己想要的了,如下面
header.Name = strings.Replace(file, oldForm, newForm, -1)
// 优化压缩
// 更多参考see http://golang.org/pkg/archive/zip/#pkg-constants
header.Method = zip.Deflate
writer, err := zipWriter.CreateHeader(header)
if err != nil {
return err
}
if _, err = io.Copy(writer, zipFile); err != nil {
return err
}
return nil
}(file)
if err != nil {
return err
}
defer zipfile.Close()
// 获取file的基础信息
info, err := zipfile.Stat()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
// 使用上面的FileInforHeader() 就可以把文件保存的路径替换成我们自己想要的了,如下面
header.Name = strings.Replace(file, oldform, newform, -1)
// 优化压缩
// 更多参考see http://golang.org/pkg/archive/zip/#pkg-constants
header.Method = zip.Deflate
writer, err := zipWriter.CreateHeader(header)
if err != nil {
return err
}
if _, err = io.Copy(writer, zipfile); err != nil {
return err
}
}
return nil
}

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