Compare commits

..

226 Commits

Author SHA1 Message Date
5bb9ed77b8 优化数据库连接配置,增强性能和稳定性 2025-08-07 17:51:31 +08:00
678686fd48 refactor(dri/baidu):优化导入路径和代码结构
- 更新了导入路径,使用了新的 "code.hoteas.com/golang/hotime/common" 路径
- 删除了未使用的变量和导入语句,简化了代码结构
2025-04-11 02:09:57 +08:00
9766648536 refactor(cache): 重构 CacheMemory 实现
- 使用 sync.Map替代自定义 Map 结构- 优化缓存过期处理逻辑
- 改进通配符删除功能
- 随机触发缓存清理机制
2025-04-10 22:09:53 +08:00
hoteas
2cf20e7206 增加数据库must设置 2023-04-06 11:37:03 +08:00
hoteas
8cac1f5393 修复部分bug,增加DB SUM函数,以及优化IN性能,增加分析接口 2023-03-22 03:17:33 +08:00
hoteas
8337cdec0c 修复部分bug,增加DB SUM函数,以及优化IN性能,增加分析接口 2023-03-10 15:22:03 +08:00
hoteas
46cecc47ea 修复部分bug 2022-12-31 22:28:12 +08:00
hoteas
7535300107 修复部分bug 2022-11-17 17:17:07 +08:00
hoteas
be41a70c76 修复部分bug 2022-11-14 16:49:37 +08:00
hoteas
5b407824a5 修复部分bug 2022-11-14 10:38:15 +08:00
hoteas
56f66fcaed 修复部分bug 2022-11-08 16:05:47 +08:00
hoteas
a298cb3d52 修复部分bug 2022-11-07 01:41:22 +08:00
hoteas
68f2c0fd8f 修复部分bug 2022-11-07 01:40:24 +08:00
hoteas
d314891126 修复部分bug 2022-11-06 06:37:44 +08:00
hoteas
c0ae31f499 修复部分bug 2022-11-05 01:55:11 +08:00
hoteas
25edb6b5b7 修复部分bug 2022-11-04 03:22:00 +08:00
hoteas
ead64dc776 修复bug 2022-11-04 02:55:58 +08:00
hoteas
876e3b1f45 优化性能 2022-11-04 02:34:48 +08:00
hoteas
d6e940803d 优化性能 2022-11-04 02:25:33 +08:00
hoteas
203e72f8a2 优化性能 2022-11-04 02:12:07 +08:00
hoteas
541c82410e 修正bug 2022-10-21 04:28:51 +08:00
hoteas
b680112fdb 修正bug 2022-10-20 15:49:49 +08:00
hoteas
4ab5ab9ff4 时间由指针改回对象 2022-10-20 09:08:23 +08:00
hoteas
b425024359 升级流程引擎配置文件版本 2022-10-20 09:00:44 +08:00
hoteas
78337c14ec 升级流程引擎配置文件版本 2022-10-19 21:32:34 +08:00
hoteas
cdba8af129 升级流程引擎配置文件版本 2022-10-19 21:29:38 +08:00
hoteas
9a7426180d 增加单表某字段权限及类型控制功能 2022-10-19 03:37:52 +08:00
hoteas
b7131603c4 增加备注功能 2022-10-08 17:32:37 +08:00
hoteas
2f3a5a0a59 增加壁纸及壁纸地址缓存 2022-10-08 16:52:42 +08:00
hoteas
c2468a7389 增加两个参数 2022-09-16 07:10:45 +08:00
hoteas
b6ba3486d6 IP获取真实条件修改 2022-09-02 00:04:23 +08:00
hoteas
f59e909d30 修复下载插件bug 2022-08-31 19:15:47 +08:00
hoteas
3bb47de45a 修复下载插件bug 2022-08-31 19:10:41 +08:00
hoteas
c71973850e 修复下载插件bug 2022-08-31 19:10:08 +08:00
hoteas
65f062b860 数据库操作bug 2022-08-31 11:20:58 +08:00
hoteas
7b502fed36 数据库操作bug 2022-08-31 11:14:45 +08:00
hoteas
fd6b15bdaf 修正查询bug 2022-08-30 06:21:46 +08:00
hoteas
f31bf24ec2 增加mongodb驱动,简单版本 2022-08-30 04:44:37 +08:00
hoteas
30edb4d9fa 增加mongodb驱动,简单版本 2022-08-30 04:05:17 +08:00
hoteas
a32c3a1589 增加mongodb驱动,简单版本 2022-08-30 03:30:27 +08:00
hoteas
127e027940 修复重复执行context.View()的bug 2022-08-25 14:06:31 +08:00
hoteas
2ee0838d8a 树状结构优化 2022-08-25 13:06:26 +08:00
hoteas
72c23499f2 树状结构优化 2022-08-25 13:02:44 +08:00
hoteas
96d8868694 数据库错误操作优化 2022-08-25 05:01:50 +08:00
hoteas
1533a57cb8 数据库错误操作优化 2022-08-25 03:48:09 +08:00
hoteas
615f52d2e4 数据库错误操作优化 2022-08-25 03:44:58 +08:00
hoteas
f7dfd4ec77 增加记录IP 2022-08-21 03:49:56 +08:00
hoteas
2276aa12ef Merge remote-tracking branch 'origin/master' 2022-08-20 22:38:40 +08:00
hoteas
6505594fd0 增加记录IP 2022-08-20 22:38:15 +08:00
hoteas
c55e26021b 数据库错误操作优化 2022-08-20 11:20:03 +08:00
hoteas
78420a692f 检索升级 2022-08-19 17:58:18 +08:00
hoteas
6d9af149ad 数据库错误操作优化 2022-08-18 13:40:02 +08:00
hoteas
253cad35ef 数据库错误操作优化 2022-08-18 13:28:02 +08:00
hoteas
47c8736f34 数据库错误操作优化 2022-08-18 12:33:01 +08:00
hoteas
dcce8ace9e 数据库事务操作优化 2022-08-18 11:36:23 +08:00
hoteas
125ccc5c3b 数据库操作优化 2022-08-17 17:10:12 +08:00
hoteas
432d59d483 数据库操作优化 2022-08-17 16:42:46 +08:00
hoteas
60f222b011 数据库操作优化 2022-08-17 16:35:52 +08:00
hoteas
7a8b86ed12 数据库操作优化,优化系统管理后台代码生成逻辑 2022-08-17 16:02:36 +08:00
hoteas
b940afa6b0 数据库操作优化 2022-08-15 05:59:06 +08:00
hoteas
8afd00ff86 修复登录bug 2022-08-11 10:41:35 +08:00
hoteas
8992fd6d3a 解决BUG 2022-08-11 10:18:48 +08:00
hoteas
524a892480 修复bug 2022-08-08 04:34:26 +08:00
hoteas
c420e23edb 修复bug 2022-08-08 02:37:15 +08:00
hoteas
7419e03d67 解决bug 2022-08-04 12:14:18 +08:00
hoteas
9425544d1c 修复bug 2022-08-04 02:41:41 +08:00
hoteas
a8d78832df 修复配置bug 2022-08-03 12:07:55 +08:00
hoteas
adfb2236dc V2.0封测 2022-08-02 03:02:57 +08:00
hoteas
6034598bb4 权限管理优化 2022-08-01 18:48:08 +08:00
hoteas
6fe44cb1cb 权限管理优化 2022-08-01 16:45:24 +08:00
hoteas
39d67d1775 增加导出功能 2022-08-01 03:40:09 +08:00
hoteas
a8f9f12bb8 大岗山水电站初版完成 2022-07-28 12:08:47 +08:00
hoteas
2c1abb1d11 大岗山水电站初版完成 2022-07-28 11:08:51 +08:00
hoteas
21e0219568 V2半封测 2022-07-27 17:09:56 +08:00
hoteas
952c3a1243 技术性调整 2022-07-26 17:37:17 +08:00
hoteas
33cd7ebd6b 技术性调整 2022-07-25 05:44:38 +08:00
hoteas
be02b3418d 技术性调整 2022-07-25 05:37:19 +08:00
hoteas
f390617167 技术性调整 2022-07-24 00:00:36 +08:00
hoteas
f7410200e3 增加权限管理 2022-07-21 00:24:39 +08:00
hoteas
9cfdfbac78 增加权限管理 2022-07-18 19:45:06 +08:00
hoteas
b015e78fa0 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	example/config/configNote.json
#	var.go
2022-07-18 19:44:52 +08:00
hoteas
bb9092c3e5 增加权限管理 2022-07-18 19:44:00 +08:00
hoteas
cc1bad8d3f 技术性调整 2022-07-18 08:46:09 +08:00
hoteas
8f7380d796 优化日志及config 2022-07-11 19:13:20 +08:00
hoteas
f37b9aee70 优化日志及config 2022-07-11 11:07:17 +08:00
hoteas
1ab9027c93 技术性调整 2022-07-08 09:55:02 +08:00
hoteas
96d341aaab 修复数据库及时间bug 2022-06-21 00:06:34 +08:00
hoteas
1f25f511cc 增加mysql断线重连优化 2022-06-14 11:29:54 +08:00
hoteas
07c7a628d1 增加time兼容性 2022-06-14 09:52:49 +08:00
hoteas
d7a59845eb 接口层复用 2022-06-09 04:05:50 +08:00
hoteas
98619083a1 接口层复用 2022-06-09 03:54:33 +08:00
hoteas
c8a9038efe 数据库where增加[##]操作 2022-05-27 15:00:44 +08:00
hoteas
b638d8bd65 增加vendor 2022-05-24 13:49:25 +08:00
hoteas
77753a123f 删除example代码 2022-05-19 15:45:51 +08:00
2c9d475a45 导出功能修改关联salesman关联关系 2022-05-18 17:52:49 +08:00
3540209b26 科创券优化 2022-05-17 12:31:47 +08:00
797681d76c 添source_type字段(券的来源:1-vip获得,2-认证获得,3-拉新获得),用来判断券的来源,
userinfo接口返回企业统一社会信用代码和营业执照路径
2022-05-13 18:43:35 +08:00
0ec83f9a95 科服券列表+领券,企业认证,购买vip领券 2022-05-13 15:50:45 +08:00
ec798bd624 科服券列表+领券,企业认证,购买vip领券 2022-05-13 15:45:50 +08:00
6b57201e59 Merge branch 'zct-v2-dengluyang' of https://code.hoteas.com/golang/hotime into zhoupengwei 2022-05-13 15:34:53 +08:00
4e35dfe6ed 科服券列表+领券,企业认证,购买vip领券 2022-05-13 15:34:15 +08:00
hoteas
970bdb0157 增加time类型直接转换 2022-05-13 15:31:55 +08:00
d656faf915 Merge branch 'zct-v2-dengluyang' of https://code.hoteas.com/golang/hotime into zhoupengwei 2022-05-13 09:36:46 +08:00
hoteas
2ecc70288e 打印影响延迟优化 2022-05-13 09:30:09 +08:00
hoteas
ce95cdc021 打印影响延迟优化 2022-05-12 18:27:01 +08:00
22130c7afe vip当日购买信息导出excel的sql调整,添加新字段:用户关联parentid时间,用户关联salesmanid时间 2022-05-11 18:19:30 +08:00
d85c65faef Merge branch 'zct-v2-dengluyang' of https://code.hoteas.com/golang/hotime into zhoupengwei 2022-05-11 18:17:40 +08:00
hoteas
c9f33eefec 打印影响延迟优化 2022-05-11 14:55:28 +08:00
hoteas
1826e76a34 打印影响延迟优化 2022-05-11 13:56:53 +08:00
b9a6b7af22 Merge branch 'zct-v2-dengluyang' of https://code.hoteas.com/golang/hotime into zhoupengwei 2022-05-11 09:51:35 +08:00
hoteas
95bfea4feb 对政策匹配进行优化 2022-05-11 00:44:52 +08:00
e4bb8ac94a vip当日购买信息导出excel 2022-05-10 19:47:20 +08:00
d7a49bf56d vip当日购买信息导出excel 2022-05-10 19:45:00 +08:00
3d1a1670cc Merge branch 'zct-v2-dengluyang' of https://code.hoteas.com/golang/hotime into zhoupengwei 2022-05-10 19:43:36 +08:00
hoteas
7de6a79611 对政策匹配进行优化 2022-05-10 12:54:24 +08:00
83198b39cb Merge branch 'zct-v2-dengluyang' of https://code.hoteas.com/golang/hotime into zhoupengwei
 Conflicts:
	example/app/declare.go
	example/provider/company.go
2022-05-10 09:43:03 +08:00
hoteas
db0724f09b 对政策匹配进行优化 2022-05-09 19:19:15 +08:00
hoteas
c1b013c926 对政策匹配进行优化 2022-05-09 15:07:01 +08:00
40bc84ea3d Merge branch 'zct-v2' of https://code.hoteas.com/golang/hotime into zhoupengwei 2022-05-07 20:56:36 +08:00
e977a97013 Merge pull request '修复 bug 客户管理领域信息没存起来,高层次人才单选的形式存储的' (#1) from liyun into zct-v2
Reviewed-on: #1
2022-05-07 12:55:28 +00:00
michael
9330f7f5ea 修复 bug 客户管理领域信息没存起来,高层次人才单选的形式存储的 2022-05-07 20:47:58 +08:00
d20bcc162c Merge branch 'zct-v2' of https://code.hoteas.com/golang/hotime into zhoupengwei 2022-05-07 17:11:27 +08:00
hoteas
b48ad793da 修正企服商那边不显示名称问题 2022-05-07 13:55:57 +08:00
hoteas
3754734130 临时增加state为1企服商列表不显示企业 2022-05-07 11:08:11 +08:00
hoteas
918b88332b 增加限制条件 2022-05-07 11:02:12 +08:00
hoteas
9ba182d65c 增加限制条件 2022-05-06 13:08:13 +08:00
hoteas
8cf54ce25b 增加限制条件 2022-05-06 11:35:40 +08:00
hoteas
22d00739ff 增加join的orm兼容性 2022-05-05 18:33:27 +08:00
hoteas
3b2a317d2b 增加U盘登录 2022-05-05 16:07:01 +08:00
afa9b173ba Merge branch 'zct-v2' of https://code.hoteas.com/golang/hotime into zhoupengwei 2022-05-05 10:44:10 +08:00
hoteas
53f24c033c 初步版本修正 2022-05-05 00:29:30 +08:00
1ffcaaef8e 只在main.go中加了双//,测试是否能够提交成功 2022-05-04 21:50:52 +08:00
hoteas
62ba00270a 调优 2022-05-03 22:40:02 +08:00
hoteas
fe31335cf5 验证数据 2022-05-03 15:17:27 +08:00
hoteas
b709b58fef 基础整理 2022-05-03 09:41:18 +08:00
hoteas
76b220aa5d 基础整理 2022-05-03 08:09:25 +08:00
hoteas
dbf8f91696 基础整理 2022-05-02 15:42:54 +08:00
hoteas
335e8730da 用户登录 2022-05-02 15:39:50 +08:00
hoteas
cbed318832 科创地图打包 2022-04-29 17:58:14 +08:00
hoteas
31a6568cbe 科创地图打包 2022-04-29 03:08:32 +08:00
hoteas
2aa86361e1 增加普通时间类型,以及增加富文本类型 2022-04-28 14:44:56 +08:00
hoteas
2a21dad90a Merge branch 'zct-wechat' into zct-manage
# Conflicts:
#	example/config/config.json
#	example/main.go
#	example/zct_manage.exe
2022-04-26 09:24:51 +08:00
hoteas
bae9f60012 增加普通时间类型,以及增加富文本类型 2022-04-25 20:08:16 +08:00
hoteas
79d1189803 增加普通时间类型,以及增加富文本类型 2022-04-25 19:58:49 +08:00
hoteas
c3d0c8921b 系统优化 2022-04-22 15:48:17 +08:00
hoteas
1da98a058b 系统优化 2022-04-21 02:20:37 +08:00
hoteas
152386c5a0 系统优化 2022-04-21 02:20:27 +08:00
hoteas
5e2845d3a1 系统优化 2022-04-20 22:49:07 +08:00
hoteas
bab49c9a66 系统优化 2022-04-20 22:47:58 +08:00
hoteas
1d3bfcaee5 系统优化 2022-04-20 18:36:05 +08:00
hoteas
a37a33321f 系统优化 2022-04-18 06:28:01 +08:00
48042ecce4 系统优化 2022-03-29 05:31:02 +08:00
5d8227d8bb 初步完成 2022-03-28 04:52:10 +08:00
38d3d77c59 初步完成 2022-03-28 01:14:09 +08:00
fec195b3a1 框架优化 2022-03-26 16:53:40 +08:00
hoteas
5945ed64c6 框架优化 2022-03-16 09:58:24 +08:00
hoteas
ce515d991a 框架优化 2022-03-14 16:48:19 +08:00
hoteas
cb04dc6c34 框架优化 2022-03-13 17:02:19 +08:00
hoteas
17905c2d21 框架优化 2022-03-13 05:13:32 +08:00
hoteas
b7c243823a 框架优化 2022-03-13 05:06:28 +08:00
hoteas
ebea14c74f Merge remote-tracking branch 'origin/master' into rfcb
# Conflicts:
#	code.go
2022-03-13 02:16:31 +08:00
hoteas
d6ef790010 优化整体 2022-03-13 02:00:40 +08:00
hoteas
5c64580378 优化整体 2022-03-13 01:48:54 +08:00
hoteas
e49164fa81 使用go mod 2022-03-13 01:12:29 +08:00
hoteas
8265e24add 使用go mod 2022-03-13 01:00:59 +08:00
hoteas
283985df52 删除无关代码 2022-03-13 00:26:01 +08:00
hoteas
95adca04bd 删除无关代码 2022-03-13 00:24:36 +08:00
hoteas
2e65138222 hotimego V1.0.1 2022-03-12 23:57:48 +08:00
hoteas
87039524a7 政企超链接开始集成 2022-03-12 23:52:42 +08:00
hoteas
66cd21c35f 政企超链接开始集成 2022-03-12 23:52:25 +08:00
hoteas
7e64131931 政企超链接开始集成 2022-03-06 23:55:14 +08:00
hoteas
e30d40cfbb 政企超链接开始集成 2022-03-04 00:06:26 +08:00
hoteas
751ed0003d 政企超链接开始集成 2022-03-04 00:06:04 +08:00
hoteas
6d9f89a1d4 政企超链接开始集成 2022-03-03 21:23:57 +08:00
hoteas
bc329be03b 政企超链接开始集成 2022-03-02 18:19:15 +08:00
hoteas
4597a0a50d 政企超链接开始集成 2022-03-02 12:14:07 +08:00
hoteas
3dda86d170 政企超链接开始集成 2022-02-28 19:37:52 +08:00
hoteas
d847da7591 政企超链接开始集成 2022-02-28 19:08:48 +08:00
hoteas
e1eca90835 政企超链接开始集成 2022-02-28 09:59:05 +08:00
hoteas
9283b8c284 政企超链接开始集成 2022-02-28 08:53:38 +08:00
hoteas
d8d9afa4d2 政企超链接开始集成 2022-02-24 06:26:36 +08:00
hoteas
4d3829c345 简阳版本 2022-02-19 21:38:35 +08:00
hoteas
a23037a437 简阳版本 2022-02-19 21:38:17 +08:00
hoteas
181295e54e 更新研发 2022-02-17 04:10:53 +08:00
hoteas
8cc2499e21 更新研发 2022-02-14 19:11:38 +08:00
hoteas
a2c49452b4 更新研发 2022-02-14 19:10:58 +08:00
hoteas
ebf0df5ca8 更新研发 2022-01-27 23:41:40 +08:00
hoteas
73bf691ccc 更新研发 2022-01-26 11:45:17 +08:00
hoteas
b2e9701826 更新研发 2022-01-23 05:13:19 +08:00
hoteas
789b0a14d1 更新研发 2022-01-22 16:12:02 +08:00
hoteas
3ee64fcd8c 更新研发 2022-01-20 07:15:14 +08:00
hoteas
527503b0d9 企业画像 2022-01-19 05:38:49 +08:00
hoteas
a95b2fccd7 更新研发 2022-01-17 04:47:39 +08:00
hoteas
7e2abb43e3 权限模块开发 2022-01-12 17:33:20 +08:00
hoteas
48fd753a96 权限模块开发 2022-01-10 13:23:39 +08:00
hoteas
136232dd57 修复太过于严格的bug 2022-01-03 01:42:35 +08:00
hoteas
008f19355c 增加自适应模式 2021-12-31 02:38:51 +08:00
hoteas
1fc0a5bbbc 增加自适应模式 2021-12-30 22:19:52 +08:00
hoteas
ce099b8fc8 增加自适应模式 2021-12-29 00:46:07 +08:00
hoteas
9c00ac6ba1 增加自适应模式 2021-12-28 09:26:26 +08:00
hoteas
a5c002bbce 增加自适应模式 2021-12-27 21:30:33 +08:00
hoteas
cf50a699a6 增加自适应模式 2021-12-27 21:30:24 +08:00
hoteas
662003c0ca 增加自适应模式 2021-12-27 20:40:16 +08:00
hoteas
f24de2562a 优化系统 2021-12-27 18:21:41 +08:00
hoteas
b84bd7e16f 优化系统 2021-12-27 14:09:49 +08:00
hoteas
2fb6abf53a Merge branch 'master' into myhs
# Conflicts:
#	example/admin/init.go
#	example/bzyy.exe
#	example/main.go
2021-12-27 14:02:39 +08:00
hoteas
2eab29f428 优化系统 2021-12-27 14:01:04 +08:00
hoteas
84ee0d259f 优化系统 2021-12-27 14:00:08 +08:00
hoteas
eccab42fc8 优化系统 2021-12-18 00:07:35 +08:00
hoteas
1465ba36d3 优化系统 2021-12-17 14:37:41 +08:00
hoteas
8380b097b2 调试 2021-12-17 01:21:08 +08:00
hoteas
6b8f901163 调试 2021-12-16 13:40:19 +08:00
hoteas
bb16f0a75b 调试 2021-12-16 13:24:31 +08:00
hoteas
84dbc5d71e 出入库完成 2021-12-16 10:49:35 +08:00
hoteas
166eeee64c 出入库完成 2021-12-15 09:24:41 +08:00
hoteas
7a649fd652 出入库完成 2021-12-15 05:56:31 +08:00
hoteas
94ae568526 书写前端接口 2021-12-12 04:22:30 +08:00
hoteas
9ec597f26c 书写前端接口 2021-12-11 23:53:47 +08:00
hoteas
388bc5006d 书写前端代码 2021-12-11 17:59:02 +08:00
hoteas
0e33c2ad9d ocr增加 2021-12-09 11:16:15 +08:00
hoteas
af726fbcfb ocr增加 2021-12-09 10:58:53 +08:00
hoteas
1e82a5964d 优化makecode 2021-11-29 03:27:07 +08:00
hoteas
d62ba8b0cd 优化makecode 2021-11-23 18:31:00 +08:00
hoteas
320ebe25ec 优化makecode 2021-11-18 12:22:14 +08:00
hoteas
68257d1742 绵阳宏升代码优化 2021-11-15 03:35:13 +08:00
hoteas
80d167cb1b 绵阳宏升代码优化 2021-11-15 03:34:45 +08:00
1344 changed files with 673855 additions and 4167 deletions

4
.gitignore vendored
View File

@ -1,2 +1,4 @@
/.idea/*
.idea
.idea
/example/config/app.json
/example/tpt/demo/

0
.tgitconfig Normal file
View File

22
LICENSE
View File

@ -7,17 +7,17 @@ AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution
as defined by Sections 1 through 9 of that document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
@ -26,31 +26,31 @@ or indirect, to cause the direction or management of such entity, whether
by contract or otherwise, or (ii) ownership of fifty percent (50%) or more
of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions
granted by that License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation
or translation of a Source form, including but not limited to compiled object
code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form,
made available under the License, as indicated by a copyright notice that
is included in or attached to the work (an example is provided in the Appendix
below).
"Derivative Works" shall mean any work, whether in Source or Object form,
that is based on (or derived from) the Work and for which the editorial revisions,
@ -59,7 +59,7 @@ original work of authorship. For the purposes of that License, Derivative
Works shall not include works that remain separable from, or merely link (or
bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative
@ -74,7 +74,7 @@ for the purpose of discussing and improving the Work, but excluding communicatio
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently incorporated
@ -142,7 +142,7 @@ any additional terms or conditions. Notwithstanding the above, nothing herein
shall supersede or modify the terms of any separate license agreement you
may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names,
6. Trademarks. that License does not grant permission to use the trade names,
trademarks, service marks, or product names of the Licensor, except as required
for reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.

View File

@ -1,12 +1,13 @@
package hotime
import (
. "./cache"
"./code"
. "./common"
. "./db"
. "./log"
. "code.hoteas.com/golang/hotime/cache"
"code.hoteas.com/golang/hotime/code"
. "code.hoteas.com/golang/hotime/common"
. "code.hoteas.com/golang/hotime/db"
. "code.hoteas.com/golang/hotime/log"
"database/sql"
"fmt"
"github.com/sirupsen/logrus"
"io/ioutil"
"net/http"
@ -19,16 +20,15 @@ import (
)
type Application struct {
*code.MakeCode
MakeCodeRouter map[string]*code.MakeCode
MethodRouter
Router
ContextBase
Error
Log *logrus.Logger
WebConnectLog *logrus.Logger
Port string //端口号
TLSPort string //ssl访问端口号
connectListener []func(this *Context) bool //所有的访问监听,true按原计划继续使用false表示有监听器处理
connectListener []func(that *Context) bool //所有的访问监听,true按原计划继续使用false表示有监听器处理
connectDbFunc func(err ...*Error) (master, slave *sql.DB)
configPath string
Config Map
@ -64,15 +64,37 @@ func (that *Application) Run(router Router) {
//
//}
that.Router = router
//that.Router = router
if that.Router == nil {
that.Router = Router{}
}
for k, _ := range router {
v := router[k]
if that.Router[k] == nil {
that.Router[k] = v
}
//直达接口层复用
for k1, _ := range v {
v1 := v[k1]
if that.Router[k][k1] == nil {
that.Router[k][k1] = v1
}
for k2, _ := range v1 {
v2 := v1[k2]
that.Router[k][k1][k2] = v2
}
}
}
//重新设置MethodRouter//直达路由
that.MethodRouter = MethodRouter{}
modeRouterStrict := true
if that.Config.GetBool("modeRouterStrict") == false {
modeRouterStrict = false
}
if router != nil {
for pk, pv := range router {
if that.Router != nil {
for pk, pv := range that.Router {
if !modeRouterStrict {
pk = strings.ToLower(pk)
}
@ -217,10 +239,8 @@ func (that *Application) SetConfig(configPath ...string) {
}
that.Log = GetLog(that.Config.GetString("logFile"), true)
that.Error = Error{Logger: that.Log}
if that.Config.Get("webConnectLogShow") == nil || that.Config.GetBool("webConnectLogShow") {
that.WebConnectLog = GetLog(that.Config.GetString("webConnectLogFile"), false)
if that.Error.GetError() != nil {
fmt.Println(that.Error.GetError().Error())
}
//文件如果损坏则不写入配置防止配置文件数据丢失
@ -247,19 +267,25 @@ func (that *Application) SetConfig(configPath ...string) {
}
that.Log = GetLog(that.Config.GetString("logFile"), true)
that.Error = Error{Logger: that.Log}
if that.Config.Get("webConnectLogShow") == nil || that.Config.GetBool("webConnectLogShow") {
that.WebConnectLog = GetLog(that.Config.GetString("webConnectLogFile"), false)
}
}
// SetConnectListener 连接判断,返回true继续传输至控制层false则停止传输
func (that *Application) SetConnectListener(lis func(this *Context) bool) {
// SetConnectListener 连接判断,返回false继续传输至控制层true则停止传输
func (that *Application) SetConnectListener(lis func(that *Context) (isFinished bool)) {
that.connectListener = append(that.connectListener, lis)
}
//网络错误
//func (this *Application) session(w http.ResponseWriter, req *http.Request) {
//func (that *Application) session(w http.ResponseWriter, req *http.Request) {
//
//}
//序列化链接
// 序列化链接
func (that *Application) urlSer(url string) (string, []string) {
q := strings.Index(url, "?")
if q == -1 {
@ -294,21 +320,25 @@ func (that *Application) handler(w http.ResponseWriter, req *http.Request) {
// 没有保存就生成随机的session
cookie, err := req.Cookie(that.Config.GetString("sessionName"))
sessionId := Md5(strconv.Itoa(Rand(10)))
token := req.FormValue("token")
needSetCookie := ""
token := req.Header.Get("Authorization")
if len(token) != 32 {
if err != nil || (len(token) == 32 && cookie.Value != token) {
if len(token) == 32 {
sessionId = token
token = req.FormValue("token")
}
//没有cookie或者cookie不等于token
//有token优先token
if len(token) == 32 {
sessionId = token
//没有token则查阅session
if cookie == nil || cookie.Value != sessionId {
needSetCookie = sessionId
}
//没有跨域设置
if that.Config.GetString("crossDomain") == "" {
http.SetCookie(w, &http.Cookie{Name: that.Config.GetString("sessionName"), Value: sessionId, Path: "/"})
} else {
//跨域允许需要设置cookie的允许跨域https才有效果
w.Header().Set("Set-Cookie", that.Config.GetString("sessionName")+"="+sessionId+"; Path=/; SameSite=None; Secure")
}
} else {
} else if err == nil && cookie.Value != "" {
sessionId = cookie.Value
//session也没有则判断是否创建cookie
} else {
needSetCookie = sessionId
}
unescapeUrl, err := url.QueryUnescape(req.RequestURI)
@ -327,20 +357,25 @@ func (that *Application) handler(w http.ResponseWriter, req *http.Request) {
context.HandlerStr, context.RouterString = that.urlSer(context.HandlerStr)
//跨域设置
that.crossDomain(&context)
that.crossDomain(&context, needSetCookie)
defer func() {
//是否展示日志
if that.WebConnectLog != nil {
ipStr := Substr(context.Req.RemoteAddr, 0, strings.Index(context.Req.RemoteAddr, ":"))
//负载均衡优化
if ipStr == "127.0.0.1" {
if req.Header.Get("X-Forwarded-For") != "" {
ipStr = req.Header.Get("X-Forwarded-For")
} else if req.Header.Get("X-Real-IP") != "" {
ipStr = req.Header.Get("X-Real-IP")
}
ipStr := ""
if req.Header.Get("X-Forwarded-For") != "" {
ipStr = req.Header.Get("X-Forwarded-For")
} else if req.Header.Get("X-Real-IP") != "" {
ipStr = req.Header.Get("X-Real-IP")
}
//负载均衡优化
if ipStr == "" {
//RemoteAddr := that.Req.RemoteAddr
ipStr = Substr(context.Req.RemoteAddr, 0, strings.Index(context.Req.RemoteAddr, ":"))
}
that.WebConnectLog.Infoln(ipStr, context.Req.Method,
"time cost:", ObjToFloat64(time.Now().UnixNano()-nowUnixTime.UnixNano())/1000000.00, "ms",
"data length:", ObjToFloat64(context.DataSize)/1000.00, "KB", context.HandlerStr)
@ -348,16 +383,17 @@ func (that *Application) handler(w http.ResponseWriter, req *http.Request) {
}()
//访问拦截true继续false暂停
connectListenerLen := len(that.connectListener)
if connectListenerLen != 0 {
for i := 0; i < connectListenerLen; i++ {
connectListenerLen := len(that.connectListener) - 1
if !that.connectListener[i](&context) {
context.View()
return
}
for true {
if connectListenerLen < 0 {
break
}
if that.connectListener[connectListenerLen](&context) {
context.View()
return
}
connectListenerLen--
}
//接口服务
@ -410,8 +446,14 @@ func (that *Application) handler(w http.ResponseWriter, req *http.Request) {
header.Set("Cache-Control", "no-cache")
}
if strings.Index(path, ".m3u8") != -1 {
header.Add("Content-Type", "audio/mpegurl")
t := strings.LastIndex(path, ".")
if t != -1 {
tt := path[t:]
if MimeMaps[tt] != "" {
header.Add("Content-Type", MimeMaps[tt])
}
}
//w.Write(data)
@ -419,35 +461,68 @@ func (that *Application) handler(w http.ResponseWriter, req *http.Request) {
}
func (that *Application) crossDomain(context *Context) {
func (that *Application) crossDomain(context *Context, sessionId string) {
//没有跨域设置
if context.Config.GetString("crossDomain") == "" {
if sessionId != "" {
http.SetCookie(context.Resp, &http.Cookie{Name: that.Config.GetString("sessionName"), Value: sessionId, Path: "/"})
//context.Resp.Header().Set("Set-Cookie", that.Config.GetString("sessionName")+"="+sessionId+"; Path=/; SameSite=None; Secure")
}
return
}
header := context.Resp.Header()
//header.Set("Access-Control-Allow-Origin", "*")
header.Set("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE")
header.Set("Access-Control-Allow-Credentials", "true")
header.Set("Access-Control-Expose-Headers", "*")
header.Set("Access-Control-Allow-Headers", "X-Requested-With,Content-Type,Access-Token")
//不跨域,则不设置
remoteHost := context.Req.Host
if context.Config.GetString("port") == "80" || context.Config.GetString("port") == "443" {
remoteHost = remoteHost + ":" + context.Config.GetString("port")
}
if context.Config.GetString("crossDomain") != "auto" {
//不跨域,则不设置
if strings.Contains(context.Config.GetString("crossDomain"), remoteHost) {
if sessionId != "" {
http.SetCookie(context.Resp, &http.Cookie{Name: that.Config.GetString("sessionName"), Value: sessionId, Path: "/"})
}
return
}
header.Set("Access-Control-Allow-Origin", that.Config.GetString("crossDomain"))
// 后端设置2592000单位秒这里是30天
header.Set("Access-Control-Max-Age", "2592000")
//header.Set("Access-Control-Allow-Origin", "*")
header.Set("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE")
header.Set("Access-Control-Allow-Credentials", "true")
header.Set("Access-Control-Expose-Headers", "*")
header.Set("Access-Control-Allow-Headers", "X-Requested-With,Content-Type,Access-Token,Authorization,Cookie,Set-Cookie")
if sessionId != "" {
//跨域允许需要设置cookie的允许跨域https才有效果
context.Resp.Header().Set("Set-Cookie", that.Config.GetString("sessionName")+"="+sessionId+"; Path=/; SameSite=None; Secure")
}
return
}
origin := context.Req.Header.Get("Origin")
if origin != "" {
header.Set("Access-Control-Allow-Origin", origin)
refer := context.Req.Header.Get("Referer")
if (origin != "" && strings.Contains(origin, remoteHost)) || strings.Contains(refer, remoteHost) {
if sessionId != "" {
//http.SetCookie(context.Resp, &http.Cookie{Name: that.Config.GetString("sessionName"), Value: sessionId, Path: "/"})
context.Resp.Header().Set("Set-Cookie", that.Config.GetString("sessionName")+"="+sessionId+"; Path=/; SameSite=None; Secure")
}
return
}
refer := context.Req.Header.Get("Referer")
if refer != "" {
if origin != "" {
header.Set("Access-Control-Allow-Origin", origin)
//return
} else if refer != "" {
tempInt := 0
lastInt := strings.IndexFunc(refer, func(r rune) bool {
if r == '/' && tempInt > 8 {
@ -462,31 +537,88 @@ func (that *Application) crossDomain(context *Context) {
}
refer = Substr(refer, 0, lastInt)
header.Set("Access-Control-Allow-Origin", refer)
//header.Set("Access-Control-Allow-Origin", "*")
}
header.Set("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE")
header.Set("Access-Control-Allow-Credentials", "true")
header.Set("Access-Control-Expose-Headers", "*")
header.Set("Access-Control-Allow-Headers", "X-Requested-With,Content-Type,Access-Token,Authorization,Cookie,Set-Cookie")
if sessionId != "" {
//跨域允许需要设置cookie的允许跨域https才有效果
context.Resp.Header().Set("Set-Cookie", that.Config.GetString("sessionName")+"="+sessionId+"; Path=/; SameSite=None; Secure")
}
}
//Init 初始化application
func Init(config string) Application {
// Init 初始化application
func Init(config string) *Application {
appIns := Application{}
//手动模式,
appIns.SetConfig(config)
SetDB(&appIns)
appIns.SetCache()
appIns.MakeCode = &code.MakeCode{}
codeConfig := appIns.Config.GetMap("codeConfig")
codeConfig := appIns.Config.GetSlice("codeConfig")
if codeConfig != nil {
for k, _ := range codeConfig {
if appIns.Config.GetInt("mode") == 2 {
appIns.MakeCode.Db2JSON(k, codeConfig.GetString(k), &appIns.Db)
} else {
appIns.MakeCode.Db2JSON(k, codeConfig.GetString(k), nil)
codeMake := codeConfig.GetMap(k)
if codeMake == nil {
continue
}
//codeMake["table"] = k
if appIns.MakeCodeRouter == nil {
appIns.MakeCodeRouter = map[string]*code.MakeCode{}
}
if codeMake.GetString("name") == "" {
codeMake["name"] = codeMake.GetString("table")
}
appIns.MakeCodeRouter[codeMake.GetString("name")] = &code.MakeCode{Error: appIns.Error}
appIns.MakeCodeRouter[codeMake.GetString("name")].Db2JSON(&appIns.Db, codeMake)
//接入动态代码层
if appIns.Router == nil {
appIns.Router = Router{}
}
//appIns.Router[codeMake.GetString("name")] = TptProject
appIns.Router[codeMake.GetString("name")] = Proj{}
for k2, _ := range TptProject {
if appIns.Router[codeMake.GetString("name")][k2] == nil {
appIns.Router[codeMake.GetString("name")][k2] = Ctr{}
}
for k3, _ := range TptProject[k2] {
v3 := TptProject[k2][k3]
appIns.Router[codeMake.GetString("name")][k2][k3] = v3
}
}
for k1, _ := range appIns.MakeCodeRouter[codeMake.GetString("name")].TableColumns {
if appIns.Router[codeMake.GetString("name")][k1] == nil {
appIns.Router[codeMake.GetString("name")][k1] = Ctr{}
}
for k2, _ := range appIns.Router[codeMake.GetString("name")]["hotimeCommon"] {
//golang毛病
v2 := appIns.Router[codeMake.GetString("name")]["hotimeCommon"][k2]
appIns.Router[codeMake.GetString("name")][k1][k2] = v2
}
}
setMakeCodeListener(codeMake.GetString("name"), &appIns)
}
}
return appIns
return &appIns
}
// SetDB 智能数据库设置
@ -506,6 +638,8 @@ func SetMysqlDB(appIns *Application, config Map) {
appIns.Db.Type = "mysql"
appIns.Db.DBName = config.GetString("name")
appIns.Db.Prefix = config.GetString("prefix")
appIns.Db.Log = appIns.Log
appIns.Db.Mode = appIns.Config.GetCeilInt("mode")
appIns.SetConnectDB(func(err ...*Error) (master, slave *sql.DB) {
//master数据库配置
query := config.GetString("user") + ":" + config.GetString("password") +
@ -535,6 +669,8 @@ func SetSqliteDB(appIns *Application, config Map) {
appIns.Db.Type = "sqlite"
appIns.Db.Prefix = config.GetString("prefix")
appIns.Db.Mode = appIns.Config.GetCeilInt("mode")
appIns.Db.Log = appIns.Log
appIns.SetConnectDB(func(err ...*Error) (master, slave *sql.DB) {
db, e := sql.Open("sqlite3", config.GetString("path"))
if e != nil && len(err) != 0 {
@ -545,3 +681,114 @@ func SetSqliteDB(appIns *Application, config Map) {
return master, slave
})
}
func setMakeCodeListener(name string, appIns *Application) {
appIns.SetConnectListener(func(context *Context) (isFinished bool) {
codeIns := appIns.MakeCodeRouter[name]
if len(context.RouterString) < 2 || appIns.MakeCodeRouter[context.RouterString[0]] == nil {
return isFinished
}
if len(context.RouterString) > 1 && context.RouterString[0] == name {
if context.RouterString[1] == "hotime" && context.RouterString[2] == "login" {
return isFinished
}
if context.RouterString[1] == "hotime" && context.RouterString[2] == "logout" {
return isFinished
}
if context.RouterString[1] == "hotime" && context.RouterString[2] == "config" {
return isFinished
}
if context.RouterString[1] == "hotime" && context.RouterString[2] == "wallpaper" {
return isFinished
}
if context.Session(codeIns.FileConfig.GetString("table")+"_id").Data == nil {
context.Display(2, "你还没有登录")
return true
}
}
if len(context.RouterString) < 2 || len(context.RouterString) > 3 ||
!(context.Router[context.RouterString[0]] != nil &&
context.Router[context.RouterString[0]][context.RouterString[1]] != nil) {
return isFinished
}
//排除无效操作
if len(context.RouterString) == 2 &&
context.Req.Method != "GET" &&
context.Req.Method != "POST" {
return isFinished
}
//排除已有接口的无效操作
if len(context.RouterString) == 3 && context.Router[context.RouterString[0]] != nil && context.Router[context.RouterString[0]][context.RouterString[1]] != nil && context.Router[context.RouterString[0]][context.RouterString[1]][context.RouterString[2]] != nil {
return isFinished
}
//列表检索
if len(context.RouterString) == 2 &&
context.Req.Method == "GET" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["search"] == nil {
return isFinished
}
context.Router[context.RouterString[0]][context.RouterString[1]]["search"](context)
}
//新建
if len(context.RouterString) == 2 &&
context.Req.Method == "POST" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["add"] == nil {
return true
}
context.Router[context.RouterString[0]][context.RouterString[1]]["add"](context)
}
if len(context.RouterString) == 3 &&
context.Req.Method == "POST" {
return isFinished
}
//分析
if len(context.RouterString) == 3 && context.RouterString[2] == "analyse" &&
context.Req.Method == "GET" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["analyse"] == nil {
return isFinished
}
context.Router[context.RouterString[0]][context.RouterString[1]]["analyse"](context)
}
//查询单条
if len(context.RouterString) == 3 &&
context.Req.Method == "GET" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["info"] == nil {
return isFinished
}
context.Router[context.RouterString[0]][context.RouterString[1]]["info"](context)
}
//更新
if len(context.RouterString) == 3 &&
context.Req.Method == "PUT" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["update"] == nil {
return true
}
context.Router[context.RouterString[0]][context.RouterString[1]]["update"](context)
}
//移除
if len(context.RouterString) == 3 &&
context.Req.Method == "DELETE" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["remove"] == nil {
return true
}
context.Router[context.RouterString[0]][context.RouterString[1]]["remove"](context)
}
//context.View()
return true
})
}

2
cache/cache.go vendored
View File

@ -1,7 +1,7 @@
package cache
import (
. "../common"
. "code.hoteas.com/golang/hotime/common"
"errors"
)

28
cache/cache_db.go vendored
View File

@ -1,7 +1,7 @@
package cache
import (
. "../common"
. "code.hoteas.com/golang/hotime/common"
"database/sql"
"encoding/json"
"strings"
@ -30,14 +30,14 @@ type CacheDb struct {
isInit bool
}
func (this *CacheDb) GetError() *Error {
func (that *CacheDb) GetError() *Error {
return this.Error
return that.Error
}
func (this *CacheDb) SetError(err *Error) {
this.Error = err
func (that *CacheDb) SetError(err *Error) {
that.Error = err
}
func (that *CacheDb) initDbTable() {
@ -58,7 +58,7 @@ func (that *CacheDb) initDbTable() {
return
}
_, e := that.Db.Exec("CREATE TABLE `" + that.Db.GetPrefix() + "cached` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `ckey` varchar(60) DEFAULT NULL, `cvalue` varchar(2000) DEFAULT NULL, `time` bigint(20) DEFAULT NULL, `endtime` bigint(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=198740 DEFAULT CHARSET=utf8")
_, e := that.Db.Exec("CREATE TABLE `" + that.Db.GetPrefix() + "cached` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `key` varchar(60) DEFAULT NULL, `value` varchar(2000) DEFAULT NULL, `time` bigint(20) DEFAULT NULL, `endtime` bigint(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=198740 DEFAULT CHARSET=utf8")
if e.GetError() == nil {
that.isInit = true
}
@ -74,8 +74,8 @@ func (that *CacheDb) initDbTable() {
}
_, e := that.Db.Exec(`CREATE TABLE "` + that.Db.GetPrefix() + `cached" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"ckey" TEXT(60),
"cvalue" TEXT(2000),
"key" TEXT(60),
"value" TEXT(2000),
"time" integer,
"endtime" integer
);`)
@ -90,7 +90,7 @@ func (that *CacheDb) initDbTable() {
//获取Cache键只能为string类型
func (that *CacheDb) get(key string) interface{} {
cached := that.Db.Get("cached", "*", Map{"ckey": key})
cached := that.Db.Get("cached", "*", Map{"key": key})
if cached == nil {
return nil
@ -103,7 +103,7 @@ func (that *CacheDb) get(key string) interface{} {
}
data := Map{}
data.JsonToMap(cached.GetString("cvalue"))
data.JsonToMap(cached.GetString("value"))
return data.Get("data")
}
@ -113,9 +113,9 @@ func (that *CacheDb) set(key string, value interface{}, tim int64) {
bte, _ := json.Marshal(Map{"data": value})
num := that.Db.Update("cached", Map{"cvalue": string(bte), "time": time.Now().UnixNano(), "endtime": tim}, Map{"ckey": key})
num := that.Db.Update("cached", Map{"value": string(bte), "time": time.Now().UnixNano(), "endtime": tim}, Map{"key": key})
if num == int64(0) {
that.Db.Insert("cached", Map{"cvalue": string(bte), "time": time.Now().UnixNano(), "endtime": tim, "ckey": key})
that.Db.Insert("cached", Map{"value": string(bte), "time": time.Now().UnixNano(), "endtime": tim, "key": key})
}
//随机执行删除命令
@ -130,10 +130,10 @@ func (that *CacheDb) delete(key string) {
//如果通配删除
if del != -1 {
key = Substr(key, 0, del)
that.Db.Delete("cached", Map{"ckey": key + "%"})
that.Db.Delete("cached", Map{"key": key + "%"})
} else {
that.Db.Delete("cached", Map{"ckey": key})
that.Db.Delete("cached", Map{"key": key})
}
}

183
cache/cache_memory.go vendored
View File

@ -1,158 +1,115 @@
package cache
import (
. "../common"
. "code.hoteas.com/golang/hotime/common"
"strings"
"sync"
"time"
)
// CacheMemory 基于 sync.Map 的缓存实现
type CacheMemory struct {
TimeOut int64
DbSet bool
SessionSet bool
Map
*Error
ContextBase
mutex *sync.RWMutex
cache sync.Map // 替代传统的 Map
}
func (this *CacheMemory) GetError() *Error {
func (that *CacheMemory) GetError() *Error {
return this.Error
return that.Error
}
func (this *CacheMemory) SetError(err *Error) {
this.Error = err
func (that *CacheMemory) SetError(err *Error) {
that.Error = err
}
func (c *CacheMemory) get(key string) (res *Obj) {
//获取Cache键只能为string类型
func (this *CacheMemory) get(key string) interface{} {
this.Error.SetError(nil)
if this.Map == nil {
this.Map = Map{}
res = &Obj{
Error: *c.Error,
}
value, ok := c.cache.Load(key)
if !ok {
return res // 缓存不存在
}
if this.Map[key] == nil {
return nil
}
data := this.Map.Get(key, this.Error).(cacheData)
if this.Error.GetError() != nil {
return nil
}
data := value.(cacheData)
// 检查是否过期
if data.time < time.Now().Unix() {
delete(this.Map, key)
return nil
c.cache.Delete(key) // 删除过期缓存
return res
}
return data.data
res.Data = data.data
return res
}
func (this *CacheMemory) refreshMap() {
func (c *CacheMemory) set(key string, value interface{}, expireAt int64) {
data := cacheData{
data: value,
time: expireAt,
}
c.cache.Store(key, data)
}
func (c *CacheMemory) delete(key string) {
if strings.Contains(key, "*") {
// 通配符删除
prefix := strings.TrimSuffix(key, "*")
c.cache.Range(func(k, v interface{}) bool {
if strings.HasPrefix(k.(string), prefix) {
c.cache.Delete(k)
}
return true
})
} else {
// 精确删除
c.cache.Delete(key)
}
}
func (c *CacheMemory) refreshMap() {
go func() {
this.mutex.Lock()
defer this.mutex.Unlock()
for key, v := range this.Map {
data := v.(cacheData)
if data.time <= time.Now().Unix() {
delete(this.Map, key)
now := time.Now().Unix()
c.cache.Range(func(key, value interface{}) bool {
data := value.(cacheData)
if data.time <= now {
c.cache.Delete(key) // 删除过期缓存
}
}
return true
})
}()
}
func (c *CacheMemory) Cache(key string, data ...interface{}) *Obj {
now := time.Now().Unix()
//key value ,时间为时间戳
func (this *CacheMemory) set(key string, value interface{}, time int64) {
this.Error.SetError(nil)
var data cacheData
if this.Map == nil {
this.Map = Map{}
// 随机触发刷新
if x := RandX(1, 100000); x > 99950 {
c.refreshMap()
}
dd := this.Map[key]
if dd == nil {
data = cacheData{}
} else {
data = dd.(cacheData)
}
data.time = time
data.data = value
this.Map.Put(key, data)
}
func (this *CacheMemory) delete(key string) {
del := strings.Index(key, "*")
//如果通配删除
if del != -1 {
key = Substr(key, 0, del)
for k, _ := range this.Map {
if strings.Index(k, key) != -1 {
delete(this.Map, k)
}
}
} else {
delete(this.Map, key)
}
}
func (this *CacheMemory) Cache(key string, data ...interface{}) *Obj {
x := RandX(1, 100000)
if x > 99950 {
this.refreshMap()
}
if this.mutex == nil {
this.mutex = &sync.RWMutex{}
}
reData := &Obj{Data: nil}
if len(data) == 0 {
this.mutex.RLock()
reData.Data = this.get(key)
this.mutex.RUnlock()
return reData
// 读操作
return c.get(key)
}
tim := time.Now().Unix()
if len(data) == 1 && data[0] == nil {
this.mutex.Lock()
this.delete(key)
this.mutex.Unlock()
return reData
// 删除操作
c.delete(key)
return nil
}
if len(data) == 1 {
tim = tim + this.TimeOut
}
// 写操作
expireAt := now + c.TimeOut
if len(data) == 2 {
this.Error.SetError(nil)
tempt := ObjToInt64(data[1], this.Error)
if tempt > tim {
tim = tempt
} else if this.Error.GetError() == nil {
tim = tim + tempt
if customExpire, ok := data[1].(int64); ok {
if customExpire > now {
expireAt = customExpire
} else {
expireAt = now + customExpire
}
}
}
this.mutex.Lock()
this.set(key, data[0], tim)
this.mutex.Unlock()
return reData
c.set(key, data[0], expireAt)
return nil
}

102
cache/cache_redis.go vendored
View File

@ -1,7 +1,7 @@
package cache
import (
. "../common"
. "code.hoteas.com/golang/hotime/common"
"github.com/garyburd/redigo/redis"
"strings"
"time"
@ -20,65 +20,65 @@ type CacheRedis struct {
*Error
}
func (this *CacheRedis) GetError() *Error {
func (that *CacheRedis) GetError() *Error {
return this.Error
return that.Error
}
func (this *CacheRedis) SetError(err *Error) {
this.Error = err
func (that *CacheRedis) SetError(err *Error) {
that.Error = err
}
//唯一标志
func (this *CacheRedis) GetTag() int64 {
func (that *CacheRedis) GetTag() int64 {
if this.tag == int64(0) {
this.tag = time.Now().UnixNano()
if that.tag == int64(0) {
that.tag = time.Now().UnixNano()
}
return this.tag
return that.tag
}
func (this *CacheRedis) reCon() bool {
func (that *CacheRedis) reCon() bool {
var err error
this.conn, err = redis.Dial("tcp", this.Host+":"+ObjToStr(this.Port))
that.conn, err = redis.Dial("tcp", that.Host+":"+ObjToStr(that.Port))
if err != nil {
this.conn = nil
this.Error.SetError(err)
that.conn = nil
that.Error.SetError(err)
return false
}
if this.Pwd != "" {
_, err = this.conn.Do("AUTH", this.Pwd)
if that.Pwd != "" {
_, err = that.conn.Do("AUTH", that.Pwd)
if err != nil {
this.conn = nil
this.Error.SetError(err)
that.conn = nil
that.Error.SetError(err)
return false
}
}
return true
}
func (this *CacheRedis) del(key string) {
func (that *CacheRedis) del(key string) {
del := strings.Index(key, "*")
if del != -1 {
val, err := redis.Strings(this.conn.Do("KEYS", key))
val, err := redis.Strings(that.conn.Do("KEYS", key))
if err != nil {
return
}
this.conn.Send("MULTI")
that.conn.Send("MULTI")
for i, _ := range val {
this.conn.Send("DEL", val[i])
that.conn.Send("DEL", val[i])
}
this.conn.Do("EXEC")
that.conn.Do("EXEC")
} else {
_, err := this.conn.Do("DEL", key)
_, err := that.conn.Do("DEL", key)
if err != nil {
this.Error.SetError(err)
_, err = this.conn.Do("PING")
that.Error.SetError(err)
_, err = that.conn.Do("PING")
if err != nil {
if this.reCon() {
_, err = this.conn.Do("DEL", key)
if that.reCon() {
_, err = that.conn.Do("DEL", key)
}
}
}
@ -86,32 +86,32 @@ func (this *CacheRedis) del(key string) {
}
//key value ,时间为时间戳
func (this *CacheRedis) set(key string, value string, time int64) {
_, err := this.conn.Do("SET", key, value, "EX", ObjToStr(time))
func (that *CacheRedis) set(key string, value string, time int64) {
_, err := that.conn.Do("SET", key, value, "EX", ObjToStr(time))
if err != nil {
this.Error.SetError(err)
_, err = this.conn.Do("PING")
that.Error.SetError(err)
_, err = that.conn.Do("PING")
if err != nil {
if this.reCon() {
_, err = this.conn.Do("SET", key, value, "EX", ObjToStr(time))
if that.reCon() {
_, err = that.conn.Do("SET", key, value, "EX", ObjToStr(time))
}
}
}
}
func (this *CacheRedis) get(key string) *Obj {
func (that *CacheRedis) get(key string) *Obj {
reData := &Obj{}
var err error
reData.Data, err = redis.String(this.conn.Do("GET", key))
reData.Data, err = redis.String(that.conn.Do("GET", key))
if err != nil {
reData.Data = nil
if !strings.Contains(err.Error(), "nil returned") {
this.Error.SetError(err)
_, err = this.conn.Do("PING")
that.Error.SetError(err)
_, err = that.conn.Do("PING")
if err != nil {
if this.reCon() {
reData.Data, err = redis.String(this.conn.Do("GET", key))
if that.reCon() {
reData.Data, err = redis.String(that.conn.Do("GET", key))
}
}
@ -121,10 +121,10 @@ func (this *CacheRedis) get(key string) *Obj {
return reData
}
func (this *CacheRedis) Cache(key string, data ...interface{}) *Obj {
func (that *CacheRedis) Cache(key string, data ...interface{}) *Obj {
reData := &Obj{}
if this.conn == nil {
re := this.reCon()
if that.conn == nil {
re := that.reCon()
if !re {
return reData
}
@ -132,38 +132,38 @@ func (this *CacheRedis) Cache(key string, data ...interface{}) *Obj {
//查询缓存
if len(data) == 0 {
reData = this.get(key)
reData = that.get(key)
return reData
}
tim := int64(0)
//删除缓存
if len(data) == 1 && data[0] == nil {
this.del(key)
that.del(key)
return reData
}
//添加缓存
if len(data) == 1 {
if this.TimeOut == 0 {
//this.Time = Config.GetInt64("cacheShortTime")
if that.TimeOut == 0 {
//that.Time = Config.GetInt64("cacheShortTime")
}
tim += this.TimeOut
tim += that.TimeOut
}
if len(data) == 2 {
this.Error.SetError(nil)
tempt := ObjToInt64(data[1], this.Error)
that.Error.SetError(nil)
tempt := ObjToInt64(data[1], that.Error)
if tempt > tim {
tim = tempt
} else if this.GetError() == nil {
} else if that.GetError() == nil {
tim = tim + tempt
}
}
this.set(key, ObjToStr(data[0]), tim)
that.set(key, ObjToStr(data[0]), tim)
return reData

2
cache/type.go vendored
View File

@ -1,7 +1,7 @@
package cache
import (
. "../common"
. "code.hoteas.com/golang/hotime/common"
)
type CacheIns interface {

1260
code.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,34 @@
package code
import (
. "../common"
. "code.hoteas.com/golang/hotime/common"
)
var Config = Map{
"name": "HoTimeDashBoard",
"id": "2f92h3herh23rh2y8",
"name": "HoTimeDashBoard",
//"id": "2f92h3herh23rh2y8",
"label": "HoTime管理平台",
"stop": Slice{"role", "org"}, //不更新的,同时不允许修改用户自身对应的表数据
"labelConfig": Map{
"show": "开启",
"add": "添加",
"delete": "删除",
"edit": "编辑",
"info": "查看详情",
"download": "下载清单",
},
"menus": []Map{
{"label": "平台首页", "name": "HelloWorld", "icon": "el-icon-s-home"},
//{"label": "平台首页", "name": "HelloWorld", "icon": "el-icon-s-home"},
//{"label": "测试表格", "table": "table", "icon": "el-icon-suitcase"},
//{"label": "系统管理", "name": "setting", "icon": "el-icon-setting",
// "menus": []Map{
// {"label": "用户管理", "table": "user"},
// {"label": "用户管理", "table": "user",
// "default": {
// "path": "info",
// "id": "1"
// },
// "auth": ["show","edit","info","add","delete"],
// },
// {"label": "组织管理", "table": "organization"},
// {"label": "地区管理", "table": "area"},
// {"label": "角色管理", "table": "role"},
@ -34,6 +48,7 @@ var ColumnDataType = map[string]string{
"float": "number",
"double": "number",
"decimal": "number",
"integer": "number", //sqlite3
"char": "text",
"text": "text",
"blob": "text",
@ -44,53 +59,130 @@ var ColumnDataType = map[string]string{
}
type ColumnShow struct {
Name string
List bool
Edit bool
Info bool
Must bool
Name string //名称
List bool //列表权限
Edit bool //新增和编辑权限
Info bool //详情权限
Must bool //字段全匹配
Type string //空字符串表示
Strict bool //name严格匹配必须是这个词才行
}
var ColumnNameType = []ColumnShow{
//通用
{"idcard", false, true, true, false, "", false},
{"id", true, false, true, false, "", true},
{"parent_id", true, true, true, false, "", true},
//"sn"{true,true,true,""},
{"status", true, true, true, false, "select", false},
{"state", false, true, true, false, "select", false},
{"sex", true, true, true, false, "select", false},
{"delete", false, false, false, false, "", false},
var RuleConfig = []Map{
{"name": "idcard", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "id", "add": false, "list": true, "edit": false, "info": true, "must": false, "strict": true, "type": ""},
{"name": "sn", "add": false, "list": true, "edit": false, "info": true, "must": false, "strict": false, "type": ""},
{"name": "parent_ids", "add": false, "list": false, "edit": false, "info": false, "must": false, "strict": true, "type": "index"},
{"name": "index", "add": false, "list": false, "edit": false, "info": false, "must": false, "strict": true, "type": "index"},
{"lat", false, true, true, false, "", false},
{"lng", false, true, true, false, "", false},
{"latitude", false, true, true, false, "", false},
{"longitude", false, true, true, false, "", false},
{"name": "parent_id", "add": true, "list": true, "edit": true, "info": true, "must": false, "true": false, "type": ""},
{"index", false, false, false, false, "index", false},
{"password", false, true, false, false, "password", false},
{"pwd", false, true, false, false, "password", false},
{"info", false, true, true, false, "", false},
{"version", false, false, false, false, "", false},
{"seq", false, true, true, false, "", false},
{"sort", false, true, true, false, "", false},
{"note", false, true, true, false, "", false},
{"description", false, true, true, false, "", false},
{"abstract", false, true, true, false, "", false},
{"content", false, true, true, false, "", false},
{"address", false, true, true, false, "", false},
{"full_name", false, true, true, false, "", false},
{"create_time", false, false, true, false, "time", true},
{"modify_time", true, false, true, false, "time", true},
{"image", false, true, true, false, "image", false},
{"img", false, true, true, false, "image", false},
{"icon", false, true, true, false, "image", false},
{"avatar", false, true, true, false, "image", false},
{"file", false, true, true, false, "file", false},
{"age", false, true, true, false, "", false},
{"email", false, true, true, false, "", false},
{"time", true, false, true, false, "time", false},
{"level", false, false, true, false, "", false},
{"name": "amount", "add": true, "list": true, "edit": true, "info": true, "must": false, "strict": true, "type": "money"},
{"name": "info", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": "textArea"},
{"name": "status", "add": true, "list": true, "edit": true, "info": true, "must": false, "strict": false, "type": "select"},
{"name": "state", "add": true, "list": true, "edit": true, "info": true, "must": false, "strict": false, "type": "select"},
{"name": "sex", "add": true, "list": true, "edit": true, "info": true, "must": false, "strict": false, "type": "select"},
{"name": "delete", "add": false, "list": false, "edit": false, "info": false, "must": false, "strict": false, "type": ""},
{"name": "lat", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "lng", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "latitude", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "longitude", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "password", "add": true, "list": false, "edit": true, "info": false, "must": false, "strict": false, "type": "password"},
{"name": "pwd", "add": true, "list": false, "edit": true, "info": false, "must": false, "strict": false, "type": "password"},
{"name": "version", "add": false, "list": false, "edit": false, "info": false, "must": false, "strict": false, "type": ""},
{"name": "seq", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "sort", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "note", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "description", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "abstract", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "content", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": "textArea"},
{"name": "address", "add": true, "list": true, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "full_name", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "create_time", "add": false, "list": false, "edit": false, "info": true, "must": false, "strict": true, "type": "time"},
{"name": "modify_time", "add": false, "list": true, "edit": false, "info": true, "must": false, "strict": true, "type": "time"},
{"name": "image", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": "image"},
{"name": "img", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": "image"},
{"name": "avatar", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": "image"},
{"name": "icon", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": "image"},
{"name": "file", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": "file"},
{"name": "age", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "email", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": ""},
{"name": "time", "add": true, "list": true, "edit": true, "info": true, "must": false, "strict": false, "type": "time"},
{"name": "level", "add": false, "list": false, "edit": false, "info": true, "must": false, "strict": false, "type": ""},
{"name": "rule", "add": true, "list": true, "edit": true, "info": true, "must": false, "strict": false, "type": "form"},
{"name": "auth", "add": true, "list": false, "edit": true, "info": true, "must": false, "strict": false, "type": "auth"},
{"name": "table", "add": false, "list": true, "edit": false, "info": true, "must": false, "strict": false, "type": "table"},
{"name": "table_id", "add": false, "list": true, "edit": false, "info": true, "must": false, "strict": false, "type": "table_id"},
}
//var ColumnNameType = []ColumnShow{
// //通用
// {"idcard", false, true, true, false, "", false},
// {"id", true, false, true, false, "", true},
// {"sn", true, false, true, false, "", false},
// {"parent_ids", false, false, false, false, "index", true},
// {"parent_id", true, true, true, false, "", true},
// {"amount", true, true, true, false, "money", true},
// {"info", false, true, true, false, "textArea", false},
// //"sn"{true,true,true,""},
// {"status", true, true, true, false, "select", false},
// {"state", true, true, true, false, "select", false},
// {"sex", true, true, true, false, "select", false},
// {"delete", false, false, false, false, "", false},
//
// {"lat", false, true, true, false, "", false},
// {"lng", false, true, true, false, "", false},
// {"latitude", false, true, true, false, "", false},
// {"longitude", false, true, true, false, "", false},
//
// {"index", false, false, false, false, "index", false},
//
// {"password", false, true, false, false, "password", false},
// {"pwd", false, true, false, false, "password", false},
//
// {"version", false, false, false, false, "", false},
// {"seq", false, true, true, false, "", false},
// {"sort", false, true, true, false, "", false},
// {"note", false, true, true, false, "", false},
// {"description", false, true, true, false, "", false},
// {"abstract", false, true, true, false, "", false},
// {"content", false, true, true, false, "textArea", false},
// {"address", true, true, true, false, "", false},
// {"full_name", false, true, true, false, "", false},
// {"create_time", false, false, true, false, "time", true},
// {"modify_time", true, false, true, false, "time", true},
// {"image", false, true, true, false, "image", false},
// {"img", false, true, true, false, "image", false},
// {"icon", false, true, true, false, "image", false},
// {"avatar", false, true, true, false, "image", false},
// {"file", false, true, true, false, "file", false},
// {"age", false, true, true, false, "", false},
// {"email", false, true, true, false, "", false},
// {"time", true, true, true, false, "time", false},
// {"level", false, false, true, false, "", false},
// {"rule", true, true, true, false, "form", false},
// {"auth", false, true, true, false, "auth", true},
// {"table", true, false, true, false, "table", false},
// {"table_id", true, false, true, false, "table_id", false},
//}

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,8 @@ package code
var InitTpt = `package {{name}}
import (
. "../../../hotime"
. "../../../hotime/common"
. "code.hoteas.com/golang/hotime"
. "code.hoteas.com/golang/hotime/common"
)
var ID = "{{id}}"
@ -14,30 +14,32 @@ var Project = Proj{
//"user": UserCtr,
{{tablesCtr}}
"hotime":Ctr{
"login": func(this *Context) {
name := this.Req.FormValue("name")
password := this.Req.FormValue("password")
"login": func(that *Context) {
name := that.Req.FormValue("name")
password := that.Req.FormValue("password")
if name == "" || password == "" {
this.Display(3, "参数不足")
that.Display(3, "参数不足")
return
}
user := this.Db.Get("admin", "*", Map{"AND": Map{"OR":Map{"name": name,"phone":name}, "password": Md5(password)}})
user := that.Db.Get("admin", "*", Map{"AND": Map{"OR":Map{"name": name,"phone":name}, "password": Md5(password)}})
if user == nil {
this.Display(5, "登录失败")
that.Display(5, "登录失败")
return
}
this.Session("admin_id", user.GetCeilInt("id"))
this.Session("admin_name", name)
this.Display(0, this.SessionId)
that.Session("admin_id", user.GetCeilInt("id"))
that.Session("admin_name", name)
that.Display(0, that.SessionId)
},
"logout": func(this *Context) {
this.Session("admin_id", nil)
this.Session("admin_name", nil)
this.Display(0, "退出登录成功")
"logout": func(that *Context) {
that.Session("admin_id", nil)
that.Session("admin_name", nil)
that.Display(0, "退出登录成功")
},
"info": func(that *Context) {
hotimeName := that.RouterString[0]
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info("admin", data, that.Db)
str, inData := that.MakeCodeRouter[hotimeName].Info("admin", data, that.Db)
where := Map{"id": that.Session("admin_id").ToCeilInt()}
if len(inData) ==1 {
inData["id"] =where["id"]
@ -52,7 +54,7 @@ var Project = Proj{
return
}
for k, v := range re {
column := that.MakeCode.TableColumns["admin"][k]
column := that.MakeCodeRouter[hotimeName].TableColumns["admin"][k]
if column == nil {
continue
}
@ -69,15 +71,16 @@ var Project = Proj{
var CtrTpt = `package {{name}}
import (
. "../../../hotime"
. "../../../hotime/common"
. "code.hoteas.com/golang/hotime"
. "code.hoteas.com/golang/hotime/common"
"strings"
)
var {{table}}Ctr = Ctr{
"info": func(that *Context) {
hotimeName := that.RouterString[0]
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info(that.RouterString[1], data, that.Db)
str, inData := that.MakeCodeRouter[hotimeName].Info(that.RouterString[1], data, that.Db)
where := Map{"id": that.RouterString[2]}
if len(inData) ==1 {
@ -96,7 +99,7 @@ var {{table}}Ctr = Ctr{
}
for k, v := range re {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
column := that.MakeCodeRouter[hotimeName].TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
@ -108,7 +111,8 @@ var {{table}}Ctr = Ctr{
that.Display(0, re)
},
"add": func(that *Context) {
inData := that.MakeCode.Add(that.RouterString[1], that.Req)
hotimeName := that.RouterString[0]
inData := that.MakeCodeRouter[hotimeName].Add(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
@ -134,7 +138,8 @@ var {{table}}Ctr = Ctr{
that.Display(0, re)
},
"update": func(that *Context) {
inData := that.MakeCode.Edit(that.RouterString[1], that.Req)
hotimeName := that.RouterString[0]
inData := that.MakeCodeRouter[hotimeName].Edit(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "没有找到要更新的数据")
return
@ -165,7 +170,8 @@ var {{table}}Ctr = Ctr{
that.Display(0, re)
},
"remove": func(that *Context) {
inData := that.MakeCode.Delete(that.RouterString[1], that.Req)
hotimeName := that.RouterString[0]
inData := that.MakeCodeRouter[hotimeName].Delete(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
@ -186,10 +192,10 @@ var {{table}}Ctr = Ctr{
},
"search": func(that *Context) {
hotimeName := that.RouterString[0]
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
columnStr, leftJoin, where := that.MakeCode.Search(that.RouterString[1], data, that.Req, that.Db)
columnStr, leftJoin, where := that.MakeCodeRouter[hotimeName].Search(that.RouterString[1], data, that.Req, that.Db)
page := ObjToInt(that.Req.FormValue("page"))
pageSize := ObjToInt(that.Req.FormValue("pageSize"))
@ -208,7 +214,7 @@ var {{table}}Ctr = Ctr{
for _, v := range reData {
for k, _ := range v {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
column := that.MakeCodeRouter[hotimeName].TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}

View File

@ -9,10 +9,10 @@ type ContextBase struct {
}
//唯一标志
func (this *ContextBase) GetTag() string {
func (that *ContextBase) GetTag() string {
if this.tag == "" {
this.tag = ObjToStr(time.Now().Unix()) + ":" + ObjToStr(Random())
if that.tag == "" {
that.tag = ObjToStr(time.Now().Unix()) + ":" + ObjToStr(Random())
}
return this.tag
return that.tag
}

View File

@ -5,6 +5,7 @@ import (
"encoding/hex"
"math"
"strings"
"time"
)
//安全锁
@ -36,6 +37,78 @@ func StrFirstToUpper(str string) string {
return strings.ToUpper(first) + other
}
// 时间转字符串第二个参数支持1-5对应显示年月日时分秒
func Time2Str(t time.Time, qu ...interface{}) string {
if t.Unix() < 0 {
return ""
}
tp := 5
if len(qu) != 0 {
tp = (qu[0]).(int)
}
switch tp {
case 1:
return t.Format("2006-01")
case 2:
return t.Format("2006-01-02")
case 3:
return t.Format("2006-01-02 15")
case 4:
return t.Format("2006-01-02 15:04")
case 5:
return t.Format("2006-01-02 15:04:05")
case 12:
return t.Format("01-02")
case 14:
return t.Format("01-02 15:04")
case 15:
return t.Format("01-02 15:04:05")
case 34:
return t.Format("15:04")
case 35:
return t.Format("15:04:05")
}
return t.Format("2006-01-02 15:04:05")
}
// StrLd 相似度计算 ld compares two strings and returns the levenshtein distance between them.
func StrLd(s, t string, ignoreCase bool) int {
if ignoreCase {
s = strings.ToLower(s)
t = strings.ToLower(t)
}
d := make([][]int, len(s)+1)
for i := range d {
d[i] = make([]int, len(t)+1)
}
for i := range d {
d[i][0] = i
}
for j := range d[0] {
d[0][j] = j
}
for j := 1; j <= len(t); j++ {
for i := 1; i <= len(s); i++ {
if s[i-1] == t[j-1] {
d[i][j] = d[i-1][j-1]
} else {
min := d[i-1][j]
if d[i][j-1] < min {
min = d[i][j-1]
}
if d[i-1][j-1] < min {
min = d[i-1][j-1]
}
d[i][j] = min + 1
}
}
}
return d[len(s)][len(t)]
}
// Substr 字符串截取
func Substr(str string, start int, length int) string {
rs := []rune(str)
@ -106,7 +179,7 @@ func Md5(req string) string {
return hex.EncodeToString(cipherStr)
}
//随机数
// Rand 随机数
func Rand(count int) int {
res := Random()
for i := 0; i < count; i++ {
@ -131,7 +204,7 @@ func Random() float64 {
}
//随机数范围
// RandX 随机数范围
func RandX(small int, max int) int {
res := 0
//随机对象
@ -183,7 +256,7 @@ func RandX(small int, max int) int {
// GetDb()
//}
//复制返回数组
// DeepCopyMap 复制返回数组
func DeepCopyMap(value interface{}) interface{} {
if valueMap, ok := value.(Map); ok {
newMap := make(Map)
@ -242,7 +315,7 @@ func DeepCopyMap(value interface{}) interface{} {
// }
//}
//浮点数四舍五入保留小数
// Round 浮点数四舍五入保留小数
func Round(f float64, n int) float64 {
pow10_n := math.Pow10(n)
return math.Trunc((f+0.5/pow10_n)*pow10_n) / pow10_n

View File

@ -4,114 +4,140 @@ import (
"encoding/json"
"errors"
"reflect"
"sort"
"time"
)
//hotime的常用map
// hotime的常用map
type Map map[string]interface{}
//获取string
func (this Map) GetString(key string, err ...*Error) string {
// 获取string
func (that Map) GetString(key string, err ...*Error) string {
if len(err) != 0 {
err[0].SetError(nil)
}
return ObjToStr((this)[key])
return ObjToStr((that)[key])
}
func (this *Map) Pointer() *Map {
func (that *Map) Pointer() *Map {
return this
return that
}
//增加接口
func (this Map) Put(key string, value interface{}) {
//if this==nil{
// this=Map{}
// 增加接口
func (that Map) Put(key string, value interface{}) {
//if that==nil{
// that=Map{}
//}
this[key] = value
that[key] = value
}
//删除接口
func (this Map) Delete(key string) {
delete(this, key)
// 删除接口
func (that Map) Delete(key string) {
delete(that, key)
}
//获取Int
func (this Map) GetInt(key string, err ...*Error) int {
v := ObjToInt((this)[key], err...)
// 获取Int
func (that Map) GetInt(key string, err ...*Error) int {
v := ObjToInt((that)[key], err...)
return v
}
//获取Int
func (this Map) GetInt64(key string, err ...*Error) int64 {
v := ObjToInt64((this)[key], err...)
// 获取Int
func (that Map) GetInt64(key string, err ...*Error) int64 {
v := ObjToInt64((that)[key], err...)
return v
}
//获取向上取整Int64
func (this Map) GetCeilInt64(key string, err ...*Error) int64 {
v := ObjToCeilInt64((this)[key], err...)
// 获取向上取整Int64
func (that Map) GetCeilInt64(key string, err ...*Error) int64 {
v := ObjToCeilInt64((that)[key], err...)
return v
}
//获取向上取整Int
func (this Map) GetCeilInt(key string, err ...*Error) int {
v := ObjToCeilInt((this)[key], err...)
// 获取向上取整Int
func (that Map) GetCeilInt(key string, err ...*Error) int {
v := ObjToCeilInt((that)[key], err...)
return v
}
//获取向上取整float64
func (this Map) GetCeilFloat64(key string, err ...*Error) float64 {
v := ObjToCeilFloat64((this)[key], err...)
// 获取向上取整float64
func (that Map) GetCeilFloat64(key string, err ...*Error) float64 {
v := ObjToCeilFloat64((that)[key], err...)
return v
}
//获取Float64
func (this Map) GetFloat64(key string, err ...*Error) float64 {
// 获取Float64
func (that Map) GetFloat64(key string, err ...*Error) float64 {
v := ObjToFloat64((this)[key], err...)
v := ObjToFloat64((that)[key], err...)
return v
}
func (this Map) GetSlice(key string, err ...*Error) Slice {
func (that Map) GetSlice(key string, err ...*Error) Slice {
//var v Slice
v := ObjToSlice((this)[key], err...)
v := ObjToSlice((that)[key], err...)
return v
}
func (this Map) GetBool(key string, err ...*Error) bool {
func (that Map) GetBool(key string, err ...*Error) bool {
//var v Slice
v := ObjToBool((this)[key], err...)
v := ObjToBool((that)[key], err...)
return v
}
func (this Map) GetMap(key string, err ...*Error) Map {
func (that Map) GetTime(key string, err ...*Error) *time.Time {
v := ObjToTime((that)[key], err...)
return v
}
func (that Map) RangeSort(callback func(k string, v interface{}) (isEnd bool)) {
testQu := []string{}
//testQuData:= qu[0].(Map)
for key, _ := range that {
//fmt.Println(key, ":", value)
testQu = append(testQu, key)
}
sort.Strings(testQu)
for _, k := range testQu {
re := callback(k, that[k])
if re {
return
}
}
}
func (that Map) GetMap(key string, err ...*Error) Map {
//var data Slice
v := ObjToMap((this)[key], err...)
v := ObjToMap((that)[key], err...)
return v
}
func (this Map) Get(key string, err ...*Error) interface{} {
func (that Map) Get(key string, err ...*Error) interface{} {
if v, ok := (this)[key]; ok {
if v, ok := (that)[key]; ok {
return v
}
e := errors.New("没有存储key及对应的数据")
@ -123,11 +149,11 @@ func (this Map) Get(key string, err ...*Error) interface{} {
return nil
}
//请传递指针过来
func (this Map) ToStruct(stct interface{}) {
// 请传递指针过来
func (that Map) ToStruct(stct interface{}) {
data := reflect.ValueOf(stct).Elem()
for k, v := range this {
for k, v := range that {
ks := StrFirstToUpper(k)
dkey := data.FieldByName(ks)
if !dkey.IsValid() {
@ -135,13 +161,13 @@ func (this Map) ToStruct(stct interface{}) {
}
switch dkey.Type().String() {
case "int":
dkey.SetInt(this.GetInt64(k))
dkey.SetInt(that.GetInt64(k))
case "int64":
dkey.Set(reflect.ValueOf(this.GetInt64(k)))
dkey.Set(reflect.ValueOf(that.GetInt64(k)))
case "float64":
dkey.Set(reflect.ValueOf(this.GetFloat64(k)))
dkey.Set(reflect.ValueOf(that.GetFloat64(k)))
case "string":
dkey.Set(reflect.ValueOf(this.GetString(k)))
dkey.Set(reflect.ValueOf(that.GetString(k)))
case "interface{}":
dkey.Set(reflect.ValueOf(v))
}
@ -149,13 +175,13 @@ func (this Map) ToStruct(stct interface{}) {
}
func (this Map) ToJsonString() string {
return ObjToStr(this)
func (that Map) ToJsonString() string {
return ObjToStr(that)
}
func (this Map) JsonToMap(jsonStr string, err ...*Error) {
e := json.Unmarshal([]byte(jsonStr), &this)
func (that Map) JsonToMap(jsonStr string, err ...*Error) {
e := json.Unmarshal([]byte(jsonStr), &that)
if e != nil && len(err) != 0 {
err[0].SetError(e)
}

View File

@ -1,6 +1,8 @@
package common
//对象封装方便取用
import "time"
// 对象封装方便取用
type Obj struct {
Data interface{}
Error
@ -18,6 +20,13 @@ func (that *Obj) ToInt(err ...Error) int {
return ObjToInt(that.Data, &that.Error)
}
func (that *Obj) ToTime(err ...Error) *time.Time {
if len(err) != 0 {
that.Error = err[0]
}
return ObjToTime(that.Data, &that.Error)
}
func (that *Obj) ToInt64(err ...Error) int64 {
if len(err) != 0 {
that.Error = err[0]
@ -73,7 +82,7 @@ func (that *Obj) ToObj() interface{} {
return that.Data
}
//获取向上取整Int64
// 获取向上取整Int64
func (that *Obj) ToCeilInt64(err ...*Error) int64 {
if len(err) != 0 {
that.Error = *err[0]
@ -83,7 +92,7 @@ func (that *Obj) ToCeilInt64(err ...*Error) int64 {
}
//获取向上取整Int
// 获取向上取整Int
func (that *Obj) ToCeilInt(err ...*Error) int {
if len(err) != 0 {
that.Error = *err[0]

View File

@ -5,9 +5,11 @@ import (
"errors"
"math"
"strconv"
"strings"
"time"
)
//仅限于hotime.Slice
// 仅限于hotime.Slice
func ObjToMap(obj interface{}, e ...*Error) Map {
var err error
var v Map
@ -58,7 +60,7 @@ func ObjToMapArray(obj interface{}, e ...*Error) []Map {
return res
}
//仅限于hotime.Slice
// 仅限于hotime.Slice
func ObjToSlice(obj interface{}, e ...*Error) Slice {
var err error
var v Slice
@ -96,6 +98,87 @@ func ObjToSlice(obj interface{}, e ...*Error) Slice {
return v
}
func ObjToTime(obj interface{}, e ...*Error) *time.Time {
tInt := ObjToInt64(obj)
//字符串类型只支持标准mysql datetime格式
if tInt == 0 {
tStr := ObjToStr(obj)
timeNewStr := ""
timeNewStrs := strings.Split(tStr, "-")
for _, v := range timeNewStrs {
if v == "" {
continue
}
if len(v) == 1 {
v = "0" + v
}
if timeNewStr == "" {
timeNewStr = v
continue
}
timeNewStr = timeNewStr + "-" + v
}
tStr = timeNewStr
if len(tStr) > 18 {
t, e := time.Parse("2006-01-02 15:04:05", tStr)
if e == nil {
return &t
}
} else if len(tStr) > 15 {
t, e := time.Parse("2006-01-02 15:04", tStr)
if e == nil {
return &t
}
} else if len(tStr) > 12 {
t, e := time.Parse("2006-01-02 15", tStr)
if e == nil {
return &t
}
} else if len(tStr) > 9 {
t, e := time.Parse("2006-01-02", tStr)
if e == nil {
return &t
}
} else if len(tStr) > 6 {
t, e := time.Parse("2006-01", tStr)
if e == nil {
return &t
}
}
}
//纳秒级别
if len(ObjToStr(tInt)) > 16 {
//t := time.Time{}.Add(time.Nanosecond * time.Duration(tInt))
t := time.UnixMicro(tInt / 1000)
return &t
//微秒级别
} else if len(ObjToStr(tInt)) > 13 {
//t := time.Time{}.Add(time.Microsecond * time.Duration(tInt))
t := time.UnixMicro(tInt)
return &t
//毫秒级别
} else if len(ObjToStr(tInt)) > 10 {
//t := time.Time{}.Add(time.Millisecond * time.Duration(tInt))
t := time.UnixMilli(tInt)
return &t
//秒级别
} else if len(ObjToStr(tInt)) > 9 {
//t := time.Time{}.Add(time.Second * time.Duration(tInt))
t := time.Unix(tInt, 0)
return &t
} else if len(ObjToStr(tInt)) > 3 {
t, e := time.Parse("2006", ObjToStr(tInt))
if e == nil {
return &t
}
}
return nil
}
func ObjToFloat64(obj interface{}, e ...*Error) float64 {
var err error
v := float64(0)
@ -135,6 +218,15 @@ func ObjToFloat64(obj interface{}, e ...*Error) float64 {
err = errors.New("没有合适的转换对象!")
}
}
if math.IsNaN(v) {
err = errors.New("float64 is NaN")
v = 0
}
if math.IsInf(v, 0) {
err = errors.New("float64 is Inf")
v = 0
}
if len(e) != 0 {
e[0].SetError(err)
}
@ -142,21 +234,21 @@ func ObjToFloat64(obj interface{}, e ...*Error) float64 {
return v
}
//向上取整
// 向上取整
func ObjToCeilInt64(obj interface{}, e ...*Error) int64 {
f := ObjToCeilFloat64(obj, e...)
return ObjToInt64(math.Ceil(f))
}
//向上取整
// 向上取整
func ObjToCeilFloat64(obj interface{}, e ...*Error) float64 {
f := ObjToFloat64(obj, e...)
return math.Ceil(f)
}
//向上取整
// 向上取整
func ObjToCeilInt(obj interface{}, e ...*Error) int {
f := ObjToCeilFloat64(obj, e...)
return ObjToInt(f)
@ -268,7 +360,7 @@ func ObjToStr(obj interface{}) string {
return str
}
//转换为Map
// 转换为Map
func StrToMap(string string) Map {
data := Map{}
data.JsonToMap(string)
@ -276,7 +368,7 @@ func StrToMap(string string) Map {
return data
}
//转换为Slice
// 转换为Slice
func StrToSlice(string string) Slice {
data := ObjToSlice(string)
@ -284,7 +376,7 @@ func StrToSlice(string string) Slice {
return data
}
//字符串数组: a1,a2,a3转["a1","a2","a3"]
// 字符串数组: a1,a2,a3转["a1","a2","a3"]
func StrArrayToJsonStr(a string) string {
if len(a) > 2 {
@ -302,7 +394,7 @@ func StrArrayToJsonStr(a string) string {
return a
}
//字符串数组: a1,a2,a3转["a1","a2","a3"]
// 字符串数组: a1,a2,a3转["a1","a2","a3"]
func JsonStrToStrArray(a string) string {
//a = strings.Replace(a, `"`, "", -1)
if len(a) != 0 {
@ -312,7 +404,7 @@ func JsonStrToStrArray(a string) string {
return "," + a + ","
}
//字符串转int
// 字符串转int
func StrToInt(s string) (int, error) {
i, err := strconv.Atoi(s)
return i, err

View File

@ -2,6 +2,7 @@ package common
import (
"errors"
"time"
)
type Slice []interface{}
@ -14,6 +15,13 @@ func (that Slice) GetString(key int, err ...*Error) string {
return ObjToStr((that)[key])
}
func (that Slice) GetTime(key int, err ...*Error) *time.Time {
v := ObjToTime((that)[key], err...)
return v
}
// GetInt 获取Int
func (that Slice) GetInt(key int, err ...*Error) int {
v := ObjToInt((that)[key], err...)

View File

@ -1,22 +1,25 @@
package hotime
import (
. "./cache"
. "./common"
. "./db"
. "code.hoteas.com/golang/hotime/common"
. "code.hoteas.com/golang/hotime/db"
"encoding/json"
"net/http"
"strings"
"time"
)
type Context struct {
*Application
Resp http.ResponseWriter
Req *http.Request
Log Map //日志有则创建
RouterString []string
Config Map
Db *HoTimeDB
RespData Map
CacheIns
RespFunc func()
//CacheIns
SessionIns
DataSize int
HandlerStr string //复写请求url
@ -57,12 +60,41 @@ func (that *Context) Display(statu int, data interface{}) {
}
func (that *Context) View() {
if that.RespFunc != nil {
that.RespFunc()
}
if that.RespData == nil {
return
}
//创建日志
if that.Log != nil {
that.Log["time"] = time.Now().Format("2006-01-02 15:04")
if that.Session("admin_id").Data != nil {
that.Log["admin_id"] = that.Session("admin_id").ToCeilInt()
}
if that.Session("user_id").Data != nil {
that.Log["user_id"] = that.Session("user_id").ToCeilInt()
}
//负载均衡优化
ipStr := ""
if that.Req.Header.Get("X-Forwarded-For") != "" {
ipStr = that.Req.Header.Get("X-Forwarded-For")
} else if that.Req.Header.Get("X-Real-IP") != "" {
ipStr = that.Req.Header.Get("X-Real-IP")
}
//负载均衡优化
if ipStr == "" {
//RemoteAddr := that.Req.RemoteAddr
ipStr = Substr(that.Req.RemoteAddr, 0, strings.Index(that.Req.RemoteAddr, ":"))
}
that.Log["ip"] = ipStr
that.Db.Insert("logs", that.Log)
}
d, err := json.Marshal(that.RespData)
if err != nil {
that.Display(1, err.Error())
that.View()
return
}
that.DataSize = len(d)

431
db/HoTimeDB_API参考.md Normal file
View File

@ -0,0 +1,431 @@
# HoTimeDB API 快速参考
## ⚠️ 重要语法说明
**条件查询语法规则:**
- 单个条件可以直接写在Map中
- 多个条件:必须使用`AND``OR`包装
- 特殊条件:`ORDER``GROUP``LIMIT`与条件同级
```go
// ✅ 正确:单个条件
Map{"status": 1}
// ✅ 正确多个条件用AND包装
Map{
"AND": Map{
"status": 1,
"age[>]": 18,
},
}
// ✅ 正确:条件 + 特殊参数
Map{
"AND": Map{
"status": 1,
"age[>]": 18,
},
"ORDER": "id DESC",
"LIMIT": 10,
}
// ❌ 错误多个条件不用AND包装
Map{
"status": 1,
"age[>]": 18, // 这样写不支持!
}
```
## 基本方法
### 数据库连接
```go
db.SetConnect(func() (master, slave *sql.DB) { ... })
db.InitDb()
```
### 链式查询构建器
```go
// 创建查询构建器
builder := db.Table("tablename")
// 设置条件
builder.Where(key, value)
builder.And(key, value) 或 builder.And(map)
builder.Or(key, value) 或 builder.Or(map)
// JOIN操作
builder.LeftJoin(table, condition)
builder.RightJoin(table, condition)
builder.InnerJoin(table, condition)
builder.FullJoin(table, condition)
builder.Join(map) // 通用JOIN
// 排序和分组
builder.Order(fields...)
builder.Group(fields...)
builder.Limit(args...)
// 分页
builder.Page(page, pageSize)
// 执行查询
builder.Select(fields...) // 返回 []Map
builder.Get(fields...) // 返回 Map
builder.Count() // 返回 int
builder.Update(data) // 返回 int64
builder.Delete() // 返回 int64
```
## CRUD 操作
### 查询 (Select)
```go
// 基本查询
data := db.Select("table")
data := db.Select("table", "field1,field2")
data := db.Select("table", []string{"field1", "field2"})
data := db.Select("table", "*", whereMap)
// 带JOIN查询
data := db.Select("table", joinSlice, "fields", whereMap)
```
### 获取单条 (Get)
```go
// 自动添加 LIMIT 1
row := db.Get("table", "fields", whereMap)
```
### 插入 (Insert)
```go
id := db.Insert("table", dataMap)
// 返回新插入记录的ID
```
### 更新 (Update)
```go
affected := db.Update("table", dataMap, whereMap)
// 返回受影响的行数
```
### 删除 (Delete)
```go
affected := db.Delete("table", whereMap)
// 返回删除的行数
```
## 聚合函数
### 计数
```go
count := db.Count("table")
count := db.Count("table", whereMap)
count := db.Count("table", joinSlice, whereMap)
```
### 求和
```go
sum := db.Sum("table", "column")
sum := db.Sum("table", "column", whereMap)
sum := db.Sum("table", "column", joinSlice, whereMap)
```
## 分页查询
```go
// 设置分页
db.Page(page, pageSize)
// 分页查询
data := db.Page(page, pageSize).PageSelect("table", "fields", whereMap)
```
## 条件语法参考
### 比较操作符
| 写法 | SQL | 说明 |
|------|-----|------|
| `"field": value` | `field = ?` | 等于 |
| `"field[!]": value` | `field != ?` | 不等于 |
| `"field[>]": value` | `field > ?` | 大于 |
| `"field[>=]": value` | `field >= ?` | 大于等于 |
| `"field[<]": value` | `field < ?` | 小于 |
| `"field[<=]": value` | `field <= ?` | 小于等于 |
### 模糊查询
| 写法 | SQL | 说明 |
|------|-----|------|
| `"field[~]": "keyword"` | `field LIKE '%keyword%'` | 包含 |
| `"field[~!]": "keyword"` | `field LIKE 'keyword%'` | 以...开头 |
| `"field[!~]": "keyword"` | `field LIKE '%keyword'` | 以...结尾 |
| `"field[~~]": "%keyword%"` | `field LIKE '%keyword%'` | 手动LIKE |
### 范围查询
| 写法 | SQL | 说明 |
|------|-----|------|
| `"field[<>]": [min, max]` | `field BETWEEN ? AND ?` | 区间内 |
| `"field[><]": [min, max]` | `field NOT BETWEEN ? AND ?` | 区间外 |
### 集合查询
| 写法 | SQL | 说明 |
|------|-----|------|
| `"field": [v1, v2, v3]` | `field IN (?, ?, ?)` | 在集合中 |
| `"field[!]": [v1, v2, v3]` | `field NOT IN (?, ?, ?)` | 不在集合中 |
### NULL查询
| 写法 | SQL | 说明 |
|------|-----|------|
| `"field": nil` | `field IS NULL` | 为空 |
| `"field[!]": nil` | `field IS NOT NULL` | 不为空 |
### 直接SQL
| 写法 | SQL | 说明 |
|------|-----|------|
| `"field[#]": "NOW()"` | `field = NOW()` | 直接SQL函数 |
| `"[##]": "a > b"` | `a > b` | 直接SQL片段 |
| `"field[#!]": "1"` | `field != 1` | 不等于(不参数化) |
## 逻辑连接符
### AND 条件
```go
whereMap := Map{
"AND": Map{
"status": 1,
"age[>]": 18,
},
}
```
### OR 条件
```go
whereMap := Map{
"OR": Map{
"status": 1,
"type": 2,
},
}
```
### 嵌套条件
```go
whereMap := Map{
"AND": Map{
"status": 1,
"OR": Map{
"age[<]": 30,
"level[>]": 5,
},
},
}
```
## JOIN 语法
### 传统语法
```go
joinSlice := Slice{
Map{"[>]profile": "user.id = profile.user_id"}, // LEFT JOIN
Map{"[<]department": "user.dept_id = department.id"}, // RIGHT JOIN
Map{"[><]role": "user.role_id = role.id"}, // INNER JOIN
Map{"[<>]group": "user.group_id = group.id"}, // FULL JOIN
}
```
### 链式语法
```go
builder.LeftJoin("profile", "user.id = profile.user_id")
builder.RightJoin("department", "user.dept_id = department.id")
builder.InnerJoin("role", "user.role_id = role.id")
builder.FullJoin("group", "user.group_id = group.id")
```
## 特殊字段语法
### ORDER BY
```go
Map{
"ORDER": []string{"created_time DESC", "id ASC"},
}
// 或
Map{
"ORDER": "created_time DESC",
}
```
### GROUP BY
```go
Map{
"GROUP": []string{"department", "level"},
}
// 或
Map{
"GROUP": "department",
}
```
### LIMIT
```go
Map{
"LIMIT": []int{10, 20}, // offset 10, limit 20
}
// 或
Map{
"LIMIT": 20, // limit 20
}
```
## 事务处理
```go
success := db.Action(func(tx HoTimeDB) bool {
// 在这里执行数据库操作
// 返回 true 提交事务
// 返回 false 回滚事务
id := tx.Insert("table", data)
if id == 0 {
return false // 回滚
}
affected := tx.Update("table2", data2, where2)
if affected == 0 {
return false // 回滚
}
return true // 提交
})
```
## 原生SQL执行
### 查询
```go
results := db.Query("SELECT * FROM user WHERE age > ?", 18)
```
### 执行
```go
result, err := db.Exec("UPDATE user SET status = ? WHERE id = ?", 1, 100)
affected, _ := result.RowsAffected()
```
## 错误处理
```go
// 检查最后的错误
if db.LastErr.GetError() != nil {
fmt.Println("错误:", db.LastErr.GetError())
}
// 查看最后执行的SQL
fmt.Println("SQL:", db.LastQuery)
fmt.Println("参数:", db.LastData)
```
## 工具方法
### 数据库信息
```go
prefix := db.GetPrefix() // 获取表前缀
dbType := db.GetType() // 获取数据库类型
```
### 设置模式
```go
db.Mode = 0 // 生产模式
db.Mode = 1 // 测试模式
db.Mode = 2 // 开发模式输出SQL日志
```
## 常用查询模式
### 分页列表查询
```go
// 获取总数
total := db.Count("user", Map{"status": 1})
// 分页数据
users := db.Table("user").
Where("status", 1).
Order("created_time DESC").
Page(page, pageSize).
Select("id,name,email,created_time")
// 计算分页信息
totalPages := (total + pageSize - 1) / pageSize
```
### 关联查询
```go
orders := db.Table("order").
LeftJoin("user", "order.user_id = user.id").
LeftJoin("product", "order.product_id = product.id").
Where("order.status", "paid").
Select(`
order.*,
user.name as user_name,
product.title as product_title
`)
```
### 统计查询
```go
stats := db.Select("order",
"user_id, COUNT(*) as order_count, SUM(amount) as total_amount",
Map{
"AND": Map{
"status": "paid",
"created_time[>]": "2023-01-01",
},
"GROUP": "user_id",
"ORDER": "total_amount DESC",
})
```
### 条件组合查询
```go
products := db.Table("product").
Where("status", 1).
And(Map{
"OR": Map{
"category_id": []int{1, 2, 3},
"tags[~]": "热销",
},
}).
And(Map{
"price[<>]": []float64{10.0, 1000.0},
}).
Order("sort DESC", "created_time DESC").
Limit(0, 20).
Select()
```
## 链式调用完整示例
```go
// 复杂查询链式调用
result := db.Table("order").
LeftJoin("user", "order.user_id = user.id").
LeftJoin("product", "order.product_id = product.id").
Where("order.status", "paid").
And("order.created_time[>]", "2023-01-01").
And(Map{
"OR": Map{
"user.level": "vip",
"order.amount[>]": 1000,
},
}).
Group("user.id").
Order("total_amount DESC").
Page(1, 20).
Select(`
user.id,
user.name,
user.email,
COUNT(order.id) as order_count,
SUM(order.amount) as total_amount
`)
```
---
*快速参考版本: 1.0*

890
db/HoTimeDB_使用说明.md Normal file
View File

@ -0,0 +1,890 @@
# HoTimeDB ORM 使用说明书
## 概述
HoTimeDB是一个基于Golang实现的轻量级ORM框架参考PHP Medoo设计提供简洁的数据库操作接口。支持MySQL、SQLite等数据库并集成了缓存、事务、链式查询等功能。
## 目录
- [快速开始](#快速开始)
- [数据库配置](#数据库配置)
- [基本操作](#基本操作)
- [查询(Select)](#查询select)
- [获取单条记录(Get)](#获取单条记录get)
- [插入(Insert)](#插入insert)
- [更新(Update)](#更新update)
- [删除(Delete)](#删除delete)
- [链式查询构建器](#链式查询构建器)
- [条件查询语法](#条件查询语法)
- [JOIN操作](#join操作)
- [分页查询](#分页查询)
- [聚合函数](#聚合函数)
- [事务处理](#事务处理)
- [缓存机制](#缓存机制)
- [高级特性](#高级特性)
## 快速开始
### 初始化数据库连接
```go
import (
"code.hoteas.com/golang/hotime/db"
"code.hoteas.com/golang/hotime/common"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
// 创建连接函数
func createConnection() (master, slave *sql.DB) {
master, _ = sql.Open("mysql", "user:password@tcp(localhost:3306)/database")
// slave是可选的用于读写分离
slave = master // 或者连接到从数据库
return
}
// 初始化HoTimeDB
db := &db.HoTimeDB{}
db.SetConnect(createConnection)
```
## 数据库配置
### 基本配置
```go
type HoTimeDB struct {
*sql.DB
ContextBase
DBName string
*cache.HoTimeCache
Log *logrus.Logger
Type string // 数据库类型
Prefix string // 表前缀
LastQuery string // 最后执行的SQL
LastData []interface{} // 最后的参数
ConnectFunc func(err ...*Error) (*sql.DB, *sql.DB)
LastErr *Error
limit Slice
*sql.Tx // 事务对象
SlaveDB *sql.DB // 从数据库
Mode int // 0生产模式,1测试模式,2开发模式
}
```
### 设置表前缀
```go
db.Prefix = "app_"
```
### 设置运行模式
```go
db.Mode = 2 // 开发模式会输出SQL日志
```
## 基本操作
### 查询(Select)
#### 基本查询
```go
// 查询所有字段
users := db.Select("user")
// 查询指定字段
users := db.Select("user", "id,name,email")
// 查询指定字段(数组形式)
users := db.Select("user", []string{"id", "name", "email"})
// 单条件查询
users := db.Select("user", "*", common.Map{
"status": 1,
})
// 多条件查询必须使用AND包装
users = db.Select("user", "*", common.Map{
"AND": common.Map{
"status": 1,
"age[>]": 18,
},
})
```
#### 复杂条件查询
**重要说明多个条件必须使用AND或OR包装不能直接在根Map中写多个字段条件**
```go
// AND条件多个条件必须用AND包装
users := db.Select("user", "*", common.Map{
"AND": common.Map{
"status": 1,
"age[>]": 18,
"name[~]": "张",
},
})
// OR条件
users := db.Select("user", "*", common.Map{
"OR": common.Map{
"status": 1,
"type": 2,
},
})
// 混合条件嵌套AND/OR
users := db.Select("user", "*", common.Map{
"AND": common.Map{
"status": 1,
"OR": common.Map{
"age[<]": 30,
"level[>]": 5,
},
},
})
// 带ORDER BY、LIMIT等特殊条件
users := db.Select("user", "*", common.Map{
"AND": common.Map{
"status": 1,
"age[>]": 18,
},
"ORDER": "id DESC",
"LIMIT": 10,
})
// 带多个特殊条件
users := db.Select("user", "*", common.Map{
"OR": common.Map{
"level": "vip",
"balance[>]": 1000,
},
"ORDER": []string{"created_time DESC", "id ASC"},
"GROUP": "department",
"LIMIT": []int{0, 20}, // offset 0, limit 20
})
```
### 获取单条记录(Get)
```go
// 获取单个用户
user := db.Get("user", "*", common.Map{
"id": 1,
})
// 获取指定字段
user := db.Get("user", "id,name,email", common.Map{
"status": 1,
})
```
### 插入(Insert)
```go
// 基本插入
id := db.Insert("user", common.Map{
"name": "张三",
"email": "zhangsan@example.com",
"age": 25,
"status": 1,
"created_time[#]": "NOW()", // [#]表示直接插入SQL函数
})
// 返回插入的ID
fmt.Println("插入的用户ID:", id)
```
### 更新(Update)
```go
// 基本更新
affected := db.Update("user", common.Map{
"name": "李四",
"email": "lisi@example.com",
"updated_time[#]": "NOW()",
}, common.Map{
"id": 1,
})
// 条件更新
affected := db.Update("user", common.Map{
"status": 0,
}, common.Map{
"age[<]": 18,
"status": 1,
})
fmt.Println("更新的记录数:", affected)
```
### 删除(Delete)
```go
// 根据ID删除
affected := db.Delete("user", common.Map{
"id": 1,
})
// 条件删除
affected := db.Delete("user", common.Map{
"status": 0,
"created_time[<]": "2023-01-01",
})
fmt.Println("删除的记录数:", affected)
```
## 链式查询构建器
HoTimeDB提供了链式查询构建器让查询更加直观
```go
// 基本链式查询
users := db.Table("user").
Where("status", 1).
And("age[>]", 18).
Order("created_time DESC").
Limit(10, 20). // offset, limit
Select()
// 链式获取单条记录
user := db.Table("user").
Where("id", 1).
Get()
// 链式更新
affected := db.Table("user").
Where("id", 1).
Update(common.Map{
"name": "新名称",
"updated_time[#]": "NOW()",
})
// 链式删除
affected := db.Table("user").
Where("status", 0).
Delete()
// 链式统计
count := db.Table("user").
Where("status", 1).
Count()
```
### 链式条件组合
```go
// 复杂条件组合
users := db.Table("user").
Where("status", 1).
And("age[>=]", 18).
Or(common.Map{
"level[>]": 5,
"vip": 1,
}).
Order("created_time DESC", "id ASC").
Group("department").
Limit(0, 20).
Select("id,name,email,age")
```
## 条件查询语法
HoTimeDB支持丰富的条件查询语法类似于Medoo
### 基本比较
```go
// 等于
"id": 1
// 不等于
"id[!]": 1
// 大于
"age[>]": 18
// 大于等于
"age[>=]": 18
// 小于
"age[<]": 60
// 小于等于
"age[<=]": 60
```
### 模糊查询
```go
// LIKE %keyword%
"name[~]": "张"
// LIKE keyword% (右边任意)
"name[~!]": "张"
// LIKE %keyword (左边任意)
"name[!~]": "san"
// 手动LIKE需要手动添加%
"name[~~]": "%张%"
```
### 区间查询
```go
// BETWEEN
"age[<>]": []int{18, 60}
// NOT BETWEEN
"age[><]": []int{18, 25}
```
### IN查询
```go
// IN
"id": []int{1, 2, 3, 4, 5}
// NOT IN
"id[!]": []int{1, 2, 3}
```
### NULL查询
```go
// IS NULL
"deleted_at": nil
// IS NOT NULL
"deleted_at[!]": nil
```
### 直接SQL
```go
// 直接插入SQL表达式注意防注入
"created_time[#]": "> DATE_SUB(NOW(), INTERVAL 1 DAY)"
// 字段直接赋值(不使用参数化查询)
"update_time[#]": "NOW()"
// 直接SQL片段
"[##]": "user.status = 1 AND user.level > 0"
```
## JOIN操作
### 链式JOIN
```go
// LEFT JOIN
users := db.Table("user").
LeftJoin("profile", "user.id = profile.user_id").
LeftJoin("department", "user.dept_id = department.id").
Where("user.status", 1).
Select("user.*, profile.avatar, department.name AS dept_name")
// RIGHT JOIN
users := db.Table("user").
RightJoin("order", "user.id = order.user_id").
Select()
// INNER JOIN
users := db.Table("user").
InnerJoin("profile", "user.id = profile.user_id").
Select()
// FULL JOIN
users := db.Table("user").
FullJoin("profile", "user.id = profile.user_id").
Select()
```
### 传统JOIN语法
```go
users := db.Select("user",
common.Slice{
common.Map{"[>]profile": "user.id = profile.user_id"},
common.Map{"[>]department": "user.dept_id = department.id"},
},
"user.*, profile.avatar, department.name AS dept_name",
common.Map{
"user.status": 1,
},
)
```
### JOIN类型说明
- `[>]`: LEFT JOIN
- `[<]`: RIGHT JOIN
- `[><]`: INNER JOIN
- `[<>]`: FULL JOIN
## 分页查询
### 基本分页
```go
// 设置分页页码3每页20条
users := db.Page(3, 20).PageSelect("user", "*", common.Map{
"status": 1,
})
// 链式分页
users := db.Table("user").
Where("status", 1).
Page(2, 15). // 第2页每页15条
Select()
```
### 分页信息获取
```go
// 获取总数
total := db.Count("user", common.Map{
"status": 1,
})
// 计算分页信息
page := 2
pageSize := 20
offset := (page - 1) * pageSize
totalPages := (total + pageSize - 1) / pageSize
fmt.Printf("总记录数: %d, 总页数: %d, 当前页: %d\n", total, totalPages, page)
```
## 聚合函数
### 计数
```go
// 总数统计
total := db.Count("user")
// 条件统计
activeUsers := db.Count("user", common.Map{
"status": 1,
})
// JOIN统计
count := db.Count("user",
common.Slice{
common.Map{"[>]profile": "user.id = profile.user_id"},
},
common.Map{
"user.status": 1,
"profile.verified": 1,
},
)
```
### 求和
```go
// 基本求和
totalAmount := db.Sum("order", "amount")
// 条件求和
paidAmount := db.Sum("order", "amount", common.Map{
"status": "paid",
"created_time[>]": "2023-01-01",
})
// JOIN求和
sum := db.Sum("order", "amount",
common.Slice{
common.Map{"[>]user": "order.user_id = user.id"},
},
common.Map{
"user.level": "vip",
"order.status": "paid",
},
)
```
## 事务处理
```go
// 事务操作
success := db.Action(func(tx db.HoTimeDB) bool {
// 在事务中执行多个操作
// 扣减用户余额
affected1 := tx.Update("user", common.Map{
"balance[#]": "balance - 100",
}, common.Map{
"id": 1,
})
if affected1 == 0 {
return false // 回滚
}
// 创建订单
orderId := tx.Insert("order", common.Map{
"user_id": 1,
"amount": 100,
"status": "paid",
"created_time[#]": "NOW()",
})
if orderId == 0 {
return false // 回滚
}
// 添加订单详情
detailId := tx.Insert("order_detail", common.Map{
"order_id": orderId,
"product_id": 1001,
"quantity": 1,
"price": 100,
})
if detailId == 0 {
return false // 回滚
}
return true // 提交
})
if success {
fmt.Println("事务执行成功")
} else {
fmt.Println("事务回滚")
fmt.Println("错误:", db.LastErr.GetError())
}
```
## 缓存机制
HoTimeDB集成了缓存功能可以自动缓存查询结果
### 缓存配置
```go
import "code.hoteas.com/golang/hotime/cache"
// 设置缓存
db.HoTimeCache = &cache.HoTimeCache{
// 缓存配置
}
```
### 缓存行为
- 查询操作会自动检查缓存
- 增删改操作会自动清除相关缓存
- 缓存键格式:`表名:查询MD5`
- `cached`表不会被缓存
### 缓存清理
```go
// 手动清除表缓存
db.HoTimeCache.Db("user*", nil) // 清除user表所有缓存
```
## 高级特性
### 调试模式
```go
// 设置调试模式
db.Mode = 2
// 查看最后执行的SQL
fmt.Println("最后的SQL:", db.LastQuery)
fmt.Println("参数:", db.LastData)
fmt.Println("错误:", db.LastErr.GetError())
```
### 主从分离
```go
func createConnection() (master, slave *sql.DB) {
// 主库连接
master, _ = sql.Open("mysql", "user:password@tcp(master:3306)/database")
// 从库连接
slave, _ = sql.Open("mysql", "user:password@tcp(slave:3306)/database")
return master, slave
}
db.SetConnect(createConnection)
// 查询会自动使用从库,增删改使用主库
```
### 原生SQL执行
```go
// 执行查询SQL
results := db.Query("SELECT * FROM user WHERE age > ? AND status = ?", 18, 1)
// 执行更新SQL
result, err := db.Exec("UPDATE user SET last_login = NOW() WHERE id = ?", 1)
if err.GetError() == nil {
affected, _ := result.RowsAffected()
fmt.Println("影响行数:", affected)
}
```
### 数据类型处理
```go
// 时间戳插入
db.Insert("log", common.Map{
"user_id": 1,
"action": "login",
"created_time[#]": "UNIX_TIMESTAMP()",
})
// JSON数据
db.Insert("user", common.Map{
"name": "张三",
"preferences": `{"theme": "dark", "language": "zh-CN"}`,
})
```
### 数据行处理
HoTimeDB内部的`Row`方法会自动处理不同数据类型:
```go
// 自动转换[]uint8为字符串
// 保持其他类型的原始值
// 处理NULL值
```
## 错误处理
```go
// 检查错误
users := db.Select("user", "*", common.Map{"status": 1})
if db.LastErr.GetError() != nil {
fmt.Println("查询错误:", db.LastErr.GetError())
return
}
// 插入时检查错误
id := db.Insert("user", common.Map{
"name": "test",
"email": "test@example.com",
})
if id == 0 && db.LastErr.GetError() != nil {
fmt.Println("插入失败:", db.LastErr.GetError())
}
```
## 性能优化
### IN查询优化
HoTimeDB会自动优化IN查询将连续的数字转换为BETWEEN查询以提高性能
```go
// 这个查询会被自动优化单个IN条件
users := db.Select("user", "*", common.Map{
"id": []int{1, 2, 3, 4, 5, 10, 11, 12},
// 自动转为 (id BETWEEN 1 AND 5) OR (id BETWEEN 10 AND 12)
})
```
### 批量操作
```go
// 使用事务进行批量插入
success := db.Action(func(tx db.HoTimeDB) bool {
for i := 0; i < 1000; i++ {
id := tx.Insert("user", common.Map{
"name": fmt.Sprintf("User%d", i),
"email": fmt.Sprintf("user%d@example.com", i),
"created_time[#]": "NOW()",
})
if id == 0 {
return false
}
}
return true
})
```
## 特殊语法详解
### 条件标记符说明
| 标记符 | 功能 | 示例 | 生成SQL |
|--------|------|------|---------|
| `[>]` | 大于 | `"age[>]": 18` | `age > 18` |
| `[<]` | 小于 | `"age[<]": 60` | `age < 60` |
| `[>=]` | 大于等于 | `"age[>=]": 18` | `age >= 18` |
| `[<=]` | 小于等于 | `"age[<=]": 60` | `age <= 60` |
| `[!]` | 不等于/NOT IN | `"id[!]": 1` | `id != 1` |
| `[~]` | LIKE模糊查询 | `"name[~]": "张"` | `name LIKE '%张%'` |
| `[!~]` | 左模糊 | `"name[!~]": "张"` | `name LIKE '%张'` |
| `[~!]` | 右模糊 | `"name[~!]": "张"` | `name LIKE '张%'` |
| `[~~]` | 手动LIKE | `"name[~~]": "%张%"` | `name LIKE '%张%'` |
| `[<>]` | BETWEEN | `"age[<>]": [18,60]` | `age BETWEEN 18 AND 60` |
| `[><]` | NOT BETWEEN | `"age[><]": [18,25]` | `age NOT BETWEEN 18 AND 25` |
| `[#]` | 直接SQL | `"time[#]": "NOW()"` | `time = NOW()` |
| `[##]` | SQL片段 | `"[##]": "a > b"` | `a > b` |
| `[#!]` | 不等于直接SQL | `"status[#!]": "1"` | `status != 1` |
| `[!#]` | 不等于直接SQL | `"status[!#]": "1"` | `status != 1` |
## 与PHP Medoo的差异
1. **类型系统**: Golang的强类型要求使用`common.Map``common.Slice`
2. **语法差异**: 某些条件语法可能略有不同
3. **错误处理**: 使用Golang的错误处理模式
4. **并发安全**: 需要注意并发使用时的安全性
5. **缓存集成**: 内置了缓存功能
6. **链式调用**: 提供了更丰富的链式API
## 完整示例
```go
package main
import (
"fmt"
"database/sql"
"code.hoteas.com/golang/hotime/db"
"code.hoteas.com/golang/hotime/common"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// 初始化数据库
database := &db.HoTimeDB{
Prefix: "app_",
Mode: 2, // 开发模式
}
database.SetConnect(func(err ...*common.Error) (master, slave *sql.DB) {
master, _ = sql.Open("mysql", "root:password@tcp(localhost:3306)/testdb")
return master, master
})
// 查询用户列表
users := database.Table("user").
Where("status", 1).
And("age[>=]", 18).
Order("created_time DESC").
Limit(0, 10).
Select("id,name,email,age")
for _, user := range users {
fmt.Printf("用户: %s, 邮箱: %s, 年龄: %v\n",
user.GetString("name"),
user.GetString("email"),
user.Get("age"))
}
// 创建新用户
userId := database.Insert("user", common.Map{
"name": "新用户",
"email": "new@example.com",
"age": 25,
"status": 1,
"created_time[#]": "NOW()",
})
fmt.Printf("创建用户ID: %d\n", userId)
// 更新用户
affected := database.Table("user").
Where("id", userId).
Update(common.Map{
"last_login[#]": "NOW()",
"login_count[#]": "login_count + 1",
})
fmt.Printf("更新记录数: %d\n", affected)
// 复杂查询示例
orders := database.Table("order").
LeftJoin("user", "order.user_id = user.id").
LeftJoin("product", "order.product_id = product.id").
Where("order.status", "paid").
And("order.created_time[>]", "2023-01-01").
And(common.Map{
"OR": common.Map{
"user.level": "vip",
"order.amount[>]": 1000,
},
}).
Order("order.created_time DESC").
Group("user.id").
Select("user.name, user.email, SUM(order.amount) as total_amount, COUNT(*) as order_count")
// 事务示例
success := database.Action(func(tx db.HoTimeDB) bool {
// 在事务中执行操作
orderId := tx.Insert("order", common.Map{
"user_id": userId,
"total": 100.50,
"status": "pending",
"created_time[#]": "NOW()",
})
if orderId == 0 {
return false
}
detailId := tx.Insert("order_detail", common.Map{
"order_id": orderId,
"product_id": 1,
"quantity": 2,
"price": 50.25,
})
return detailId > 0
})
if success {
fmt.Println("订单创建成功")
} else {
fmt.Println("订单创建失败:", database.LastErr.GetError())
}
// 统计示例
totalUsers := database.Count("user", common.Map{"status": 1})
totalAmount := database.Sum("order", "amount", common.Map{"status": "paid"})
fmt.Printf("活跃用户数: %d, 总交易额: %.2f\n", totalUsers, totalAmount)
}
```
## 常见问题
### Q1: 如何处理事务中的错误?
A1: 在`Action`函数中返回`false`即可触发回滚,所有操作都会被撤销。
### Q2: 缓存何时会被清除?
A2: 执行`Insert``Update``Delete`操作时会自动清除对应表的缓存。
### Q3: 如何执行复杂的原生SQL
A3: 使用`Query`方法执行查询,使用`Exec`方法执行更新操作。
### Q4: 主从分离如何工作?
A4: 查询操作自动使用从库(如果配置了),增删改操作使用主库。
### Q5: 如何处理NULL值
A5: 使用`nil`作为值,查询时使用`"field": nil`表示`IS NULL`
---
*文档版本: 1.0*
*最后更新: 2024年*
> 本文档基于HoTimeDB源码分析生成如有疑问请参考源码实现。该ORM框架参考了PHP Medoo的设计理念但根据Golang语言特性进行了适配和优化。

252
db/README.md Normal file
View File

@ -0,0 +1,252 @@
# HoTimeDB ORM 文档集合
这是HoTimeDB ORM框架的完整文档集合包含使用说明、API参考、示例代码和测试数据。
## ⚠️ 重要更新说明
**语法修正通知**经过对源码的深入分析发现HoTimeDB的条件查询语法有特定规则
- ✅ **单个条件**可以直接写在Map中
- ⚠️ **多个条件**:必须使用`AND``OR`包装
- 📝 所有文档和示例代码已按正确语法更新
## 📚 文档列表
### 1. [HoTimeDB_使用说明.md](./HoTimeDB_使用说明.md)
**完整使用说明书** - 详细的功能介绍和使用指南
- 🚀 快速开始
- ⚙️ 数据库配置
- 🔧 基本操作 (CRUD)
- 🔗 链式查询构建器
- 🔍 条件查询语法
- 🔄 JOIN操作
- 📄 分页查询
- 📊 聚合函数
- 🔐 事务处理
- 💾 缓存机制
- ⚡ 高级特性
### 2. [HoTimeDB_API参考.md](./HoTimeDB_API参考.md)
**快速API参考手册** - 开发时的速查手册
- 📖 基本方法
- 🔧 CRUD操作
- 📊 聚合函数
- 📄 分页查询
- 🔍 条件语法参考
- 🔗 JOIN语法
- 🔐 事务处理
- 🛠️ 工具方法
### 3. [示例代码文件](../examples/hotimedb_examples.go)
**完整示例代码集合** - 可运行的实际应用示例(语法已修正)
- 🏗️ 基本初始化和配置
- 📝 基本CRUD操作
- 🔗 链式查询操作
- 🤝 JOIN查询操作
- 🔍 条件查询语法
- 📄 分页查询
- 📊 聚合函数查询
- 🔐 事务处理
- 💾 缓存机制
- 🔧 原生SQL执行
- 🚨 错误处理和调试
- ⚡ 性能优化技巧
- 🎯 完整应用示例
### 4. [test_tables.sql](./test_tables.sql)
**测试数据库结构** - 快速搭建测试环境
- 🏗️ 完整的表结构定义
- 📊 测试数据插入
- 🔍 索引优化
- 👁️ 视图示例
- 🔧 存储过程示例
## 🎯 核心特性
### 🌟 主要优势
- **类Medoo语法**: 参考PHP Medoo设计语法简洁易懂
- **链式查询**: 支持流畅的链式查询构建器
- **条件丰富**: 支持丰富的条件查询语法
- **事务支持**: 完整的事务处理机制
- **缓存集成**: 内置查询结果缓存
- **读写分离**: 支持主从数据库配置
- **类型安全**: 基于Golang的强类型系统
### 🔧 支持的数据库
- ✅ MySQL
- ✅ SQLite
- ✅ 其他标准SQL数据库
## 🚀 快速开始
### 1. 安装依赖
```bash
go mod init your-project
go get github.com/go-sql-driver/mysql
go get github.com/sirupsen/logrus
```
### 2. 创建测试数据库
```bash
mysql -u root -p < test_tables.sql
```
### 3. 基本使用
```go
import (
"code.hoteas.com/golang/hotime/db"
"code.hoteas.com/golang/hotime/common"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
// 初始化数据库
database := &db.HoTimeDB{
Prefix: "app_",
Mode: 2, // 开发模式
}
database.SetConnect(func() (master, slave *sql.DB) {
master, _ = sql.Open("mysql", "user:pass@tcp(localhost:3306)/dbname")
return master, master
})
// 链式查询链式语法支持单独Where然后用And添加条件
users := database.Table("user").
Where("status", 1). // 链式中可以单独Where
And("age[>]", 18). // 用And添加更多条件
Order("created_time DESC").
Limit(0, 10).
Select("id,name,email")
// 或者使用传统语法多个条件必须用AND包装
users2 := database.Select("user", "id,name,email", common.Map{
"AND": common.Map{
"status": 1,
"age[>]": 18,
},
"ORDER": "created_time DESC",
"LIMIT": []int{0, 10},
})
```
## ⚠️ 重要语法规则
**条件查询语法规则:**
- ✅ **单个条件**可以直接写在Map中
- ✅ **多个条件**:必须使用`AND``OR`包装
- ✅ **特殊参数**`ORDER``GROUP``LIMIT`与条件同级
```go
// ✅ 正确:单个条件
Map{"status": 1}
// ✅ 正确多个条件用AND包装
Map{
"AND": Map{
"status": 1,
"age[>]": 18,
},
"ORDER": "id DESC",
}
// ❌ 错误多个条件不用AND包装
Map{
"status": 1,
"age[>]": 18, // 不支持!
}
```
## 📝 条件查询语法速查
| 语法 | SQL | 说明 |
|------|-----|------|
| `"field": value` | `field = ?` | 等于 |
| `"field[!]": value` | `field != ?` | 不等于 |
| `"field[>]": value` | `field > ?` | 大于 |
| `"field[>=]": value` | `field >= ?` | 大于等于 |
| `"field[<]": value` | `field < ?` | 小于 |
| `"field[<=]": value` | `field <= ?` | 小于等于 |
| `"field[~]": "keyword"` | `field LIKE '%keyword%'` | 包含 |
| `"field[<>]": [min, max]` | `field BETWEEN ? AND ?` | 区间内 |
| `"field": [v1, v2, v3]` | `field IN (?, ?, ?)` | 在集合中 |
| `"field": nil` | `field IS NULL` | 为空 |
| `"field[#]": "NOW()"` | `field = NOW()` | 直接SQL |
## 🔗 JOIN语法速查
| 语法 | SQL | 说明 |
|------|-----|------|
| `"[>]table"` | `LEFT JOIN` | 左连接 |
| `"[<]table"` | `RIGHT JOIN` | 右连接 |
| `"[><]table"` | `INNER JOIN` | 内连接 |
| `"[<>]table"` | `FULL JOIN` | 全连接 |
## 🛠️ 链式方法速查
```go
db.Table("table") // 指定表名
.Where(key, value) // WHERE条件
.And(key, value) // AND条件
.Or(map) // OR条件
.LeftJoin(table, on) // LEFT JOIN
.Order(fields...) // ORDER BY
.Group(fields...) // GROUP BY
.Limit(offset, limit) // LIMIT
.Page(page, pageSize) // 分页
.Select(fields...) // 查询
.Get(fields...) // 获取单条
.Count() // 计数
.Update(data) // 更新
.Delete() // 删除
```
## ⚡ 性能优化建议
### 🔍 查询优化
- 使用合适的索引字段作为查询条件
- IN查询会自动优化为BETWEEN连续数字
- 避免SELECT *,指定需要的字段
- 合理使用LIMIT限制结果集大小
### 💾 缓存使用
- 查询结果会自动缓存
- 增删改操作会自动清除缓存
- `cached`表不参与缓存
### 🔐 事务处理
- 批量操作使用事务提高性能
- 事务中避免长时间操作
- 合理设置事务隔离级别
## 🚨 注意事项
### 🔒 安全相关
- 使用参数化查询防止SQL注入
- `[#]`语法需要注意防止注入
- 敏感数据加密存储
### 🎯 最佳实践
- 开发时设置`Mode = 2`便于调试
- 生产环境设置`Mode = 0`
- 合理设置表前缀
- 定期检查慢查询日志
## 🤝 与PHP Medoo的差异
1. **类型系统**: 使用`common.Map``common.Slice`
2. **错误处理**: Golang风格的错误处理
3. **链式调用**: 提供更丰富的链式API
4. **缓存集成**: 内置缓存功能
5. **并发安全**: 需要注意并发使用
## 📞 技术支持
- 📧 查看源码:`hotimedb.go`
- 📖 参考文档:本目录下的各个文档文件
- 🔧 示例代码:运行`HoTimeDB_示例代码.go`中的示例
---
**HoTimeDB ORM框架 - 让数据库操作更简单!** 🎉
> 本文档基于HoTimeDB源码分析生成参考了PHP Medoo的设计理念并根据Golang语言特性进行了优化。

File diff suppressed because it is too large Load Diff

332
db/test_tables.sql Normal file
View File

@ -0,0 +1,332 @@
-- HoTimeDB 测试表结构
-- 用于测试和示例的MySQL表结构定义
-- 请根据实际需要修改表结构和字段类型
-- 创建数据库(可选)
CREATE DATABASE IF NOT EXISTS `hotimedb_test` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `hotimedb_test`;
-- 用户表
DROP TABLE IF EXISTS `app_user`;
CREATE TABLE `app_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '用户姓名',
`email` varchar(255) NOT NULL DEFAULT '' COMMENT '邮箱地址',
`password` varchar(255) NOT NULL DEFAULT '' COMMENT '密码hash',
`phone` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号',
`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',
`gender` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0-未知 1-男 2-女',
`avatar` varchar(500) NOT NULL DEFAULT '' COMMENT '头像URL',
`level` varchar(20) NOT NULL DEFAULT 'normal' COMMENT '用户等级 normal-普通 vip-会员 svip-超级会员',
`balance` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '账户余额',
`login_count` int(11) NOT NULL DEFAULT '0' COMMENT '登录次数',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态 1-正常 0-禁用 -1-删除',
`last_login` datetime DEFAULT NULL COMMENT '最后登录时间',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_email` (`email`),
KEY `idx_status` (`status`),
KEY `idx_level` (`level`),
KEY `idx_created_time` (`created_time`),
KEY `idx_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
-- 用户资料表
DROP TABLE IF EXISTS `app_profile`;
CREATE TABLE `app_profile` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint(20) unsigned NOT NULL COMMENT '用户ID',
`real_name` varchar(50) NOT NULL DEFAULT '' COMMENT '真实姓名',
`id_card` varchar(20) NOT NULL DEFAULT '' COMMENT '身份证号',
`address` varchar(500) NOT NULL DEFAULT '' COMMENT '地址',
`bio` text COMMENT '个人简介',
`verified` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否认证 1-是 0-否',
`preferences` json DEFAULT NULL COMMENT '用户偏好设置JSON',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_id` (`user_id`),
KEY `idx_verified` (`verified`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户资料表';
-- 部门表
DROP TABLE IF EXISTS `app_department`;
CREATE TABLE `app_department` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '部门ID',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '部门名称',
`parent_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '上级部门ID',
`manager_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '部门经理ID',
`description` text COMMENT '部门描述',
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态 1-正常 0-禁用',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_parent_id` (`parent_id`),
KEY `idx_manager_id` (`manager_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='部门表';
-- 商品表
DROP TABLE IF EXISTS `app_product`;
CREATE TABLE `app_product` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '商品ID',
`title` varchar(200) NOT NULL DEFAULT '' COMMENT '商品标题',
`description` text COMMENT '商品描述',
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '商品价格',
`stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存数量',
`category_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '分类ID',
`brand` varchar(100) NOT NULL DEFAULT '' COMMENT '品牌',
`tags` varchar(500) NOT NULL DEFAULT '' COMMENT '标签,逗号分隔',
`images` json DEFAULT NULL COMMENT '商品图片JSON数组',
`attributes` json DEFAULT NULL COMMENT '商品属性JSON',
`sales_count` int(11) NOT NULL DEFAULT '0' COMMENT '销售数量',
`view_count` int(11) NOT NULL DEFAULT '0' COMMENT '浏览数量',
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态 1-上架 0-下架',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_category_id` (`category_id`),
KEY `idx_price` (`price`),
KEY `idx_status` (`status`),
KEY `idx_created_time` (`created_time`),
FULLTEXT KEY `ft_title_description` (`title`,`description`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='商品表';
-- 订单表
DROP TABLE IF EXISTS `app_order`;
CREATE TABLE `app_order` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '订单ID',
`order_no` varchar(50) NOT NULL DEFAULT '' COMMENT '订单号',
`user_id` bigint(20) unsigned NOT NULL COMMENT '用户ID',
`product_id` bigint(20) unsigned NOT NULL COMMENT '商品ID',
`quantity` int(11) NOT NULL DEFAULT '1' COMMENT '数量',
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '单价',
`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '总金额',
`discount_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额',
`final_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '实付金额',
`status` varchar(20) NOT NULL DEFAULT 'pending' COMMENT '订单状态 pending-待付款 paid-已付款 shipped-已发货 completed-已完成 cancelled-已取消',
`payment_method` varchar(20) NOT NULL DEFAULT '' COMMENT '支付方式',
`shipping_address` json DEFAULT NULL COMMENT '收货地址JSON',
`remark` text COMMENT '订单备注',
`paid_time` datetime DEFAULT NULL COMMENT '支付时间',
`shipped_time` datetime DEFAULT NULL COMMENT '发货时间',
`completed_time` datetime DEFAULT NULL COMMENT '完成时间',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`),
KEY `idx_user_id` (`user_id`),
KEY `idx_product_id` (`product_id`),
KEY `idx_status` (`status`),
KEY `idx_created_time` (`created_time`),
KEY `idx_paid_time` (`paid_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单表';
-- 订单详情表
DROP TABLE IF EXISTS `app_order_detail`;
CREATE TABLE `app_order_detail` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`order_id` bigint(20) unsigned NOT NULL COMMENT '订单ID',
`product_id` bigint(20) unsigned NOT NULL COMMENT '商品ID',
`product_title` varchar(200) NOT NULL DEFAULT '' COMMENT '商品标题',
`product_image` varchar(500) NOT NULL DEFAULT '' COMMENT '商品图片',
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '单价',
`quantity` int(11) NOT NULL DEFAULT '1' COMMENT '数量',
`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '小计',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_order_id` (`order_id`),
KEY `idx_product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单详情表';
-- 支付日志表
DROP TABLE IF EXISTS `app_payment_log`;
CREATE TABLE `app_payment_log` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint(20) unsigned NOT NULL COMMENT '用户ID',
`order_id` bigint(20) unsigned DEFAULT NULL COMMENT '订单ID',
`transaction_id` varchar(100) NOT NULL DEFAULT '' COMMENT '交易ID',
`type` varchar(20) NOT NULL DEFAULT '' COMMENT '类型 order_payment-订单支付 recharge-充值 refund-退款',
`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '金额',
`method` varchar(20) NOT NULL DEFAULT '' COMMENT '支付方式 balance-余额 alipay-支付宝 wechat-微信',
`status` varchar(20) NOT NULL DEFAULT 'pending' COMMENT '状态 pending-处理中 success-成功 failed-失败',
`description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述',
`extra_data` json DEFAULT NULL COMMENT '额外数据JSON',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_order_id` (`order_id`),
KEY `idx_transaction_id` (`transaction_id`),
KEY `idx_type` (`type`),
KEY `idx_status` (`status`),
KEY `idx_created_time` (`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='支付日志表';
-- 转账日志表
DROP TABLE IF EXISTS `app_transfer_log`;
CREATE TABLE `app_transfer_log` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`from_user_id` bigint(20) unsigned NOT NULL COMMENT '转出用户ID',
`to_user_id` bigint(20) unsigned NOT NULL COMMENT '转入用户ID',
`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '转账金额',
`type` varchar(20) NOT NULL DEFAULT 'transfer' COMMENT '类型',
`status` varchar(20) NOT NULL DEFAULT 'success' COMMENT '状态',
`description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_from_user_id` (`from_user_id`),
KEY `idx_to_user_id` (`to_user_id`),
KEY `idx_created_time` (`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转账日志表';
-- 操作日志表
DROP TABLE IF EXISTS `app_operation_log`;
CREATE TABLE `app_operation_log` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`module` varchar(50) NOT NULL DEFAULT '' COMMENT '模块',
`action` varchar(50) NOT NULL DEFAULT '' COMMENT '操作',
`description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述',
`ip` varchar(45) NOT NULL DEFAULT '' COMMENT 'IP地址',
`user_agent` varchar(500) NOT NULL DEFAULT '' COMMENT '用户代理',
`request_data` json DEFAULT NULL COMMENT '请求数据JSON',
`response_data` json DEFAULT NULL COMMENT '响应数据JSON',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态 1-成功 0-失败',
`execution_time` int(11) NOT NULL DEFAULT '0' COMMENT '执行时间(毫秒)',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_module` (`module`),
KEY `idx_action` (`action`),
KEY `idx_created_time` (`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='操作日志表';
-- 缓存表HoTimeDB内置缓存使用
DROP TABLE IF EXISTS `app_cached`;
CREATE TABLE `app_cached` (
`key` varchar(255) NOT NULL COMMENT '缓存键',
`value` longtext COMMENT '缓存值',
`expire_time` datetime DEFAULT NULL COMMENT '过期时间',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`key`),
KEY `idx_expire_time` (`expire_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='缓存表';
-- 批量用户表(用于批量操作示例)
DROP TABLE IF EXISTS `app_user_batch`;
CREATE TABLE `app_user_batch` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '用户姓名',
`email` varchar(255) NOT NULL DEFAULT '' COMMENT '邮箱地址',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_created_time` (`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='批量用户表';
-- 插入测试数据
INSERT INTO `app_user` (`name`, `email`, `password`, `age`, `level`, `balance`, `status`, `created_time`) VALUES
('张三', 'zhangsan@example.com', 'hashed_password_1', 25, 'normal', 1000.00, 1, '2023-01-15 10:30:00'),
('李四', 'lisi@example.com', 'hashed_password_2', 30, 'vip', 5000.00, 1, '2023-02-20 14:20:00'),
('王五', 'wangwu@example.com', 'hashed_password_3', 28, 'svip', 10000.00, 1, '2023-03-10 16:45:00'),
('赵六', 'zhaoliu@example.com', 'hashed_password_4', 35, 'normal', 500.00, 1, '2023-04-05 09:15:00'),
('钱七', 'qianqi@example.com', 'hashed_password_5', 22, 'vip', 2500.00, 0, '2023-05-12 11:30:00');
INSERT INTO `app_profile` (`user_id`, `real_name`, `verified`) VALUES
(1, '张三', 1),
(2, '李四', 1),
(3, '王五', 1),
(4, '赵六', 0),
(5, '钱七', 0);
INSERT INTO `app_department` (`name`, `parent_id`, `description`) VALUES
('技术部', 0, '负责技术开发和维护'),
('产品部', 0, '负责产品设计和规划'),
('市场部', 0, '负责市场推广和销售'),
('前端组', 1, '负责前端开发'),
('后端组', 1, '负责后端开发');
INSERT INTO `app_product` (`title`, `description`, `price`, `stock`, `category_id`, `brand`, `sales_count`) VALUES
('苹果手机', '最新款苹果手机,性能强劲', 6999.00, 100, 1, '苹果', 50),
('华为手机', '国产精品手机,拍照出色', 4999.00, 200, 1, '华为', 80),
('小米手机', '性价比之王,配置丰富', 2999.00, 300, 1, '小米', 120),
('联想笔记本', '商务办公首选,稳定可靠', 5999.00, 50, 2, '联想', 30),
('戴尔笔记本', '游戏性能出色,散热良好', 8999.00, 30, 2, '戴尔', 15);
INSERT INTO `app_order` (`order_no`, `user_id`, `product_id`, `quantity`, `price`, `amount`, `final_amount`, `status`, `created_time`) VALUES
('ORD202301150001', 1, 1, 1, 6999.00, 6999.00, 6999.00, 'paid', '2023-01-15 15:30:00'),
('ORD202301160001', 2, 2, 2, 4999.00, 9998.00, 9998.00, 'paid', '2023-01-16 10:20:00'),
('ORD202301170001', 3, 3, 1, 2999.00, 2999.00, 2999.00, 'completed', '2023-01-17 14:15:00'),
('ORD202301180001', 1, 4, 1, 5999.00, 5999.00, 5999.00, 'pending', '2023-01-18 16:45:00'),
('ORD202301190001', 4, 5, 1, 8999.00, 8999.00, 8999.00, 'cancelled', '2023-01-19 11:30:00');
INSERT INTO `app_order_detail` (`order_id`, `product_id`, `product_title`, `price`, `quantity`, `amount`) VALUES
(1, 1, '苹果手机', 6999.00, 1, 6999.00),
(2, 2, '华为手机', 4999.00, 2, 9998.00),
(3, 3, '小米手机', 2999.00, 1, 2999.00),
(4, 4, '联想笔记本', 5999.00, 1, 5999.00),
(5, 5, '戴尔笔记本', 8999.00, 1, 8999.00);
INSERT INTO `app_payment_log` (`user_id`, `order_id`, `type`, `amount`, `method`, `status`, `description`) VALUES
(1, 1, 'order_payment', 6999.00, 'balance', 'success', '订单支付'),
(2, 2, 'order_payment', 9998.00, 'alipay', 'success', '订单支付'),
(3, 3, 'order_payment', 2999.00, 'wechat', 'success', '订单支付'),
(2, NULL, 'recharge', 10000.00, 'alipay', 'success', '账户充值'),
(3, NULL, 'recharge', 5000.00, 'wechat', 'success', '账户充值');
-- 创建索引优化查询性能
CREATE INDEX idx_user_email_status ON app_user(email, status);
CREATE INDEX idx_order_user_status ON app_order(user_id, status);
CREATE INDEX idx_order_created_status ON app_order(created_time, status);
CREATE INDEX idx_product_category_status ON app_product(category_id, status);
-- 创建视图(可选)
CREATE OR REPLACE VIEW v_user_order_stats AS
SELECT
u.id as user_id,
u.name as user_name,
u.email,
u.level,
COUNT(o.id) as order_count,
COALESCE(SUM(o.final_amount), 0) as total_amount,
COALESCE(AVG(o.final_amount), 0) as avg_amount,
MAX(o.created_time) as last_order_time
FROM app_user u
LEFT JOIN app_order o ON u.id = o.user_id AND o.status IN ('paid', 'completed')
WHERE u.status = 1
GROUP BY u.id;
-- 存储过程示例(可选)
DELIMITER //
CREATE PROCEDURE GetUserOrderSummary(IN p_user_id BIGINT)
BEGIN
SELECT
u.name,
u.email,
u.level,
u.balance,
COUNT(o.id) as order_count,
COALESCE(SUM(CASE WHEN o.status = 'paid' THEN o.final_amount END), 0) as paid_amount,
COALESCE(SUM(CASE WHEN o.status = 'completed' THEN o.final_amount END), 0) as completed_amount
FROM app_user u
LEFT JOIN app_order o ON u.id = o.user_id
WHERE u.id = p_user_id AND u.status = 1
GROUP BY u.id;
END //
DELIMITER ;
-- 显示表结构信息
SELECT
TABLE_NAME as '表名',
TABLE_COMMENT as '表注释',
TABLE_ROWS as '预估行数',
ROUND(DATA_LENGTH/1024/1024, 2) as '数据大小(MB)'
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME LIKE 'app_%'
ORDER BY TABLE_NAME;

142
dri/aliyun/company.go Normal file
View File

@ -0,0 +1,142 @@
package aliyun
import (
. "code.hoteas.com/golang/hotime/common"
"fmt"
"io/ioutil"
"net/http"
//"fmt"
)
type company struct {
ApiCode string
Url string
}
var Company = company{}
func (that *company) Init(apiCode string) {
//"06c6a07e89dd45c88de040ee1489eef7"
that.ApiCode = apiCode
that.Url = "http://api.81api.com"
}
// GetCompanyOtherAll 获取企业基础信息
func (that *company) GetCompanyOtherAll(name string) Map {
res := Map{}
data, e := that.GetCompanyPatentsInfo(name) //获取专利信息
if e != nil {
fmt.Println(e)
} else {
res["PatentsInfo"] = data.GetMap("data")
}
data, e = that.GetCompanyOtherCopyrightsInfo(name) //获取其他专利
if e != nil {
fmt.Println(e)
} else {
res["OtherCopyrightsInfo"] = data.GetMap("data")
}
data, e = that.GetCompanyTrademarksInfo(name) //获取商标
if e != nil {
fmt.Println(e)
} else {
res["TrademarksInfo"] = data.GetMap("data")
}
data, e = that.GetCompanySoftwareCopyrightsInfo(name) //获取软著
if e != nil {
fmt.Println(e)
} else {
res["SoftwareCopyrightsInfo"] = data.GetMap("data")
}
data, e = that.GetCompanyProfileTags(name) //获取大数据标签
if e != nil {
fmt.Println(e)
} else {
res["ProfileTags"] = data.GetSlice("data")
}
return res
}
// GetCompanyBaseInfo 获取企业基础信息
func (that *company) GetCompanyList(name string) (Map, error) {
url := "/fuzzyQueryCompanyInfo/"
body, err := that.basePost(url, name)
return ObjToMap(body), err
}
// GetCompanyBaseInfo 获取企业基础信息
func (that *company) GetCompanyBaseInfo(name string) (Map, error) {
url := "/getCompanyBaseInfo/"
body, err := that.basePost(url, name)
return ObjToMap(body), err
}
// GetCompanyPatentsInfo 获取专利信息
func (that *company) GetCompanyPatentsInfo(name string) (Map, error) {
url := "/getCompanyPatentsInfo/"
body, err := that.basePost(url, name)
return ObjToMap(body), err
}
// GetCompanyTrademarksInfo 获取商标信息
func (that *company) GetCompanyTrademarksInfo(name string) (Map, error) {
url := "/getCompanyTrademarksInfo/"
body, err := that.basePost(url, name)
return ObjToMap(body), err
}
// GetCompanySoftwareCopyrightsInfo 获取软著信息
func (that *company) GetCompanySoftwareCopyrightsInfo(name string) (Map, error) {
url := "/getCompanySoftwareCopyrightsInfo/"
body, err := that.basePost(url, name)
return ObjToMap(body), err
}
// GetCompanyOtherCopyrightsInfo 获取其他著作信息
func (that *company) GetCompanyOtherCopyrightsInfo(name string) (Map, error) {
url := "/getCompanyOtherCopyrightsInfo/"
body, err := that.basePost(url, name)
return ObjToMap(body), err
}
// GetCompanyProfileTags 获取大数据标签
func (that *company) GetCompanyProfileTags(name string) (Map, error) {
url := "/getCompanyProfileTags/"
body, err := that.basePost(url, name)
return ObjToMap(body), err
}
func (that *company) basePost(url string, name string) (string, error) {
client := &http.Client{}
reqest, err := http.NewRequest("GET", that.Url+url+name+"/?isRaiseErrorCode=1", nil)
if err != nil {
fmt.Println("Fatal error ", err.Error())
return "", err
}
reqest.Header.Add("Authorization", "APPCODE "+that.ApiCode)
response, err := client.Do(reqest)
defer response.Body.Close()
if err != nil {
fmt.Println("Fatal error ", err.Error())
return "", err
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return "", err
}
res := string(body)
fmt.Println(res)
return res, err
}

142
dri/baidu/map.go Normal file
View File

@ -0,0 +1,142 @@
package baidu
import (
. "code.hoteas.com/golang/hotime/common"
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
type baiduMap struct {
Ak string
Url string
}
var BaiDuMap = baiduMap{}
func (that *baiduMap) Init(Ak string) {
//"ak=ZeT902EZvVgIoGVWEFK3osUm"
that.Ak = Ak
that.Url = "https://api.map.baidu.com/place/v2/suggestion?output=json" + "&ak=" + Ak
//query
}
// from 源坐标类型:
// 1GPS标准坐标
// 2搜狗地图坐标
// 3火星坐标gcj02即高德地图、腾讯地图和MapABC等地图使用的坐标
// 43中列举的地图坐标对应的墨卡托平面坐标;
// 5百度地图采用的经纬度坐标bd09ll
// 6百度地图采用的墨卡托平面坐标bd09mc;
// 7图吧地图坐标
// 851地图坐标
// int 1 1 否
// to
// 目标坐标类型:
// 3火星坐标gcj02即高德地图、腾讯地图及MapABC等地图使用的坐标
// 5百度地图采用的经纬度坐标bd09ll
// 6百度地图采用的墨卡托平面坐标bd09mc
func (that *baiduMap) Geoconv(latlngs []Map, from, to int) (Slice, error) {
client := &http.Client{}
latlngsStr := ""
for _, v := range latlngs {
if latlngsStr != "" {
latlngsStr = latlngsStr + ";" + v.GetString("lng") + "," + v.GetString("lat")
} else {
latlngsStr = v.GetString("lng") + "," + v.GetString("lat")
}
}
url := "https://api.map.baidu.com/geoconv/v1/?from=" + ObjToStr(from) + "&to=" + ObjToStr(to) + "&ak=" + that.Ak + "&coords=" + latlngsStr
reqest, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Println("Fatal error ", err.Error())
return nil, err
}
response, err := client.Do(reqest)
defer response.Body.Close()
if err != nil {
fmt.Println("Fatal error ", err.Error())
return nil, err
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
//fmt.Println(string(body))
data := ObjToMap(string(body))
if data.GetCeilInt64("status") != 0 {
return nil, err
}
return data.GetSlice("result"), err
}
func (that *baiduMap) GetAddress(lat string, lng string) (string, error) {
client := &http.Client{}
url := "https://api.map.baidu.com/reverse_geocoding/v3/?ak=" + that.Ak + "&output=json&location=" + lat + "," + lng
reqest, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Println("Fatal error ", err.Error())
return "", err
}
response, err := client.Do(reqest)
defer response.Body.Close()
if err != nil {
fmt.Println("Fatal error ", err.Error())
return "", err
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return "", err
}
//fmt.Println(string(body))
return string(body), err
}
// GetPosition 获取定位列表
func (that *baiduMap) GetPosition(name string, region string) (string, error) {
client := &http.Client{}
if region == "" {
region = "全国"
}
reqest, err := http.NewRequest("GET", that.Url+"&query="+url.PathEscape(name)+"&region="+url.PathEscape(region), nil)
if err != nil {
fmt.Println("Fatal error ", err.Error())
return "", err
}
response, err := client.Do(reqest)
defer response.Body.Close()
if err != nil {
fmt.Println("Fatal error ", err.Error())
return "", err
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return "", err
}
//fmt.Println(string(body))
return string(body), err
}

View File

@ -10,29 +10,31 @@ import (
//"fmt"
)
type DDY struct {
type dingdongyun struct {
ApiKey string
YzmUrl string
TzUrl string
}
func (this *DDY) Init(apikey string) {
this.ApiKey = apikey
this.YzmUrl = "https://api.dingdongcloud.com/v2/sms/captcha/send.json"
this.TzUrl = "https://api.dingdongcloud.com/v2/sms/notice/send.json"
var DDY = dingdongyun{}
func (that *dingdongyun) Init(apikey string) {
that.ApiKey = apikey
that.YzmUrl = "https://api.dingdongcloud.com/v2/sms/captcha/send.json"
that.TzUrl = "https://api.dingdongcloud.com/v2/sms/notice/send.json"
}
//发送短信验证码 code验证码如123456 返回true表示发送成功flase表示发送失败
func (this *DDY) SendYZM(umoblie string, tpt string, data map[string]string) (bool, error) {
// SendYZM 发送短信验证码 code验证码如123456 返回true表示发送成功flase表示发送失败
func (that *dingdongyun) SendYZM(umoblie string, tpt string, data map[string]string) (bool, error) {
for k, v := range data {
tpt = strings.Replace(tpt, "{"+k+"}", v, -1)
}
return this.send(this.YzmUrl, umoblie, tpt)
return that.send(that.YzmUrl, umoblie, tpt)
}
//发送通知
func (this *DDY) SendTz(umoblie []string, tpt string, data map[string]string) (bool, error) {
// SendTz 发送通知
func (that *dingdongyun) SendTz(umoblie []string, tpt string, data map[string]string) (bool, error) {
for k, v := range data {
tpt = strings.Replace(tpt, "{"+k+"}", v, -1)
}
@ -44,14 +46,14 @@ func (this *DDY) SendTz(umoblie []string, tpt string, data map[string]string) (b
}
umobleStr += "," + v
}
return this.send(this.TzUrl, umobleStr, tpt)
return that.send(that.TzUrl, umobleStr, tpt)
}
//发送短信
func (this *DDY) send(mUrl string, umoblie string, content string) (bool, error) {
func (that *dingdongyun) send(mUrl string, umoblie string, content string) (bool, error) {
data_send_sms_yzm := url.Values{"apikey": {this.ApiKey}, "mobile": {umoblie}, "content": {content}}
res, err := this.httpsPostForm(mUrl, data_send_sms_yzm)
data_send_sms_yzm := url.Values{"apikey": {that.ApiKey}, "mobile": {umoblie}, "content": {content}}
res, err := that.httpsPostForm(mUrl, data_send_sms_yzm)
if err != nil && res == "" {
return false, errors.New("连接错误")
}
@ -73,7 +75,7 @@ func (this *DDY) send(mUrl string, umoblie string, content string) (bool, error)
}
//调用url发送短信的连接
func (this *DDY) httpsPostForm(url string, data url.Values) (string, error) {
func (that *dingdongyun) httpsPostForm(url string, data url.Values) (string, error) {
resp, err := http.PostForm(url, data)
if err != nil {
@ -89,9 +91,3 @@ func (this *DDY) httpsPostForm(url string, data url.Values) (string, error) {
return string(body), nil
}
var DefaultDDY DDY
func init() {
DefaultDDY = DDY{}
}

View File

@ -1,15 +1,15 @@
package download
import (
. "../../common"
"bytes"
. "code.hoteas.com/golang/hotime/common"
"io"
"io/ioutil"
"net/http"
"os"
)
//下载文件
// Down 下载文件
func Down(url, path, name string, e ...*Error) bool {
os.MkdirAll(path, os.ModeDir)
@ -18,13 +18,13 @@ func Down(url, path, name string, e ...*Error) bool {
}
out, err := os.Create(path + name)
if err != nil && e[0] != nil {
if err != nil && len(e) != 0 {
e[0].SetError(err)
return false
}
defer out.Close()
resp, err := http.Get(url)
if err != nil && e[0] != nil {
if err != nil && len(e) != 0 {
e[0].SetError(err)
return false
}
@ -32,7 +32,7 @@ func Down(url, path, name string, e ...*Error) bool {
pix, err := ioutil.ReadAll(resp.Body)
_, err = io.Copy(out, bytes.NewReader(pix))
if err != nil && e[0] != nil {
if err != nil && len(e) != 0 {
e[0].SetError(err)
return false
}

149
dri/mongodb/mongodb.go Normal file
View File

@ -0,0 +1,149 @@
package mongodb
import (
. "code.hoteas.com/golang/hotime/common"
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type MongoDb struct {
Client *mongo.Client
Ctx context.Context
DataBase *mongo.Database
Connect *mongo.Collection
LastErr error
}
func GetMongoDb(database, url string) (*MongoDb, error) {
db := MongoDb{}
clientOptions := options.Client().ApplyURI(url)
db.Ctx = context.TODO()
// Connect to MongoDb
var err error
db.Client, err = mongo.Connect(db.Ctx, clientOptions)
if err != nil {
return nil, err
}
// Check the connection
err = db.Client.Ping(db.Ctx, nil)
if err != nil {
return nil, err
}
fmt.Println("Connected to MongoDb!")
//databases, err := db.Client.ListDatabaseNames(db.Ctx, bson.M{})
//if err != nil {
// return nil, err
//}
//fmt.Println(databases)
db.DataBase = db.Client.Database(database)
return &db, nil
}
func (that *MongoDb) Insert(table string, data interface{}) string {
collection := that.DataBase.Collection(table)
re, err := collection.InsertOne(that.Ctx, data)
if err != nil {
that.LastErr = err
return ""
}
return ObjToStr(re.InsertedID)
}
func (that *MongoDb) InsertMany(table string, data ...interface{}) Slice {
collection := that.DataBase.Collection(table)
re, err := collection.InsertMany(that.Ctx, data)
if err != nil {
that.LastErr = err
return Slice{}
}
return ObjToSlice(re.InsertedIDs)
}
func (that *MongoDb) Update(table string, data Map, where Map) int64 {
collection := that.DataBase.Collection(table)
re, err := collection.UpdateMany(that.Ctx, where, data)
if err != nil {
that.LastErr = err
return 0
}
return re.ModifiedCount
}
func (that *MongoDb) Delete(table string, where Map) int64 {
collection := that.DataBase.Collection(table)
re, err := collection.DeleteMany(that.Ctx, where)
if err != nil {
that.LastErr = err
return 0
}
return re.DeletedCount
}
func (that *MongoDb) Get(table string, where Map) Map {
results := []Map{}
var cursor *mongo.Cursor
var err error
collection := that.DataBase.Collection(table)
if cursor, err = collection.Find(that.Ctx, where, options.Find().SetSkip(0), options.Find().SetLimit(2)); err != nil {
that.LastErr = err
return nil
}
//延迟关闭游标
defer func() {
if err := cursor.Close(that.Ctx); err != nil {
that.LastErr = err
}
}()
//这里的结果遍历可以使用另外一种更方便的方式:
if err = cursor.All(that.Ctx, &results); err != nil {
that.LastErr = err
return nil
}
if len(results) > 0 {
return results[0]
}
return nil
}
func (that MongoDb) Select(table string, where Map, page, pageRow int64) []Map {
page = (page - 1) * pageRow
if page < 0 {
page = 0
}
results := []Map{}
var cursor *mongo.Cursor
var err error
collection := that.DataBase.Collection(table)
if cursor, err = collection.Find(that.Ctx, where, options.Find().SetSkip(page), options.Find().SetLimit(pageRow)); err != nil {
that.LastErr = err
return results
}
//延迟关闭游标
defer func() {
if err := cursor.Close(that.Ctx); err != nil {
that.LastErr = err
}
}()
//这里的结果遍历可以使用另外一种更方便的方式:
if err = cursor.All(that.Ctx, &results); err != nil {
that.LastErr = err
return results
}
return results
}

View File

@ -23,7 +23,7 @@ func FileGet(path string) []byte {
return buf
}
//RSA加密
// RSA_Encrypt RSA加密
// plainText 要加密的数据
// path 公钥匙文件地址
func RSA_Encrypt(plainText []byte, buf []byte) []byte {
@ -46,7 +46,7 @@ func RSA_Encrypt(plainText []byte, buf []byte) []byte {
return cipherText
}
//RSA解密
// RSA_Decrypt RSA解密
// cipherText 需要解密的byte数据
// path 私钥文件路径
func RSA_Decrypt(cipherText []byte, buf []byte) []byte {
@ -97,7 +97,7 @@ func Demo() {
fmt.Println(string(decrypt))
}
//生成RSA私钥和公钥保存到文件中
// GenerateRSAKey 生成RSA私钥和公钥保存到文件中
// bits 证书大小
func GenerateRSAKey(bits int, path string) {
//GenerateKey函数使用随机数据生成器random生成一对具有指定字位数的RSA密钥

119
dri/tencent/company.go Normal file
View File

@ -0,0 +1,119 @@
package tencent
import (
. "code.hoteas.com/golang/hotime/common"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"net/http"
gourl "net/url"
"strings"
"time"
)
type company struct {
secretId string
secretKey string
}
var Company = company{}
func (that *company) Init(secretId, secretKey string) {
// 云市场分配的密钥Id
//secretId := "xxxx"
//// 云市场分配的密钥Key
//secretKey := "xxxx"
that.secretId = secretId
that.secretKey = secretKey
}
func (that *company) calcAuthorization(source string) (auth string, datetime string, err error) {
timeLocation, _ := time.LoadLocation("Etc/GMT")
datetime = time.Now().In(timeLocation).Format("Mon, 02 Jan 2006 15:04:05 GMT")
signStr := fmt.Sprintf("x-date: %s\nx-source: %s", datetime, source)
// hmac-sha1
mac := hmac.New(sha1.New, []byte(that.secretKey))
mac.Write([]byte(signStr))
sign := base64.StdEncoding.EncodeToString(mac.Sum(nil))
auth = fmt.Sprintf("hmac id=\"%s\", algorithm=\"hmac-sha1\", headers=\"x-date x-source\", signature=\"%s\"",
that.secretId, sign)
return auth, datetime, nil
}
func (that *company) urlencode(params map[string]string) string {
var p = gourl.Values{}
for k, v := range params {
p.Add(k, v)
}
return p.Encode()
}
func (that *company) GetCompany(name string) Map {
// 云市场分配的密钥Id
//secretId := "xxxx"
//// 云市场分配的密钥Key
//secretKey := "xxxx"
source := "market"
// 签名
auth, datetime, _ := that.calcAuthorization(source)
// 请求方法
method := "GET"
// 请求头
headers := map[string]string{"X-Source": source, "X-Date": datetime, "Authorization": auth}
// 查询参数
queryParams := make(map[string]string)
queryParams["keyword"] = name
// body参数
bodyParams := make(map[string]string)
// url参数拼接
url := "https://service-3jnh3ku8-1256140209.gz.apigw.tencentcs.com/release/business4/geet"
if len(queryParams) > 0 {
url = fmt.Sprintf("%s?%s", url, that.urlencode(queryParams))
}
bodyMethods := map[string]bool{"POST": true, "PUT": true, "PATCH": true}
var body io.Reader = nil
if bodyMethods[method] {
body = strings.NewReader(that.urlencode(bodyParams))
headers["Content-Type"] = "application/x-www-form-urlencoded"
}
client := &http.Client{
Timeout: 5 * time.Second,
}
request, err := http.NewRequest(method, url, body)
if err != nil {
fmt.Println(err)
return nil
}
for k, v := range headers {
request.Header.Set(k, v)
}
response, err := client.Do(request)
if err != nil {
fmt.Println(err)
return nil
}
defer response.Body.Close()
bodyBytes, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println(err)
return nil
}
res := string(bodyBytes)
fmt.Println(res)
return ObjToMap(res)
}

104
dri/tencent/tencent.go Normal file
View File

@ -0,0 +1,104 @@
package tencent
import (
"fmt"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
ocr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr/v20181119"
)
type tencent struct {
secretId string
secretKey string
credential *common.Credential
}
var Tencent = tencent{}
func (that *tencent) Init(secretId, secretKey string) {
// 云市场分配的密钥Id
//secretId := "xxxx"
//// 云市场分配的密钥Key
//secretKey := "xxxx"
that.secretId = secretId
that.secretKey = secretKey
that.credential = common.NewCredential(
that.secretId,
that.secretKey,
)
}
func (that *tencent) OCRCOMPANY(base64Str string) string {
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "ocr.tencentcloudapi.com"
client, _ := ocr.NewClient(that.credential, "ap-guangzhou", cpf)
request := ocr.NewBizLicenseOCRRequest()
//request.ImageUrl = common.StringPtr("https://img0.baidu.com/it/u=2041013181,3227632688&fm=26&fmt=auto")
request.ImageBase64 = common.StringPtr(base64Str)
response, err := client.BizLicenseOCR(request)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Println("An API error has returned: %s", err)
return ""
}
if err != nil {
fmt.Println("An API error has returned: %s", err)
return ""
}
//fmt.Printf("%s", response.ToJsonString())
return response.ToJsonString()
}
func (that *tencent) OCR(base64Str string) string {
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "ocr.tencentcloudapi.com"
client, _ := ocr.NewClient(that.credential, "ap-guangzhou", cpf)
request := ocr.NewGeneralAccurateOCRRequest()
//request.ImageUrl = common.StringPtr("https://img0.baidu.com/it/u=2041013181,3227632688&fm=26&fmt=auto")
request.ImageBase64 = common.StringPtr(base64Str)
response, err := client.GeneralAccurateOCR(request)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Println("An API error has returned: %s", err)
return ""
}
if err != nil {
fmt.Println("An API error has returned: %s", err)
return ""
}
//fmt.Printf("%s", response.ToJsonString())
return response.ToJsonString()
}
func (that *tencent) Qrcode(base64Str string) string {
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "ocr.tencentcloudapi.com"
client, _ := ocr.NewClient(that.credential, "ap-guangzhou", cpf)
request := ocr.NewQrcodeOCRRequest()
request.ImageBase64 = common.StringPtr(base64Str)
response, err := client.QrcodeOCR(request)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Println("An API error has returned: %s", err)
return ""
}
if err != nil {
fmt.Println("An API error has returned: %s", err)
return ""
}
//fmt.Printf("%s", response.ToJsonString())
return response.ToJsonString()
}

View File

@ -1,7 +1,7 @@
package upload
import (
. "../../common"
. "code.hoteas.com/golang/hotime/common"
"errors"
"io"
"mime/multipart"
@ -15,7 +15,7 @@ type Upload struct {
Path string
}
func (this *Upload) UpFile(Request *http.Request, fieldName, savefilepath, savePath string) (string, error) {
func (that *Upload) UpFile(Request *http.Request, fieldName, savefilepath, savePath string) (string, error) {
Request.ParseMultipartForm(32 << 20)
var filePath string
files := Request.MultipartForm.File
@ -36,7 +36,7 @@ func (this *Upload) UpFile(Request *http.Request, fieldName, savefilepath, saveP
data := time.Unix(int64(t), 0).Format("2006-01")
path := ""
if strings.EqualFold(savefilepath, "") {
path = this.Path + data
path = that.Path + data
} else {
path = savefilepath + data
}
@ -51,7 +51,7 @@ func (this *Upload) UpFile(Request *http.Request, fieldName, savefilepath, saveP
}
}
filename := time.Unix(int64(t), 0).Format("2006-01-02-15-22-25") + ObjToStr(Rand(6))
filePath = path + "/" + filename + this.Path
filePath = path + "/" + filename + that.Path
} else {
filePath = savePath
}

79
dri/wechat/h5program.go Normal file
View File

@ -0,0 +1,79 @@
package wechat
import (
"github.com/silenceper/wechat/v2"
"github.com/silenceper/wechat/v2/cache"
"github.com/silenceper/wechat/v2/officialaccount"
h5config "github.com/silenceper/wechat/v2/officialaccount/config"
"github.com/silenceper/wechat/v2/officialaccount/js"
"github.com/silenceper/wechat/v2/officialaccount/oauth"
)
//基于此文档开发
//https://github.com/silenceper/wechat/blob/v2/doc/api/officialaccount.md
type h5Program struct {
Memory *cache.Memory
Config *h5config.Config
*officialaccount.OfficialAccount
weixin *wechat.Wechat //微信登录实例
}
var H5Program = h5Program{}
// Init 初始化
func (that *h5Program) Init(appid string, appsecret string) {
that.weixin = wechat.NewWechat()
that.Memory = cache.NewMemory()
that.Config = &h5config.Config{
AppID: appid,
AppSecret: appsecret,
//Token: "xxx",
//EncodingAESKey: "xxxx",
Cache: that.Memory,
}
that.OfficialAccount = that.weixin.GetOfficialAccount(that.Config)
}
// GetUserInfo 获取用户信息
func (that *h5Program) GetUserInfo(code string) (appid string, resToken oauth.ResAccessToken, userInfo oauth.UserInfo, err error) {
auth := that.GetOauth()
//weixin.GetOpenPlatform()
resToken, err = auth.GetUserAccessToken(code)
if err != nil {
return auth.AppID, resToken, userInfo, err
}
//getUserInfo
userInfo, err = auth.GetUserInfo(resToken.AccessToken, resToken.OpenID, "")
if err != nil {
return auth.AppID, resToken, userInfo, err
}
return auth.AppID, resToken, userInfo, err
}
// GetSignUrl js url签名
func (that *h5Program) GetSignUrl(signUrl string) (*js.Config, error) {
js := that.OfficialAccount.GetJs()
cfg1, e := js.GetConfig(signUrl)
if e != nil {
return nil, e
}
return cfg1, nil
}
// GetSignUrl js url签名
//func (that *h5Program) GetJsPay(signUrl string) (*js.Config, error) {
// //
// //js := that.OfficialAccount().GetJs()
// //
// //cfg1, e := js.GetConfig(signUrl)
// //if e != nil {
// // return nil, e
// //}
//
// return cfg1, nil
//}

66
dri/wechat/miniprogram.go Normal file
View File

@ -0,0 +1,66 @@
package wechat
import (
"errors"
"github.com/silenceper/wechat/v2"
"github.com/silenceper/wechat/v2/cache"
"github.com/silenceper/wechat/v2/miniprogram"
"github.com/silenceper/wechat/v2/miniprogram/auth"
"github.com/silenceper/wechat/v2/miniprogram/config"
"github.com/silenceper/wechat/v2/miniprogram/encryptor"
)
type miniProgram struct {
Memory *cache.Memory
Config *config.Config
weixin *wechat.Wechat //微信登录实例
*miniprogram.MiniProgram
}
var MiniProgram = miniProgram{}
// Init 初始化
func (that *miniProgram) Init(appid string, appsecret string) {
that.weixin = wechat.NewWechat()
that.Memory = cache.NewMemory()
that.Config = &config.Config{
AppID: appid,
AppSecret: appsecret,
//Token: "xxx",
//EncodingAESKey: "xxxx",
Cache: that.Memory,
}
that.MiniProgram = that.weixin.GetMiniProgram(that.Config)
}
func (that *miniProgram) GetBaseUserInfo(code string) (appid string, re auth.ResCode2Session, err error) {
appid = that.Config.AppID
a := that.GetAuth()
re, err = a.Code2Session(code)
if err != nil {
return appid, re, err
}
return appid, re, err
}
func (that *miniProgram) GetPhoneNumber(sessionkey, encryptedData, iv string) (appid string, re *encryptor.PlainData, err error) {
appid = that.Config.AppID
if sessionkey == "" || encryptedData == "" || iv == "" {
return appid, re, errors.New("参数不足")
}
eny := that.GetEncryptor()
re, err = eny.Decrypt(sessionkey, encryptedData, iv)
if err != nil {
return appid, re, err
}
return appid, re, err
}

142
dri/wechat/pay.go Normal file
View File

@ -0,0 +1,142 @@
package wechat
import (
"context"
"fmt"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/wechat/v3"
"net/http"
"time"
)
//基于此文档开发
//https://github.com/silenceper/wechat/blob/v2/doc/api/officialaccount.md
type wxpay struct {
client *wechat.ClientV3
ctx context.Context
apiV3Key string
MchId string
}
var WxPay = wxpay{}
// Init 初始化
func (that *wxpay) Init(MchId, SerialNo, APIv3Key, PrivateKey string) {
client, err := wechat.NewClientV3(MchId, SerialNo, APIv3Key, PrivateKey)
if err != nil {
//xlog.Error(err)
fmt.Println(err)
return
}
that.client = client
that.apiV3Key = APIv3Key
that.MchId = MchId
// 设置微信平台API证书和序列号如开启自动验签请忽略此步骤
//client.SetPlatformCert([]byte(""), "")
that.ctx = context.Background()
// 启用自动同步返回验签并定时更新微信平台API证书开启自动验签时无需单独设置微信平台API证书和序列号
err = client.AutoVerifySign()
if err != nil {
//xlog.Error(err)
fmt.Println(err)
return
}
// 打开Debug开关输出日志默认是关闭的
client.DebugSwitch = gopay.DebugOn
}
// GetUserInfo 获取用户信息
func (that *wxpay) GetJsOrder(money int64, appid, openid, name, tradeNo, notifyUrl string) (jsApiParams *wechat.JSAPIPayParams, err error) {
fmt.Println("dasdas", money, appid, name, tradeNo, notifyUrl)
PrepayId, err := that.getPrepayId(money, appid, that.MchId, openid, name, tradeNo, notifyUrl)
if err != nil {
return nil, err
}
//小程序
jsapi, err := that.client.PaySignOfJSAPI(appid, PrepayId)
return jsapi, err
}
func (that *wxpay) CallbackJsOrder(req *http.Request) (*wechat.V3DecryptResult, error) {
notifyReq, err := wechat.V3ParseNotify(req)
if err != nil {
//xlog.Error(err)
return nil, err
}
// wxPublicKey 通过 client.WxPublicKey() 获取
err = notifyReq.VerifySignByPK(that.client.WxPublicKey())
if err != nil {
//xlog.Error(err)
return nil, err
}
// ========异步通知敏感信息解密========
// 普通支付通知解密
result, err := notifyReq.DecryptCipherText(that.apiV3Key)
//that.client.V3TransactionQueryOrder(that.ctx,result.BankType,result.OR)
return result, err
// 合单支付通知解密
//result, err := notifyReq.DecryptCombineCipherText(apiV3Key)
//// 退款通知解密
//result, err := notifyReq.DecryptRefundCipherText(apiV3Key)
// ========异步通知应答========
// 退款通知http应答码为200且返回状态码为SUCCESS才会当做商户接收成功否则会重试。
// 注意:重试过多会导致微信支付端积压过多通知而堵塞,影响其他正常通知。
// 此写法是 gin 框架返回微信的写法
//c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"})
//
//// 此写法是 echo 框架返回微信的写法
//return c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"})
}
// GetUserInfo 获取用户信息
//func (that *wxpay) GetMiniOrder(money int64,appid,name,tradeNo,notifyUrl string) (jsApiParams *wechat.AppletParams,err error){
//
// PrepayId,err:=that.getPrepayId(money,name,tradeNo,notifyUrl)
// if err!=nil{
// return nil,err
// }
//
// //小程序
// applet, err := that.client.PaySignOfApplet(appid,PrepayId)
//
// return applet,err
//}
func (that *wxpay) getPrepayId(money int64, appid, mchid, openid, name, tradeNo, notifyUrl string) (prepayid string, err error) {
expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
// 初始化 BodyMap
bm := make(gopay.BodyMap)
bm.Set("appid", appid).
Set("mchid", mchid).
//Set("sub_mchid", "sub_mchid").
Set("description", name).
Set("out_trade_no", tradeNo).
Set("time_expire", expire).
Set("notify_url", notifyUrl).
SetBodyMap("amount", func(bm gopay.BodyMap) {
bm.Set("total", money).
Set("currency", "CNY")
}).
SetBodyMap("payer", func(bm gopay.BodyMap) {
bm.Set("openid", openid)
})
//ctx:=context.Context()
wxRsp, err := that.client.V3TransactionJsapi(that.ctx, bm)
fmt.Println("获取PrepayId", wxRsp, err)
if err != nil {
//xlog.Error(err)
return "", err
}
return wxRsp.Response.PrepayId, nil
}

View File

@ -1,160 +0,0 @@
package admin
import (
. "../../../hotime"
. "../../../hotime/common"
"strings"
)
var adminCtr = Ctr{
"info": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info(that.RouterString[1], data, that.Db)
where := Map{"id": that.RouterString[2]}
if len(inData) == 1 {
inData["id"] = where["id"]
where = Map{"AND": inData}
} else if len(inData) > 1 {
where["OR"] = inData
where = Map{"AND": where}
}
re := that.Db.Get(that.RouterString[1], str, where)
if re == nil {
that.Display(4, "找不到对应信息")
return
}
for k, v := range re {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if (column["list"] == nil || column.GetBool("list")) && column.GetString("link") != "" {
re[column.GetString("link")] = that.Db.Get(column.GetString("link"), "id,"+column.GetString("value"), Map{"id": v})
}
}
that.Display(0, re)
},
"add": func(that *Context) {
inData := that.MakeCode.Add(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := that.Db.Insert(that.RouterString[1], inData)
if re == 0 {
that.Display(4, "无法插入对应数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = index.GetString("index") + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
} else if inData.GetString("index") != "" {
inData["index"] = "," + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
}
that.Display(0, re)
},
"update": func(that *Context) {
inData := that.MakeCode.Edit(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "没有找到要更新的数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
Index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": that.RouterString[2]})
parentIndex := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = parentIndex.GetString("index") + that.RouterString[2] + ","
childNodes := that.Db.Select(that.RouterString[1], "id,`index`", Map{"index[~]": "," + that.RouterString[2] + ","})
for _, v := range childNodes {
v["index"] = strings.Replace(v.GetString("index"), Index.GetString("index"), inData.GetString("index"), -1)
that.Db.Update(that.RouterString[1], Map{"index": v["index"]}, Map{"id": v.GetCeilInt("id")})
}
}
re := that.Db.Update(that.RouterString[1], inData, Map{"id": that.RouterString[2]})
if re == 0 {
that.Display(4, "更新数据失败")
return
}
that.Display(0, re)
},
"remove": func(that *Context) {
inData := that.MakeCode.Delete(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := int64(0)
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetSlice("index") != nil {
re = that.Db.Delete(that.RouterString[1], Map{"index[~]": "," + that.RouterString[2] + ","})
} else {
re = that.Db.Delete(that.RouterString[1], Map{"id": that.RouterString[2]})
}
if re == 0 {
that.Display(4, "删除数据失败")
return
}
that.Display(0, "删除成功")
},
"search": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
columnStr, leftJoin, where := that.MakeCode.Search(that.RouterString[1], data, that.Req, that.Db)
page := ObjToInt(that.Req.FormValue("page"))
pageSize := ObjToInt(that.Req.FormValue("pageSize"))
if page < 1 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
count := that.Db.Count(that.RouterString[1], leftJoin, where)
reData := that.Db.Page(page, pageSize).
PageSelect(that.RouterString[1], leftJoin, columnStr, where)
for _, v := range reData {
for k, _ := range v {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if column["list"] != false && column["name"] == "parent_id" && column.GetString("link") != "" {
parentC := that.Db.Get(column.GetString("link"), column.GetString("value"), Map{"id": v.GetCeilInt(k)})
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = ""
if parentC != nil {
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = parentC.GetString(column.GetString("value"))
}
}
}
}
that.Display(0, Map{"count": count, "data": reData})
},
}

View File

@ -1,160 +0,0 @@
package admin
import (
. "../../../hotime"
. "../../../hotime/common"
"strings"
)
var categoryCtr = Ctr{
"info": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info(that.RouterString[1], data, that.Db)
where := Map{"id": that.RouterString[2]}
if len(inData) == 1 {
inData["id"] = where["id"]
where = Map{"AND": inData}
} else if len(inData) > 1 {
where["OR"] = inData
where = Map{"AND": where}
}
re := that.Db.Get(that.RouterString[1], str, where)
if re == nil {
that.Display(4, "找不到对应信息")
return
}
for k, v := range re {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if (column["list"] == nil || column.GetBool("list")) && column.GetString("link") != "" {
re[column.GetString("link")] = that.Db.Get(column.GetString("link"), "id,"+column.GetString("value"), Map{"id": v})
}
}
that.Display(0, re)
},
"add": func(that *Context) {
inData := that.MakeCode.Add(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := that.Db.Insert(that.RouterString[1], inData)
if re == 0 {
that.Display(4, "无法插入对应数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = index.GetString("index") + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
} else if inData.GetString("index") != "" {
inData["index"] = "," + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
}
that.Display(0, re)
},
"update": func(that *Context) {
inData := that.MakeCode.Edit(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "没有找到要更新的数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
Index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": that.RouterString[2]})
parentIndex := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = parentIndex.GetString("index") + that.RouterString[2] + ","
childNodes := that.Db.Select(that.RouterString[1], "id,`index`", Map{"index[~]": "," + that.RouterString[2] + ","})
for _, v := range childNodes {
v["index"] = strings.Replace(v.GetString("index"), Index.GetString("index"), inData.GetString("index"), -1)
that.Db.Update(that.RouterString[1], Map{"index": v["index"]}, Map{"id": v.GetCeilInt("id")})
}
}
re := that.Db.Update(that.RouterString[1], inData, Map{"id": that.RouterString[2]})
if re == 0 {
that.Display(4, "更新数据失败")
return
}
that.Display(0, re)
},
"remove": func(that *Context) {
inData := that.MakeCode.Delete(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := int64(0)
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetSlice("index") != nil {
re = that.Db.Delete(that.RouterString[1], Map{"index[~]": "," + that.RouterString[2] + ","})
} else {
re = that.Db.Delete(that.RouterString[1], Map{"id": that.RouterString[2]})
}
if re == 0 {
that.Display(4, "删除数据失败")
return
}
that.Display(0, "删除成功")
},
"search": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
columnStr, leftJoin, where := that.MakeCode.Search(that.RouterString[1], data, that.Req, that.Db)
page := ObjToInt(that.Req.FormValue("page"))
pageSize := ObjToInt(that.Req.FormValue("pageSize"))
if page < 1 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
count := that.Db.Count(that.RouterString[1], leftJoin, where)
reData := that.Db.Page(page, pageSize).
PageSelect(that.RouterString[1], leftJoin, columnStr, where)
for _, v := range reData {
for k, _ := range v {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if column["list"] != false && column["name"] == "parent_id" && column.GetString("link") != "" {
parentC := that.Db.Get(column.GetString("link"), column.GetString("value"), Map{"id": v.GetCeilInt(k)})
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = ""
if parentC != nil {
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = parentC.GetString(column.GetString("value"))
}
}
}
}
that.Display(0, Map{"count": count, "data": reData})
},
}

View File

@ -1,160 +0,0 @@
package admin
import (
. "../../../hotime"
. "../../../hotime/common"
"strings"
)
var ctg_order_dateCtr = Ctr{
"info": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info(that.RouterString[1], data, that.Db)
where := Map{"id": that.RouterString[2]}
if len(inData) == 1 {
inData["id"] = where["id"]
where = Map{"AND": inData}
} else if len(inData) > 1 {
where["OR"] = inData
where = Map{"AND": where}
}
re := that.Db.Get(that.RouterString[1], str, where)
if re == nil {
that.Display(4, "找不到对应信息")
return
}
for k, v := range re {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if (column["list"] == nil || column.GetBool("list")) && column.GetString("link") != "" {
re[column.GetString("link")] = that.Db.Get(column.GetString("link"), "id,"+column.GetString("value"), Map{"id": v})
}
}
that.Display(0, re)
},
"add": func(that *Context) {
inData := that.MakeCode.Add(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := that.Db.Insert(that.RouterString[1], inData)
if re == 0 {
that.Display(4, "无法插入对应数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = index.GetString("index") + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
} else if inData.GetString("index") != "" {
inData["index"] = "," + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
}
that.Display(0, re)
},
"update": func(that *Context) {
inData := that.MakeCode.Edit(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "没有找到要更新的数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
Index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": that.RouterString[2]})
parentIndex := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = parentIndex.GetString("index") + that.RouterString[2] + ","
childNodes := that.Db.Select(that.RouterString[1], "id,`index`", Map{"index[~]": "," + that.RouterString[2] + ","})
for _, v := range childNodes {
v["index"] = strings.Replace(v.GetString("index"), Index.GetString("index"), inData.GetString("index"), -1)
that.Db.Update(that.RouterString[1], Map{"index": v["index"]}, Map{"id": v.GetCeilInt("id")})
}
}
re := that.Db.Update(that.RouterString[1], inData, Map{"id": that.RouterString[2]})
if re == 0 {
that.Display(4, "更新数据失败")
return
}
that.Display(0, re)
},
"remove": func(that *Context) {
inData := that.MakeCode.Delete(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := int64(0)
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetSlice("index") != nil {
re = that.Db.Delete(that.RouterString[1], Map{"index[~]": "," + that.RouterString[2] + ","})
} else {
re = that.Db.Delete(that.RouterString[1], Map{"id": that.RouterString[2]})
}
if re == 0 {
that.Display(4, "删除数据失败")
return
}
that.Display(0, "删除成功")
},
"search": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
columnStr, leftJoin, where := that.MakeCode.Search(that.RouterString[1], data, that.Req, that.Db)
page := ObjToInt(that.Req.FormValue("page"))
pageSize := ObjToInt(that.Req.FormValue("pageSize"))
if page < 1 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
count := that.Db.Count(that.RouterString[1], leftJoin, where)
reData := that.Db.Page(page, pageSize).
PageSelect(that.RouterString[1], leftJoin, columnStr, where)
for _, v := range reData {
for k, _ := range v {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if column["list"] != false && column["name"] == "parent_id" && column.GetString("link") != "" {
parentC := that.Db.Get(column.GetString("link"), column.GetString("value"), Map{"id": v.GetCeilInt(k)})
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = ""
if parentC != nil {
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = parentC.GetString(column.GetString("value"))
}
}
}
}
that.Display(0, Map{"count": count, "data": reData})
},
}

View File

@ -1,72 +0,0 @@
package admin
import (
. "../../../hotime"
. "../../../hotime/common"
)
var ID = "ede7cc05f2e6c63b4572883f4b9a9853"
// Project 管理端项目
var Project = Proj{
//"user": UserCtr,
"admin": adminCtr,
"category": categoryCtr,
"ctg_order_date": ctg_order_dateCtr,
"order": orderCtr,
"org": orgCtr,
"role": roleCtr,
"user": userCtr,
"hotime": Ctr{
"login": func(this *Context) {
name := this.Req.FormValue("name")
password := this.Req.FormValue("password")
if name == "" || password == "" {
this.Display(3, "参数不足")
return
}
user := this.Db.Get("admin", "*", Map{"AND": Map{"OR": Map{"name": name, "phone": name}, "password": Md5(password)}})
if user == nil {
this.Display(5, "登录失败")
return
}
this.Session("admin_id", user.GetCeilInt("id"))
this.Session("admin_name", name)
this.Display(0, this.SessionId)
},
"logout": func(this *Context) {
this.Session("admin_id", nil)
this.Session("admin_name", nil)
this.Display(0, "退出登录成功")
},
"info": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info("admin", data, that.Db)
where := Map{"id": that.Session("admin_id").ToCeilInt()}
if len(inData) == 1 {
inData["id"] = where["id"]
where = Map{"AND": inData}
} else if len(inData) > 1 {
where["OR"] = inData
where = Map{"AND": where}
}
re := that.Db.Get("admin", str, where)
if re == nil {
that.Display(4, "找不到对应信息")
return
}
for k, v := range re {
column := that.MakeCode.TableColumns["admin"][k]
if column == nil {
continue
}
if (column["list"] == nil || column.GetBool("list")) && column.GetString("link") != "" {
re[column.GetString("link")] = that.Db.Get(column.GetString("link"), "id,"+column.GetString("value"), Map{"id": v})
}
}
that.Display(0, re)
},
},
}

View File

@ -1,160 +0,0 @@
package admin
import (
. "../../../hotime"
. "../../../hotime/common"
"strings"
)
var orderCtr = Ctr{
"info": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info(that.RouterString[1], data, that.Db)
where := Map{"id": that.RouterString[2]}
if len(inData) == 1 {
inData["id"] = where["id"]
where = Map{"AND": inData}
} else if len(inData) > 1 {
where["OR"] = inData
where = Map{"AND": where}
}
re := that.Db.Get(that.RouterString[1], str, where)
if re == nil {
that.Display(4, "找不到对应信息")
return
}
for k, v := range re {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if (column["list"] == nil || column.GetBool("list")) && column.GetString("link") != "" {
re[column.GetString("link")] = that.Db.Get(column.GetString("link"), "id,"+column.GetString("value"), Map{"id": v})
}
}
that.Display(0, re)
},
"add": func(that *Context) {
inData := that.MakeCode.Add(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := that.Db.Insert(that.RouterString[1], inData)
if re == 0 {
that.Display(4, "无法插入对应数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = index.GetString("index") + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
} else if inData.GetString("index") != "" {
inData["index"] = "," + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
}
that.Display(0, re)
},
"update": func(that *Context) {
inData := that.MakeCode.Edit(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "没有找到要更新的数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
Index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": that.RouterString[2]})
parentIndex := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = parentIndex.GetString("index") + that.RouterString[2] + ","
childNodes := that.Db.Select(that.RouterString[1], "id,`index`", Map{"index[~]": "," + that.RouterString[2] + ","})
for _, v := range childNodes {
v["index"] = strings.Replace(v.GetString("index"), Index.GetString("index"), inData.GetString("index"), -1)
that.Db.Update(that.RouterString[1], Map{"index": v["index"]}, Map{"id": v.GetCeilInt("id")})
}
}
re := that.Db.Update(that.RouterString[1], inData, Map{"id": that.RouterString[2]})
if re == 0 {
that.Display(4, "更新数据失败")
return
}
that.Display(0, re)
},
"remove": func(that *Context) {
inData := that.MakeCode.Delete(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := int64(0)
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetSlice("index") != nil {
re = that.Db.Delete(that.RouterString[1], Map{"index[~]": "," + that.RouterString[2] + ","})
} else {
re = that.Db.Delete(that.RouterString[1], Map{"id": that.RouterString[2]})
}
if re == 0 {
that.Display(4, "删除数据失败")
return
}
that.Display(0, "删除成功")
},
"search": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
columnStr, leftJoin, where := that.MakeCode.Search(that.RouterString[1], data, that.Req, that.Db)
page := ObjToInt(that.Req.FormValue("page"))
pageSize := ObjToInt(that.Req.FormValue("pageSize"))
if page < 1 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
count := that.Db.Count(that.RouterString[1], leftJoin, where)
reData := that.Db.Page(page, pageSize).
PageSelect(that.RouterString[1], leftJoin, columnStr, where)
for _, v := range reData {
for k, _ := range v {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if column["list"] != false && column["name"] == "parent_id" && column.GetString("link") != "" {
parentC := that.Db.Get(column.GetString("link"), column.GetString("value"), Map{"id": v.GetCeilInt(k)})
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = ""
if parentC != nil {
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = parentC.GetString(column.GetString("value"))
}
}
}
}
that.Display(0, Map{"count": count, "data": reData})
},
}

View File

@ -1,160 +0,0 @@
package admin
import (
. "../../../hotime"
. "../../../hotime/common"
"strings"
)
var orgCtr = Ctr{
"info": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info(that.RouterString[1], data, that.Db)
where := Map{"id": that.RouterString[2]}
if len(inData) == 1 {
inData["id"] = where["id"]
where = Map{"AND": inData}
} else if len(inData) > 1 {
where["OR"] = inData
where = Map{"AND": where}
}
re := that.Db.Get(that.RouterString[1], str, where)
if re == nil {
that.Display(4, "找不到对应信息")
return
}
for k, v := range re {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if (column["list"] == nil || column.GetBool("list")) && column.GetString("link") != "" {
re[column.GetString("link")] = that.Db.Get(column.GetString("link"), "id,"+column.GetString("value"), Map{"id": v})
}
}
that.Display(0, re)
},
"add": func(that *Context) {
inData := that.MakeCode.Add(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := that.Db.Insert(that.RouterString[1], inData)
if re == 0 {
that.Display(4, "无法插入对应数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = index.GetString("index") + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
} else if inData.GetString("index") != "" {
inData["index"] = "," + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
}
that.Display(0, re)
},
"update": func(that *Context) {
inData := that.MakeCode.Edit(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "没有找到要更新的数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
Index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": that.RouterString[2]})
parentIndex := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = parentIndex.GetString("index") + that.RouterString[2] + ","
childNodes := that.Db.Select(that.RouterString[1], "id,`index`", Map{"index[~]": "," + that.RouterString[2] + ","})
for _, v := range childNodes {
v["index"] = strings.Replace(v.GetString("index"), Index.GetString("index"), inData.GetString("index"), -1)
that.Db.Update(that.RouterString[1], Map{"index": v["index"]}, Map{"id": v.GetCeilInt("id")})
}
}
re := that.Db.Update(that.RouterString[1], inData, Map{"id": that.RouterString[2]})
if re == 0 {
that.Display(4, "更新数据失败")
return
}
that.Display(0, re)
},
"remove": func(that *Context) {
inData := that.MakeCode.Delete(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := int64(0)
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetSlice("index") != nil {
re = that.Db.Delete(that.RouterString[1], Map{"index[~]": "," + that.RouterString[2] + ","})
} else {
re = that.Db.Delete(that.RouterString[1], Map{"id": that.RouterString[2]})
}
if re == 0 {
that.Display(4, "删除数据失败")
return
}
that.Display(0, "删除成功")
},
"search": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
columnStr, leftJoin, where := that.MakeCode.Search(that.RouterString[1], data, that.Req, that.Db)
page := ObjToInt(that.Req.FormValue("page"))
pageSize := ObjToInt(that.Req.FormValue("pageSize"))
if page < 1 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
count := that.Db.Count(that.RouterString[1], leftJoin, where)
reData := that.Db.Page(page, pageSize).
PageSelect(that.RouterString[1], leftJoin, columnStr, where)
for _, v := range reData {
for k, _ := range v {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if column["list"] != false && column["name"] == "parent_id" && column.GetString("link") != "" {
parentC := that.Db.Get(column.GetString("link"), column.GetString("value"), Map{"id": v.GetCeilInt(k)})
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = ""
if parentC != nil {
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = parentC.GetString(column.GetString("value"))
}
}
}
}
that.Display(0, Map{"count": count, "data": reData})
},
}

View File

@ -1,160 +0,0 @@
package admin
import (
. "../../../hotime"
. "../../../hotime/common"
"strings"
)
var roleCtr = Ctr{
"info": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info(that.RouterString[1], data, that.Db)
where := Map{"id": that.RouterString[2]}
if len(inData) == 1 {
inData["id"] = where["id"]
where = Map{"AND": inData}
} else if len(inData) > 1 {
where["OR"] = inData
where = Map{"AND": where}
}
re := that.Db.Get(that.RouterString[1], str, where)
if re == nil {
that.Display(4, "找不到对应信息")
return
}
for k, v := range re {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if (column["list"] == nil || column.GetBool("list")) && column.GetString("link") != "" {
re[column.GetString("link")] = that.Db.Get(column.GetString("link"), "id,"+column.GetString("value"), Map{"id": v})
}
}
that.Display(0, re)
},
"add": func(that *Context) {
inData := that.MakeCode.Add(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := that.Db.Insert(that.RouterString[1], inData)
if re == 0 {
that.Display(4, "无法插入对应数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = index.GetString("index") + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
} else if inData.GetString("index") != "" {
inData["index"] = "," + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
}
that.Display(0, re)
},
"update": func(that *Context) {
inData := that.MakeCode.Edit(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "没有找到要更新的数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
Index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": that.RouterString[2]})
parentIndex := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = parentIndex.GetString("index") + that.RouterString[2] + ","
childNodes := that.Db.Select(that.RouterString[1], "id,`index`", Map{"index[~]": "," + that.RouterString[2] + ","})
for _, v := range childNodes {
v["index"] = strings.Replace(v.GetString("index"), Index.GetString("index"), inData.GetString("index"), -1)
that.Db.Update(that.RouterString[1], Map{"index": v["index"]}, Map{"id": v.GetCeilInt("id")})
}
}
re := that.Db.Update(that.RouterString[1], inData, Map{"id": that.RouterString[2]})
if re == 0 {
that.Display(4, "更新数据失败")
return
}
that.Display(0, re)
},
"remove": func(that *Context) {
inData := that.MakeCode.Delete(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := int64(0)
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetSlice("index") != nil {
re = that.Db.Delete(that.RouterString[1], Map{"index[~]": "," + that.RouterString[2] + ","})
} else {
re = that.Db.Delete(that.RouterString[1], Map{"id": that.RouterString[2]})
}
if re == 0 {
that.Display(4, "删除数据失败")
return
}
that.Display(0, "删除成功")
},
"search": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
columnStr, leftJoin, where := that.MakeCode.Search(that.RouterString[1], data, that.Req, that.Db)
page := ObjToInt(that.Req.FormValue("page"))
pageSize := ObjToInt(that.Req.FormValue("pageSize"))
if page < 1 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
count := that.Db.Count(that.RouterString[1], leftJoin, where)
reData := that.Db.Page(page, pageSize).
PageSelect(that.RouterString[1], leftJoin, columnStr, where)
for _, v := range reData {
for k, _ := range v {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if column["list"] != false && column["name"] == "parent_id" && column.GetString("link") != "" {
parentC := that.Db.Get(column.GetString("link"), column.GetString("value"), Map{"id": v.GetCeilInt(k)})
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = ""
if parentC != nil {
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = parentC.GetString(column.GetString("value"))
}
}
}
}
that.Display(0, Map{"count": count, "data": reData})
},
}

View File

@ -1,160 +0,0 @@
package admin
import (
. "../../../hotime"
. "../../../hotime/common"
"strings"
)
var userCtr = Ctr{
"info": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
str, inData := that.MakeCode.Info(that.RouterString[1], data, that.Db)
where := Map{"id": that.RouterString[2]}
if len(inData) == 1 {
inData["id"] = where["id"]
where = Map{"AND": inData}
} else if len(inData) > 1 {
where["OR"] = inData
where = Map{"AND": where}
}
re := that.Db.Get(that.RouterString[1], str, where)
if re == nil {
that.Display(4, "找不到对应信息")
return
}
for k, v := range re {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if (column["list"] == nil || column.GetBool("list")) && column.GetString("link") != "" {
re[column.GetString("link")] = that.Db.Get(column.GetString("link"), "id,"+column.GetString("value"), Map{"id": v})
}
}
that.Display(0, re)
},
"add": func(that *Context) {
inData := that.MakeCode.Add(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := that.Db.Insert(that.RouterString[1], inData)
if re == 0 {
that.Display(4, "无法插入对应数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = index.GetString("index") + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
} else if inData.GetString("index") != "" {
inData["index"] = "," + ObjToStr(re) + ","
that.Db.Update(that.RouterString[1], Map{"index": inData["index"]}, Map{"id": re})
}
that.Display(0, re)
},
"update": func(that *Context) {
inData := that.MakeCode.Edit(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "没有找到要更新的数据")
return
}
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetString("index") != "" {
Index := that.Db.Get(that.RouterString[1], "`index`", Map{"id": that.RouterString[2]})
parentIndex := that.Db.Get(that.RouterString[1], "`index`", Map{"id": inData.Get("parent_id")})
inData["index"] = parentIndex.GetString("index") + that.RouterString[2] + ","
childNodes := that.Db.Select(that.RouterString[1], "id,`index`", Map{"index[~]": "," + that.RouterString[2] + ","})
for _, v := range childNodes {
v["index"] = strings.Replace(v.GetString("index"), Index.GetString("index"), inData.GetString("index"), -1)
that.Db.Update(that.RouterString[1], Map{"index": v["index"]}, Map{"id": v.GetCeilInt("id")})
}
}
re := that.Db.Update(that.RouterString[1], inData, Map{"id": that.RouterString[2]})
if re == 0 {
that.Display(4, "更新数据失败")
return
}
that.Display(0, re)
},
"remove": func(that *Context) {
inData := that.MakeCode.Delete(that.RouterString[1], that.Req)
if inData == nil {
that.Display(3, "请求参数不足")
return
}
re := int64(0)
//索引管理,便于检索以及权限
if inData.Get("parent_id") != nil && inData.GetSlice("index") != nil {
re = that.Db.Delete(that.RouterString[1], Map{"index[~]": "," + that.RouterString[2] + ","})
} else {
re = that.Db.Delete(that.RouterString[1], Map{"id": that.RouterString[2]})
}
if re == 0 {
that.Display(4, "删除数据失败")
return
}
that.Display(0, "删除成功")
},
"search": func(that *Context) {
data := that.Db.Get("admin", "*", Map{"id": that.Session("admin_id").ToCeilInt()})
columnStr, leftJoin, where := that.MakeCode.Search(that.RouterString[1], data, that.Req, that.Db)
page := ObjToInt(that.Req.FormValue("page"))
pageSize := ObjToInt(that.Req.FormValue("pageSize"))
if page < 1 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
count := that.Db.Count(that.RouterString[1], leftJoin, where)
reData := that.Db.Page(page, pageSize).
PageSelect(that.RouterString[1], leftJoin, columnStr, where)
for _, v := range reData {
for k, _ := range v {
column := that.MakeCode.TableColumns[that.RouterString[1]][k]
if column == nil {
continue
}
if column["list"] != false && column["name"] == "parent_id" && column.GetString("link") != "" {
parentC := that.Db.Get(column.GetString("link"), column.GetString("value"), Map{"id": v.GetCeilInt(k)})
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = ""
if parentC != nil {
v[column.GetString("link")+"_"+column.GetString("name")+"_"+column.GetString("value")] = parentC.GetString(column.GetString("value"))
}
}
}
}
that.Display(0, Map{"count": count, "data": reData})
},
}

View File

@ -1,34 +0,0 @@
package app
import (
. "../../../hotime"
. "../../../hotime/common"
)
var categoryCtr = Ctr{
"info": func(that *Context) {
parentId := ObjToInt(that.Req.FormValue("id"))
//parentId := ObjToInt(that.RouterString[2])
childData := []Map{}
if parentId == 0 {
childData1 := that.Db.Select("category", "*", Map{"parent_id": nil})
for _, v := range childData1 {
data := that.Db.Get("category", "*", Map{"parent_id": v.GetCeilInt("id")})
if data != nil {
childData = append(childData, data)
}
}
} else {
childData = that.Db.Select("category", "*", Map{"parent_id": parentId})
}
for _, v := range childData {
v["child"] = that.Db.Select("category", "*", Map{"parent_id": v.GetCeilInt("id")})
}
that.Display(0, childData)
},
}

View File

@ -1,103 +0,0 @@
package app
import (
. "../../../hotime"
. "../../../hotime/common"
"time"
)
var ctg_order_dateCtr = Ctr{
"info": func(that *Context) {
//today:=time.Now().Weekday()
id := ObjToInt(that.Req.FormValue("id"))
category := that.Db.Get("category", "*", Map{"id": id})
if category == nil {
that.Display(4, "找不到该类别!")
return
}
todayPMTime, _ := time.ParseInLocation("2006-01-02 15:04", time.Now().Format("2006-01-02")+" 14:00", time.Local)
todayAMTime, _ := time.ParseInLocation("2006-01-02 15:04", time.Now().Format("2006-01-02")+" 09:00", time.Local)
weekDay := 1
switch time.Now().Weekday().String() {
case "Monday":
weekDay = 1
case "Tuesday":
weekDay = 2
case "Wednesday":
weekDay = 3
case "Thursday":
weekDay = 4
case "Friday":
weekDay = 5
case "Saturday":
weekDay = 6
case "Sunday":
weekDay = 7
}
////future:=that.Db.Select("ctg_order_date","*",Map{"category_id":that.RouterString[2],"date[>]":time})
date := Slice{}
for i := 0; i < 7; i++ {
day := weekDay + i + 1
if day > 7 {
day = day - 7
}
if day == 6 || day == 7 {
continue
}
//fmt.Println(todayAMTime.Unix() + int64(24*60*60*(i+1)))
dayAM := that.Db.Get("ctg_order_date", "*", Map{"AND": Map{"category_id": category.GetCeilInt("id"),
"date": todayAMTime.Unix() + int64(24*60*60*(i+1))}})
if dayAM == nil {
dayAM = Map{"name": "9:00-11:30",
"date": todayAMTime.Unix() + int64(24*60*60*(i+1)),
"create_time": time.Now().Unix(),
"modify_time": time.Now().Unix(),
"start_sn": category.GetCeilInt("start_sn"),
"max_sn": category.GetCeilInt("start_sn") + category.GetCeilInt("am"+ObjToStr(day)),
"now_sn": category.GetCeilInt("start_sn"),
"category_id": category.GetCeilInt("id"),
}
dayAM["id"] = that.Db.Insert("ctg_order_date", dayAM)
if dayAM.GetCeilInt64("id") == 0 {
that.Display(4, "内部错误!")
return
}
}
dayPM := that.Db.Get("ctg_order_date", "*", Map{"AND": Map{"category_id": category.GetCeilInt("id"), "date": todayPMTime.Unix() + int64(24*60*60*(i+1))}})
//fmt.Println(that.Db.LastQuery, that.Db.LastData, dayPM, that.Db.LastErr)
if dayPM == nil {
//fmt.Println("dasdasdasda")
dayPM = Map{"name": "13:30-16:30",
"date": todayPMTime.Unix() + int64(24*60*60*(i+1)),
"create_time": time.Now().Unix(),
"modify_time": time.Now().Unix(),
"start_sn": category.GetCeilInt("start_sn"),
"max_sn": category.GetCeilInt("start_sn") + category.GetCeilInt("pm"+ObjToStr(day)),
"now_sn": category.GetCeilInt("start_sn"),
"category_id": category.GetCeilInt("id"),
}
dayPM["id"] = that.Db.Insert("ctg_order_date", dayPM)
if dayPM.GetCeilInt64("id") == 0 {
that.Display(4, "内部错误!")
return
}
}
date = append(date, Map{"name": "星期" + ObjToStr(day) + "(" + time.Unix(todayPMTime.Unix()+int64(24*60*60*(i+1)), 0).Format("01-02") + ")",
"am": dayAM,
"pm": dayPM,
})
}
that.Display(0, date)
},
}

View File

@ -1,121 +0,0 @@
package app
import (
. "../../../hotime"
. "../../../hotime/common"
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/pem"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"time"
)
// Project 管理端项目
var Project = Proj{
//"user": UserCtr,
"category": categoryCtr,
"ctg_order_date": ctg_order_dateCtr,
"order": orderCtr,
"user": userCtr,
"sms": Sms,
}
//生成随机码的4位随机数
func getCode() string {
//res := ""
//for i := 0; i < 4; i++ {
res := ObjToStr(RandX(1000, 9999))
//}
return res
}
func tencentSendYzm(umobile, code string) error {
random := RandX(999999, 9999999)
url := "https://yun.tim.qq.com/v5/tlssmssvr/sendsms?sdkappid=1400235813&random=" + ObjToStr(random)
fmt.Println("URL:>", url)
h := sha256.New()
h.Write([]byte(`appkey=d511de15e5ccb43fc171772dbb8b599f&random=` + ObjToStr(random) + `&time=` + ObjToStr(time.Now().Unix()) + `&mobile=` + umobile))
bs := h.Sum(nil)
s256 := hex.EncodeToString(bs)
//json序列化
post := `{
"ext": "",
"extend": "",
"params": [
"` + code + `"
],
"sig": "` + s256 + `",
"sign": "乐呵呵旅游网",
"tel": {
"mobile": "` + umobile + `",
"nationcode": "86"
},
"time": ` + ObjToStr(time.Now().Unix()) + `,
"tpl_id": 378916
}`
fmt.Println(url, "post", post)
var jsonStr = []byte(post)
fmt.Println("jsonStr", jsonStr)
fmt.Println("new_str", bytes.NewBuffer(jsonStr))
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
// req.Header.Set("X-Custom-Header", "myvalue")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Println("response Status:", resp.Status)
fmt.Println("response Headers:", resp.Header)
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response Body:", string(body))
return nil
}
var privateKey = `-----BEGIN RSA Private Key-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJJuFUH/4m9H5hCCzxtd9BxpjWlG9gbejqiJpV0XJKaU1V7xDBJasswxPY7Zc15RoxWClPoKPwKrbWKm49dgBJebJq5xd4sLCSbboxRkKxpRiJHMZ4LJjYa5h9Ei9RyfoUzqGHqH4UrDy3m3IwPiP19cIBqoU50shyQf92ZpcGZhAgMBAAECgYEAiadU8pODoUs82x6tZbPALQmJN4PO+wwznfqv6sA74yGdKECAMazz0oMjtGt1SiCCqFD2jcweCftvvELZg3mvNg1V0vRQRD1ZCA8HDp8DXm20d11K3+RX39tR4KgyyM3HsSEhkUDujMxKIpYjyiB5iEtV7Ja9bZ2fROszq+mUIqUCQQDQQf6vWRMLBqfnDcU77vuDGOhXbjkF2ytLxLW3fbKaW3GWvC3n93zPM+mcvWSXgkl448+jFjpMktm1Vn+w+YX3AkEAs/+bbRbod6AcVbLu8C5E44qDRoRpu+LF7Cphp8tlSAIRjm2yGP5acMWGRUtH9MF2QJYPF0PgDzdmUSVqWnCAZwJBALnSuRri4wAKn1SmT+ALfLZcSiyBODZGeppv2ijw6qWahH8YR+ncRaxoyMFHqPMbmM1akJIXqktbGREaLnPOIb8CQQCdJycJaL3Qa98xR4dr9cm5rF6PO96g5w6M8jfO6ztjUkMHymh7f99wpFRlvaN2Y06edyV315ARWPohEPy5N44zAkBlLuDHLm1TkTTAfdlL5r2OcdjpaJYloTdn05Mp3+J+w1zTX8k6Mz8lFZtLUcoMeTfQ9rm/+u2KwxS8NljtSZWH
-----END RSA Private Key-----
`
func RSA_Decrypt(cipherTextBase64 string) string {
cipherText, _ := base64.StdEncoding.DecodeString(cipherTextBase64)
buf := []byte(privateKey)
//pem解码
block, _ := pem.Decode(buf)
//X509解码
private, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return ""
}
//对密文进行解密
//plainText,_:=rsa.DecryptPKCS1v15(rand.Reader,privateKey,cipherText)
v, err := rsa.DecryptPKCS1v15(rand.Reader, private.(*rsa.PrivateKey), cipherText)
if err != nil {
return ""
}
//返回明文
v1, err1 := url.QueryUnescape(string(v))
if err1 != nil {
return ""
}
return v1
}

View File

@ -1,99 +0,0 @@
package app
import (
. "../../../hotime"
. "../../../hotime/common"
"../../dri/ddsms"
"time"
)
var orderCtr = Ctr{
"count": func(this *Context) {
if this.Session("id").ToCeilInt() == 0 {
this.Display(2, "没有登录!")
return
}
re := Map{}
re["total"] = this.Db.Count("order", Map{"user_id": this.Session("id").ToCeilInt()})
re["finish"] = this.Db.Count("order", Map{"AND": Map{"user_id": this.Session("id").ToCeilInt(), "status": 2}})
re["late"] = this.Db.Count("order", Map{"AND": Map{"user_id": this.Session("id").ToCeilInt(), "status": 3}})
this.Display(0, re)
},
"add": func(this *Context) {
if this.Session("id").ToCeilInt() == 0 {
this.Display(2, "没有登录!")
return
}
ctgOrderDateId := ObjToInt(this.Req.FormValue("ctg_order_date_id"))
//ctgId:=ObjToInt(this.Req.FormValue("category_id"))
ctgOrderDate := this.Db.Get("ctg_order_date", "*", Map{"id": ctgOrderDateId})
if ctgOrderDate.GetCeilInt64("now_sn")+1 > ctgOrderDate.GetCeilInt64("max_sn") {
this.Display(5, "当前排号已经用完")
return
}
data := Map{"create_time": time.Now().Unix(),
"modify_time": time.Now().Unix(),
"user_id": this.Session("id").ToCeilInt(),
"date": ctgOrderDate.GetString("date"),
"sn": ctgOrderDate.GetCeilInt64("now_sn") + 1,
"category_id": ctgOrderDate.GetCeilInt("category_id"),
"admin_id": 1,
"status": 1,
"name": time.Unix(ctgOrderDate.GetCeilInt64("date"), 0).Format("2006-01-02 ") + ctgOrderDate.GetString("name"),
}
data["id"] = this.Db.Insert("order", data)
if data.GetCeilInt("id") == 0 {
this.Display(5, "预约失败")
return
}
this.Db.Update("ctg_order_date", Map{"now_sn": ctgOrderDate.GetCeilInt64("now_sn") + 1, "modify_time": time.Now().Unix()}, Map{"id": ctgOrderDate.GetCeilInt("id")})
//查询并发送短信
category := this.Db.Get("category", "`name`,`index`", Map{"id": ctgOrderDate.GetCeilInt("category_id")})
//categorys := this.Db.Select("category", "org_id", Map{"index[~]": "," + ctgOrderDate.GetString("category_id") + ","})
categorys := this.Db.Select("category", "org_id", Map{"[#]": "id IN (" + category.GetString("index")[1:len(category.GetString("index"))-1] + ")"})
orgIDs := ""
for _, v := range categorys {
orgs := this.Db.Select("org", "id,`index`", Map{"id": v.GetCeilInt("org_id")})
for _, orgv := range orgs {
//orgIDs = append(orgIDs, orgv.GetCeilInt("id"))
orgIDs = orgIDs + orgv.GetString("index")[1:]
}
}
if len(orgIDs) != 0 {
orgIDs = orgIDs[0 : len(orgIDs)-1]
admin := this.Db.Select("admin", "phone,id", Map{"[#]": "org_id IN (" + orgIDs + ")"})
user := this.Db.Get("user", "name", Map{"id": this.Session("id").ToCeilInt()})
for _, v := range admin {
phone := v.GetString("phone")
if len(phone) == 11 {
ddsms.DefaultDDY.SendTz([]string{phone}, this.Config.GetString("smsNotice"),
map[string]string{"date": data.GetString("name"), "ctg": category.GetString("name"),
"name": user.GetString("name"),
"sn": data.GetString("sn"),
})
}
}
}
this.Display(0, data)
},
"search": func(that *Context) {
if that.Session("id").ToCeilInt() == 0 {
that.Display(2, "没有登录!")
return
}
data := that.Db.Select("order", "*", Map{"user_id": that.Session("id").ToCeilInt()})
for _, v := range data {
v["category"] = that.Db.Get("category", "*", Map{"id": v.GetCeilInt("category_id")})
v["parent_category"] = that.Db.Get("category", "id,name", Map{"id": v.GetMap("category").GetCeilInt("parent_id")})
}
that.Display(0, data)
},
}

View File

@ -1,33 +0,0 @@
package app
import (
. "../../../hotime"
"../../dri/ddsms"
)
var Sms = Ctr{
//只允许微信验证过的或者登录成功的发送短信
"send": func(this *Context) {
//if this.Session("uid").Data == nil && this.Session("wechatInfo").Data == nil {
// this.Display(2, "没有授权")
// return
//}
if len(this.Req.FormValue("token")) != 32 {
this.Display(2, "没有授权")
return
}
phone := this.Req.FormValue("phone")
if len(phone) < 11 {
this.Display(3, "手机号格式错误")
return
}
code := getCode()
this.Session("phone", phone)
this.Session("code", code)
ddsms.DefaultDDY.SendYZM(phone, this.Config.GetString("smsLogin"), map[string]string{"code": code})
this.Display(0, "发送成功")
},
}

View File

@ -1,94 +0,0 @@
package app
import (
. "../../../hotime"
. "../../../hotime/common"
"time"
)
var userCtr = Ctr{
"token": func(this *Context) {
this.Display(0, this.SessionId)
},
"test": func(this *Context) {
this.Session("id", 1)
},
//自带的登录
"login": func(this *Context) {
phone := RSA_Decrypt(this.Req.FormValue("phone"))
idcard := RSA_Decrypt(this.Req.FormValue("idcard"))
name := RSA_Decrypt(this.Req.FormValue("name"))
if len(phone) != 11 ||
len(idcard) != 18 ||
len(name) < 1 {
this.Display(3, "数据校验不通过")
}
user := this.Db.Get("user", "*", Map{"phone": phone})
if user == nil {
user = Map{"phone": phone, "idcard": idcard, "name": name, "create_time": time.Now().Unix(), "modify_time": time.Now().Unix()}
user["id"] = this.Db.Insert("user", user)
} else {
user["phone"] = phone
user["idcard"] = idcard
user["name"] = name
user["modify_time"] = time.Now().Unix()
re := this.Db.Update("user", user, Map{"id": user.GetCeilInt64("id")})
if re == 0 {
this.Display(4, "系统错误")
return
}
}
if user.GetCeilInt64("id") == 0 {
this.Display(5, "登录失败")
return
}
this.Session("id", user.GetCeilInt("id"))
this.Display(0, "登录成功")
},
"add": func(this *Context) {
if this.Req.FormValue("code") != this.Session("code").ToStr() ||
this.Req.FormValue("phone") != this.Session("phone").ToStr() {
this.Display(3, "短信验证不通过")
return
}
phone := this.Req.FormValue("phone")
idcard := this.Req.FormValue("idcard")
name := this.Req.FormValue("name")
user := this.Db.Get("user", "*", Map{"phone": phone})
if user == nil {
user = Map{"phone": phone, "idcard": idcard, "name": name, "create_time": time.Now().Unix(), "modify_time": time.Now().Unix()}
user["id"] = this.Db.Insert("user", user)
} else {
user["phone"] = phone
user["idcard"] = idcard
user["name"] = name
user["modify_time"] = time.Now().Unix()
re := this.Db.Update("user", user, Map{"id": user.GetCeilInt64("id")})
if re == 0 {
this.Display(4, "系统错误")
return
}
}
if user.GetCeilInt64("id") == 0 {
this.Display(5, "登录失败")
return
}
this.Session("id", user.GetCeilInt("id"))
this.Session("code", nil)
this.Display(0, "登录成功")
},
}

Binary file not shown.

472
example/config/admin.json Normal file
View File

@ -0,0 +1,472 @@
{
"flow": {
"admin": {
"sql": {
"role_id": "role_id"
},
"stop": false,
"table": "admin"
},
"article": {
"sql": {
"admin_id": "id"
},
"stop": false,
"table": "article"
},
"ctg": {
"sql": {
"admin_id": "id"
},
"stop": false,
"table": "ctg"
},
"ctg_article": {
"sql": {
"admin_id": "id"
},
"stop": false,
"table": "ctg_article"
},
"ctg_copy": {
"sql": {
"admin_id": "id"
},
"stop": false,
"table": "ctg_copy"
},
"logs": {
"sql": {
},
"stop": false,
"table": "logs"
},
"org": {
"sql": {
"admin_id": "id"
},
"stop": false,
"table": "org"
},
"role": {
"sql": {
"admin_id": "id",
"id": "role_id"
},
"stop": true,
"table": "role"
}
},
"id": "74a8a59407fa7d6c7fcdc85742dbae57",
"label": "HoTime管理平台",
"labelConfig": {
"add": "添加",
"delete": "删除",
"download": "下载清单",
"edit": "编辑",
"info": "查看详情",
"show": "开启"
},
"menus": [
{
"auth": [
"show"
],
"icon": "Setting",
"label": "ebw_news",
"menus": [
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_news",
"table": "ebw_news"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_news_addition_res",
"table": "ebw_news_addition_res"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_annex",
"table": "ebw_annex"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_customer",
"table": "ebw_customer"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_items",
"table": "ebw_items"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_res",
"table": "ebw_res"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_vote",
"table": "ebw_vote"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_vote_option",
"table": "ebw_vote_option"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_user",
"table": "ebw_user"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_attachment",
"table": "ebw_attachment"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_jobs",
"table": "ebw_jobs"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "ebw_vote_user",
"table": "ebw_vote_user"
}
],
"name": "sys:ebw"
},
{
"auth": [
"show"
],
"icon": "Setting",
"label": "系统管理",
"menus": [
{
"auth": [
"show",
"download"
],
"label": "日志管理",
"table": "logs"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "角色管理",
"table": "role"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "组织管理",
"table": "org"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "人员管理",
"table": "admin"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "文章管理",
"table": "article"
}
],
"name": "sys"
},
{
"auth": [
"show"
],
"icon": "Setting",
"label": "外部系统",
"menus": [
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "外部系统",
"table": "swiper_sys"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "顶部",
"table": "swiper_top"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "飘窗",
"table": "swiper_fly"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "底部",
"table": "swiper_bottom"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "中间",
"table": "swiper_center"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "关联专题",
"table": "swiper_point"
}
],
"name": "sys:swiper"
},
{
"auth": [
"show"
],
"icon": "Setting",
"label": "栏目管理",
"menus": [
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "栏目管理",
"table": "ctg"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "关联栏目",
"table": "ctg_article"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "栏目管理",
"table": "ctg_copy"
}
],
"name": "sys:ctg"
},
{
"auth": [
"show"
],
"icon": "Setting",
"label": "纪委信箱",
"menus": [
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "纪委信箱",
"table": "mail_discipline"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "总经理信箱",
"table": "mail"
},
{
"auth": [
"show",
"add",
"delete",
"edit",
"info",
"download"
],
"label": "党委书记信箱",
"table": "mail_part"
}
],
"name": "sys:mail"
}
],
"name": "admin",
"stop": [
"role",
"org"
]
}

5236
example/config/adminDB.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,8 @@
"cache": {
"db": {
"db": false,
"session": true
"session": true,
"timeout": 7200
},
"memory": {
"db": true,
@ -10,24 +11,22 @@
"timeout": 7200
}
},
"codeConfig": {
"admin": "config/app.json"
},
"codeConfig1": {
"admin": {
"config": "config/app.json",
"package": "admin",
"rule": "config/rule.json"
"codeConfig": [
{
"config": "config/admin.json",
"configDB": "config/adminDB.json",
"mode": 0,
"name": "",
"rule": "config/rule.json",
"table": "admin"
}
},
"crossDomain": "auto",
],
"db": {
"mysql": {
"host": "192.168.6.253",
"name": "bzyyweb",
"name": "dgs-cms",
"password": "dasda8454456",
"port": "3306",
"prefix": "",
"user": "root"
}
},
@ -43,10 +42,7 @@
"5": "数据结果异常"
},
"mode": 2,
"port": "80",
"port": "8081",
"sessionName": "HOTIME",
"smsKey": "b0eb4bf0198b9983cffcb85b69fdf4fa",
"smsLogin": "【恩易办】您的验证码为:{code}请在5分钟内使用切勿将验证码泄露于他人如非本人操作请忽略。",
"smsNotice": "【恩易办】你收到一条新的预约事项,{name}预约办理{ctg}事项,预约办理时间:{date},排号:{sn}。",
"tpt": "tpt"
}

View File

@ -20,10 +20,17 @@
},
"注释": "可配置memorydbredis默认启用memory默认优先级为memory\u003eredis\u003edb,memory与数据库缓存设置项一致缓存数据填充会自动反方向反哺加入memory缓存过期将自动从redis更新但memory永远不会更新redis如果是集群建议不要开启memory配置即启用"
},
"codeConfig": {
"packageName": "默认无必须包名称以及应用名生成代码的配置文件地址比如config/app.json数据库有更新时自动更新配置文件以及对应的生成文件",
"注释": "配置即启用,非必须,默认无"
},
"codeConfig": [
"注释:配置即启用,非必须,默认无",
{
"config": "默认config/app.json必须接口描述配置文件",
"configDB": "默认无,非必须,有则每次将数据库数据生成到此目录用于配置读写,无则不生成",
"mode": "默认0非必须0为内嵌代码模式1为生成代码模式",
"name": "默认无非必须有则生成代码到此目录无则采用缺省模式使用表名如设置为admin将在admin目录生成包名为admin的代码",
"rule": "默认config/rule.json非必须有则按改规则生成接口无则按系统内嵌方式生成",
"table": "默认admin必须根据数据库内当前表名做为用户生成数据"
}
],
"crossDomain": "默认空 非必须空字符串为不开启如果需要跨域设置auto为智能开启所有网站允许跨域http://www.baidu.com为指定域允许跨域",
"db": {
"mysql": {
@ -59,7 +66,7 @@
},
"logFile": "无默认,非必须,如果需要存储日志文件时使用,保存格式为:a/b/c/20060102150405.txt,将生成a/b/c/年月日时分秒.txt按需设置",
"logLevel": "默认0必须0关闭1打印日志等级",
"mode": "默认0,非必须0生产模式1测试模式2开发模式,在开发模式下会显示更多的数据用于开发测试,并能够辅助研发,自动生成配置文件、代码等功能,web无缓存数据库不启用缓存",
"mode": "默认0,非必须0生产模式1测试模式2开发模式3内嵌代码模式,在开发模式下会显示更多的数据用于开发测试,并能够辅助研发,自动生成配置文件、代码等功能,web无缓存数据库不启用缓存",
"modeRouterStrict": "默认false,必须路由严格模式false,为大小写忽略必须匹配true必须大小写匹配",
"port": "默认80必须web服务开启Http端口0为不启用http服务,默认80",
"sessionName": "默认HOTIME必须设置session的cookie名",

Binary file not shown.

422
example/config/rule.json Normal file
View File

@ -0,0 +1,422 @@
[
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "idcard",
"strict": false,
"type": ""
},
{
"add": false,
"edit": false,
"info": true,
"list": true,
"must": false,
"name": "id",
"strict": true,
"type": ""
},
{
"add": false,
"edit": false,
"info": true,
"list": true,
"must": false,
"name": "sn",
"strict": false,
"type": ""
},
{
"add": false,
"edit": false,
"info": false,
"list": false,
"must": false,
"name": "parent_ids",
"strict": true,
"type": "index"
},
{
"add": false,
"edit": false,
"info": false,
"list": false,
"must": false,
"name": "index",
"strict": true,
"type": "index"
},
{
"add": true,
"edit": true,
"info": true,
"list": true,
"must": false,
"name": "parent_id",
"true": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": true,
"must": false,
"name": "amount",
"strict": true,
"type": "money"
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "info",
"strict": false,
"type": "textArea"
},
{
"add": true,
"edit": true,
"info": true,
"list": true,
"must": false,
"name": "status",
"strict": false,
"type": "select"
},
{
"add": true,
"edit": true,
"info": true,
"list": true,
"must": false,
"name": "state",
"strict": false,
"type": "select"
},
{
"add": true,
"edit": true,
"info": true,
"list": true,
"must": false,
"name": "sex",
"strict": false,
"type": "select"
},
{
"add": false,
"edit": false,
"info": false,
"list": false,
"must": false,
"name": "delete",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "lat",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "lng",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "latitude",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "longitude",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": false,
"list": false,
"must": false,
"name": "password",
"strict": false,
"type": "password"
},
{
"add": true,
"edit": true,
"info": false,
"list": false,
"must": false,
"name": "pwd",
"strict": false,
"type": "password"
},
{
"add": false,
"edit": false,
"info": false,
"list": false,
"must": false,
"name": "version",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "seq",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "sort",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "note",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "description",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "abstract",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "content",
"strict": false,
"type": "textArea"
},
{
"add": true,
"edit": true,
"info": true,
"list": true,
"must": false,
"name": "address",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "full_name",
"strict": false,
"type": ""
},
{
"add": false,
"edit": false,
"info": true,
"list": false,
"must": false,
"name": "create_time",
"strict": true,
"type": "time"
},
{
"add": false,
"edit": false,
"info": true,
"list": true,
"must": false,
"name": "modify_time",
"strict": true,
"type": "time"
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "image",
"strict": false,
"type": "image"
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "img",
"strict": false,
"type": "image"
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "avatar",
"strict": false,
"type": "image"
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "icon",
"strict": false,
"type": "image"
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "file",
"strict": false,
"type": "file"
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "age",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "email",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": true,
"must": false,
"name": "time",
"strict": false,
"type": "time"
},
{
"add": false,
"edit": false,
"info": true,
"list": false,
"must": false,
"name": "level",
"strict": false,
"type": ""
},
{
"add": true,
"edit": true,
"info": true,
"list": true,
"must": false,
"name": "rule",
"strict": false,
"type": "form"
},
{
"add": true,
"edit": true,
"info": true,
"list": false,
"must": false,
"name": "auth",
"strict": true,
"type": "auth"
},
{
"add": false,
"edit": false,
"info": true,
"list": true,
"must": false,
"name": "table",
"strict": false,
"type": "table"
},
{
"add": false,
"edit": false,
"info": true,
"list": true,
"must": false,
"name": "table_id",
"strict": false,
"type": "table_id"
}
]

View File

@ -1,202 +1,17 @@
package main
import (
"../../hotime"
"../../hotime/common"
"../dri/ddsms"
//"./admin"
"./app"
"fmt"
"io"
"os"
"strings"
"time"
. "code.hoteas.com/golang/hotime"
)
func main() {
date, _ := time.Parse("2006-01-02 15:04", time.Now().Format("2006-01-02")+" 14:00")
fmt.Println(date, date.Unix())
//fmt.Println("0123456"[1:7])
appIns := hotime.Init("config/config.json")
//RESTfull接口适配
appIns.SetConnectListener(func(context *hotime.Context) bool {
if len(context.RouterString) > 1 && context.RouterString[0] == "admin" {
if context.RouterString[1] == "hotime" && context.RouterString[2] == "login" {
return true
}
if context.RouterString[1] == "hotime" && context.RouterString[2] == "logout" {
return true
}
appIns := Init("config/config.json")
appIns.SetConnectListener(func(that *Context) (isFinished bool) {
if context.Session("admin_id").Data == nil {
context.Display(2, "你还没有登录")
return false
}
}
//文件上传接口
if len(context.RouterString) == 1 && context.RouterString[0] == "file" && context.Req.Method == "POST" {
//读取网络文件
fi, fheader, err := context.Req.FormFile("file")
if err != nil {
context.Display(3, err)
return false
}
filePath := context.Config.GetString("filePath")
if filePath == "" {
filePath = "file/2006/01/02/"
}
path := time.Now().Format(filePath)
e := os.MkdirAll(context.Config.GetString("tpt")+"/"+path, os.ModeDir)
if e != nil {
context.Display(3, e)
return false
}
filePath = path + common.Md5(common.ObjToStr(common.RandX(100000, 9999999))) + fheader.Filename[strings.LastIndex(fheader.Filename, "."):]
newFile, e := os.Create(context.Config.GetString("tpt") + "/" + filePath)
if e != nil {
context.Display(3, e)
return false
}
_, e = io.Copy(newFile, fi)
if e != nil {
context.Display(3, e)
return false
}
context.Display(0, filePath)
return false
}
if len(context.RouterString) < 2 || len(context.RouterString) > 3 ||
!(context.Router[context.RouterString[0]] != nil &&
context.Router[context.RouterString[0]][context.RouterString[1]] != nil) {
return true
}
//排除无效操作
if len(context.RouterString) == 2 &&
context.Req.Method != "GET" &&
context.Req.Method != "POST" {
return true
}
//列表检索
if len(context.RouterString) == 2 &&
context.Req.Method == "GET" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["search"] == nil {
return true
}
context.Router[context.RouterString[0]][context.RouterString[1]]["search"](context)
}
//新建
if len(context.RouterString) == 2 &&
context.Req.Method == "POST" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["add"] == nil {
return true
}
context.Router[context.RouterString[0]][context.RouterString[1]]["add"](context)
}
if len(context.RouterString) == 3 &&
context.Req.Method == "POST" {
return true
}
//查询单条
if len(context.RouterString) == 3 &&
context.Req.Method == "GET" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["info"] == nil {
return true
}
context.Router[context.RouterString[0]][context.RouterString[1]]["info"](context)
}
//更新
if len(context.RouterString) == 3 &&
context.Req.Method == "PUT" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["update"] == nil {
return true
}
context.Router[context.RouterString[0]][context.RouterString[1]]["update"](context)
}
//移除
if len(context.RouterString) == 3 &&
context.Req.Method == "DELETE" {
if context.Router[context.RouterString[0]][context.RouterString[1]]["remove"] == nil {
return true
}
context.Router[context.RouterString[0]][context.RouterString[1]]["remove"](context)
}
context.View()
return false
return isFinished
})
//makeCode := code.MakeCode{}
//fmt.Println(common.ObjToStr(makeCode.Db2JSON("admin","test",appIns.Db)))
if ddsms.DefaultDDY.ApiKey == "" {
ddsms.DefaultDDY.Init(appIns.Config.GetString("smsKey"))
}
appIns.Run(Router{})
appIns.Run(hotime.Router{
//"admin": admin.Project,
"app": app.Project,
//"app": hotime.Proj{
// "index": hotime.Ctr{
// "test": func(this *hotime.Context) {
//
// data := this.Db.Get("cached", "*")
// fmt.Println(data)
// fmt.Println(this.Session("test").ToCeilInt())
// this.Session("test1", 98984984)
// fmt.Println(this.Session("test1").Data)
// this.Error.SetError(errors.New("dasdasdas"))
// //fmt.Println(this.Db.GetTag())
// //this.Application.Log.Error("dasdasdas")
// //this.Log.Error("dadasdasd")
// //x:=this.Db.Action(func(db hotime.HoTimeDB) bool {
// //
// // db.Insert("user",hotime.Map{"unickname":"dasdas"})
// //
// // return true
// //})
// //hotime.LogError("dasdasdasdasdas")
// this.Display(5, "dsadas")
// },
// "websocket": func(this *hotime.Context) {
// hdler := websocket.Handler(func(ws *websocket.Conn) {
// for true {
// msg := make([]byte, 5120)
// n, err := ws.Read(msg)
// go func() {
// time.Sleep(time.Second * 5)
// ws.Write([]byte("dsadasdasgregergrerge"))
//
// }()
// if err != nil {
// return
// }
// fmt.Printf("Receive: %s\n", msg[:n])
//
// send_msg := "[" + string(msg[:n]) + "]"
// m, err := ws.Write([]byte(send_msg))
// if err != nil {
// return
// }
// fmt.Printf("Send: %s\n", msg[:m])
// }
// })
// hdler.ServeHTTP(this.Resp, this.Req)
// },
// },
//},
})
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.el-upload{height:100px;width:100px;background:#eee;overflow:hidden}.el-upload img[data-v-3b5105e6]{height:100%;width:100%;-o-object-fit:cover;object-fit:cover;display:block}.el-upload i[data-v-3b5105e6]{font-size:40px;margin:30% 31%;display:block}.custom-tree-node[data-v-3b5105e6]{font-size:14px;padding-right:8px}.info-descriptions[data-v-4d4566fc] .el-descriptions__body .el-descriptions__label{min-width:90px;text-align:right;background:transparent;color:#606266;font-weight:400}.el-descriptions .is-bordered th[data-v-4d4566fc],.info-descriptions[data-v-4d4566fc] .el-descriptions .is-bordered td{border:transparent;max-width:25vw}.tree-line .el-tree-node{position:relative;padding-left:16px}.tree-line .el-tree-node__content{line-height:18px;font-size:14px}.tree-line .el-tree-node__children{padding-left:16px}.tree-line .el-tree-node:before{content:"";height:100%;width:1px;position:absolute;left:-3px;top:-26px;border-width:1px;border-left:1px dashed #52627c}.tree-line .el-tree-node:last-child:before{height:38px}.tree-line .el-tree-node:after{content:"";width:24px;height:20px;position:absolute;left:-3px;top:12px;border-width:1px;border-top:1px dashed #52627c}.tree-line>.el-tree-node:after{border-top:none}.tree-line>.el-tree-node:before{border-left:none}.tree-line .el-tree-node__expand-icon{font-size:18px;color:#000}.tree-line .el-tree-node__expand-icon.is-leaf{color:transparent}.dialog-box .el-descriptions__header{margin:20px 0 5px}.dialog-box .el-descriptions__body{background:#fff}.textarea-box *{word-break:break-all;white-space:pre-wrap}.textarea-box table{width:100%!important}.textarea-box img{max-width:80%!important}.textarea-box::-webkit-scrollbar-thumb{height:5px;background-color:rgba(0,0,0,.2)!important}

View File

@ -0,0 +1 @@
body[data-v-c08f3364],dd[data-v-c08f3364],dl[data-v-c08f3364],form[data-v-c08f3364],h1[data-v-c08f3364],h2[data-v-c08f3364],h3[data-v-c08f3364],h4[data-v-c08f3364],h5[data-v-c08f3364],h6[data-v-c08f3364],html[data-v-c08f3364],ol[data-v-c08f3364],p[data-v-c08f3364],pre[data-v-c08f3364],tbody[data-v-c08f3364],textarea[data-v-c08f3364],tfoot[data-v-c08f3364],thead[data-v-c08f3364],ul[data-v-c08f3364]{margin:0;font-size:14px;font-family:Microsoft YaHei}dl[data-v-c08f3364],ol[data-v-c08f3364],ul[data-v-c08f3364]{padding:0}li[data-v-c08f3364]{list-style:none}input[data-v-c08f3364]{border:none;outline:none;font-family:Microsoft YaHei;background-color:#fff}a[data-v-c08f3364]{font-family:Microsoft YaHei;text-decoration:none}[data-v-c08f3364]{margin:0;padding:0}.login[data-v-c08f3364]{position:relative;width:100%;height:100%;background-color:#353d56;background-repeat:no-repeat;background-attachment:fixed;background-size:cover}.login-item[data-v-c08f3364]{position:absolute;top:calc(50% - 30vh);left:60%;min-width:388px;width:18vw;max-width:588px;padding:8vh 30px;box-sizing:border-box;background-size:468px 468px;background:hsla(0,0%,100%,.85);border-radius:10px}.login-item .right-content[data-v-c08f3364]{box-sizing:border-box;width:100%}.login-item .right-content .login-title[data-v-c08f3364]{font-size:26px;font-weight:700;color:#4f619b;text-align:center}.errorMsg[data-v-c08f3364]{width:100%;height:34px;line-height:34px;color:red;font-size:14px;overflow:hidden}.login-item .right-content .inputWrap[data-v-c08f3364]{width:90%;height:32px;line-height:32px;color:#646464;font-size:16px;border:1px solid #b4b4b4;margin:0 auto 5%;padding:2% 10px;border-radius:10px}.login-item .right-content .inputWrap.inputFocus[data-v-c08f3364]{border:1px solid #4f619b;box-shadow:0 0 0 3px rgba(91,113,185,.4)}.login-item .right-content .inputWrap input[data-v-c08f3364]{background-color:transparent;color:#646464;display:inline-block;height:100%;width:80%}.login-btn[data-v-c08f3364]{width:97%;height:52px;text-align:center;line-height:52px;font-size:17px;color:#fff;background-color:#4f619b;border-radius:10px;margin:0 auto;margin-top:50px;cursor:pointer;font-weight:800}

View File

@ -0,0 +1 @@
.el-upload{height:100px;width:100px;background:#eee;overflow:hidden}.el-upload img[data-v-51dbed3c]{height:100%;width:100%;-o-object-fit:cover;object-fit:cover;display:block}.el-upload i[data-v-51dbed3c]{font-size:40px;margin:30% 31%;display:block}.custom-tree-node[data-v-51dbed3c]{font-size:14px;padding-right:8px}.info-descriptions[data-v-4d4566fc] .el-descriptions__body .el-descriptions__label{min-width:90px;text-align:right;background:transparent;color:#606266;font-weight:400}.el-descriptions .is-bordered th[data-v-4d4566fc],.info-descriptions[data-v-4d4566fc] .el-descriptions .is-bordered td{border:transparent;max-width:25vw}.tree-line .el-tree-node{position:relative;padding-left:16px}.tree-line .el-tree-node__content{line-height:18px;font-size:14px}.tree-line .el-tree-node__children{padding-left:16px}.tree-line .el-tree-node:before{content:"";height:100%;width:1px;position:absolute;left:-3px;top:-26px;border-width:1px;border-left:1px dashed #52627c}.tree-line .el-tree-node:last-child:before{height:38px}.tree-line .el-tree-node:after{content:"";width:24px;height:20px;position:absolute;left:-3px;top:12px;border-width:1px;border-top:1px dashed #52627c}.tree-line>.el-tree-node:after{border-top:none}.tree-line>.el-tree-node:before{border-left:none}.tree-line .el-tree-node__expand-icon{font-size:18px;color:#000}.tree-line .el-tree-node__expand-icon.is-leaf{color:transparent}.dialog-box .el-descriptions__header{margin:20px 0 5px}.dialog-box .el-descriptions__body{background:#fff}.textarea-box *{word-break:break-all;white-space:pre-wrap}.textarea-box table{width:100%!important}.textarea-box img{max-width:80%!important}.textarea-box::-webkit-scrollbar-thumb{height:5px;background-color:rgba(0,0,0,.2)!important}

View File

@ -1 +0,0 @@
h3[data-v-b9167eee]{margin:40px 0 0}ul[data-v-b9167eee]{list-style-type:none;padding:0}li[data-v-b9167eee]{display:inline-block;margin:0 10px}a[data-v-b9167eee]{color:#42b983}

View File

@ -0,0 +1 @@
.full-screen-container[data-v-12e6b782]{z-index:10000}.file-upload .el-upload{background:transparent;width:100%;height:auto;text-align:left;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.file-upload .el-upload .el-button{margin-right:10px}.el-upload img[data-v-69e31561]{height:100%;width:100%;-o-object-fit:cover;object-fit:cover;display:block}.el-upload i[data-v-69e31561]{font-size:40px;margin:30% 31%;display:block}.el-upload{height:100px;width:100px;background:#eee;overflow:hidden}.tree-line .el-tree-node{position:relative;padding-left:16px}.tree-line .el-tree-node__content{line-height:18px;font-size:14px}.tree-line .el-tree-node__children{padding-left:16px}.tree-line .el-tree-node:before{content:"";height:100%;width:1px;position:absolute;left:-3px;top:-26px;border-width:1px;border-left:1px dashed #52627c}.tree-line .el-tree-node:last-child:before{height:38px}.tree-line .el-tree-node:after{content:"";width:24px;height:20px;position:absolute;left:-3px;top:12px;border-width:1px;border-top:1px dashed #52627c}.tree-line>.el-tree-node:after{border-top:none}.tree-line>.el-tree-node:before{border-left:none}.tree-line .el-tree-node__expand-icon{font-size:18px;color:#000}.tree-line .el-tree-node__expand-icon.is-leaf{color:transparent}

View File

@ -0,0 +1 @@
.left-nav-home-bar{background:#2c3759!important;overflow:hidden;text-overflow:ellipsis}.left-nav-home-bar,.left-nav-home-bar i{color:#fff!important}.el-submenu .el-menu-item{height:40px;line-height:40px;width:auto;min-width:60px;padding:0 10px 0 25px!important;text-overflow:ellipsis;overflow:hidden}.el-menu .el-submenu__title{height:46px;line-height:46px;padding-left:10px!important;text-overflow:ellipsis;overflow:hidden}.left-nav-home-bar i{margin-bottom:6px!important}.el-menu-item-group__title{padding:0 0 0 10px}.el-menu--collapse .el-menu-item-group__title,.el-menu--collapse .el-submenu__title{padding-left:20px!important}.el-menu-item i,.el-submenu__title i{margin-top:-4px;vertical-align:middle;margin:-3px 5px 0 0;right:1px}.head-left[data-v-b2941c10],.head-right[data-v-b2941c10]{display:flex;justify-content:center;flex-direction:column}.head-right[data-v-b2941c10]{align-items:flex-end}.el-upload{height:100px;width:100px;background:#eee;overflow:hidden}.el-upload img[data-v-51dbed3c]{height:100%;width:100%;-o-object-fit:cover;object-fit:cover;display:block}.el-upload i[data-v-51dbed3c]{font-size:40px;margin:30% 31%;display:block}.custom-tree-node[data-v-51dbed3c]{font-size:14px;padding-right:8px}.info-descriptions[data-v-4d4566fc] .el-descriptions__body .el-descriptions__label{min-width:90px;text-align:right;background:transparent;color:#606266;font-weight:400}.el-descriptions .is-bordered th[data-v-4d4566fc],.info-descriptions[data-v-4d4566fc] .el-descriptions .is-bordered td{border:transparent;max-width:25vw}.tree-line .el-tree-node{position:relative;padding-left:16px}.tree-line .el-tree-node__content{line-height:18px;font-size:14px}.tree-line .el-tree-node__children{padding-left:16px}.tree-line .el-tree-node:before{content:"";height:100%;width:1px;position:absolute;left:-3px;top:-26px;border-width:1px;border-left:1px dashed #52627c}.tree-line .el-tree-node:last-child:before{height:38px}.tree-line .el-tree-node:after{content:"";width:24px;height:20px;position:absolute;left:-3px;top:12px;border-width:1px;border-top:1px dashed #52627c}.tree-line>.el-tree-node:after{border-top:none}.tree-line>.el-tree-node:before{border-left:none}.tree-line .el-tree-node__expand-icon{font-size:18px;color:#000}.tree-line .el-tree-node__expand-icon.is-leaf{color:transparent}.dialog-box .el-descriptions__header{margin:20px 0 5px}.dialog-box .el-descriptions__body{background:#fff}.textarea-box *{word-break:break-all;white-space:pre-wrap}.textarea-box table{width:100%!important}.textarea-box img{max-width:80%!important}.textarea-box::-webkit-scrollbar-thumb{height:5px;background-color:rgba(0,0,0,.2)!important}.el-dialog{margin:auto!important;top:50%;transform:translateY(-50%)}.el-dialog-div{height:75vh;overflow:auto}.el-dialog__body{padding-top:15px;padding-bottom:45px}.el-dialog-div .el-tabs__header{position:absolute;left:1px;top:69px;width:calc(90vw - 42px);margin:0 20px;z-index:1}.el-dialog-div .el-tabs__content{padding-top:50px}.el-dialog-div .el-affix--fixed{bottom:20vh}.el-dialog-div .el-affix--fixed .el-form-item{padding:0!important;background:transparent!important}

View File

@ -0,0 +1 @@
.full-screen-container[data-v-12e6b782]{z-index:10000}.file-upload .el-upload{background:transparent;width:100%;height:auto;text-align:left;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.file-upload .el-upload .el-button{margin-right:10px}.el-upload img[data-v-96cdfb38]{height:100%;width:100%;-o-object-fit:cover;object-fit:cover;display:block}.el-upload i[data-v-96cdfb38]{font-size:40px;margin:30% 31%;display:block}.el-upload{height:100px;width:100px;background:#eee;overflow:hidden}.tree-line .el-tree-node{position:relative;padding-left:16px}.tree-line .el-tree-node__content{line-height:18px;font-size:14px}.tree-line .el-tree-node__children{padding-left:16px}.tree-line .el-tree-node:before{content:"";height:100%;width:1px;position:absolute;left:-3px;top:-26px;border-width:1px;border-left:1px dashed #52627c}.tree-line .el-tree-node:last-child:before{height:38px}.tree-line .el-tree-node:after{content:"";width:24px;height:20px;position:absolute;left:-3px;top:12px;border-width:1px;border-top:1px dashed #52627c}.tree-line>.el-tree-node:after{border-top:none}.tree-line>.el-tree-node:before{border-left:none}.tree-line .el-tree-node__expand-icon{font-size:18px;color:#000}.tree-line .el-tree-node__expand-icon.is-leaf{color:transparent}

View File

@ -0,0 +1 @@
.not-show-tab-label .el-tabs__header{display:none}.el-descriptions__body{background:#f0f0f0}.not-show-tab-search{display:none}.el-table__body-wrapper{margin-bottom:4px;padding-bottom:2px}.el-table__body-wrapper::-webkit-scrollbar{width:8px;height:8px}.el-table__body-wrapper::-webkit-scrollbar-track{border-radius:10px;-webkit-box-shadow:inset 0 0 6px hsla(0,0%,93.3%,.3);background-color:#eee}.el-table__body-wrapper::-webkit-scrollbar-thumb{border-radius:10px;-webkit-box-shadow:inset 0 0 6px rgba(145,143,143,.3);background-color:#918f8f}.input-with-select .el-input-group__prepend{background-color:#fff}.daterange-box .select .el-input__inner{border-top-right-radius:0;border-bottom-right-radius:0}.daterange-box .daterange.el-input__inner{border-top-left-radius:0;border-bottom-left-radius:0;vertical-align:bottom}[data-v-e9f58da4] .el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#409eff!important;color:#fff}

View File

@ -0,0 +1 @@
.left-nav-home-bar{background:#2c3759!important;overflow:hidden;text-overflow:ellipsis}.left-nav-home-bar,.left-nav-home-bar i{color:#fff!important}.el-submenu .el-menu-item{height:40px;line-height:40px;width:auto;min-width:60px;padding:0 10px 0 25px!important;text-overflow:ellipsis;overflow:hidden}.el-menu .el-submenu__title{height:46px;line-height:46px;padding-left:10px!important;text-overflow:ellipsis;overflow:hidden}.left-nav-home-bar i{margin-bottom:6px!important}.el-menu-item-group__title{padding:0 0 0 10px}.el-menu--collapse .el-menu-item-group__title,.el-menu--collapse .el-submenu__title{padding-left:20px!important}.el-menu-item i,.el-submenu__title i{margin-top:-4px;vertical-align:middle;margin:-3px 5px 0 0;right:1px}.head-left[data-v-b2941c10],.head-right[data-v-b2941c10]{display:flex;justify-content:center;flex-direction:column}.head-right[data-v-b2941c10]{align-items:flex-end}.el-upload{height:100px;width:100px;background:#eee;overflow:hidden}.el-upload img[data-v-3b5105e6]{height:100%;width:100%;-o-object-fit:cover;object-fit:cover;display:block}.el-upload i[data-v-3b5105e6]{font-size:40px;margin:30% 31%;display:block}.custom-tree-node[data-v-3b5105e6]{font-size:14px;padding-right:8px}.info-descriptions[data-v-4d4566fc] .el-descriptions__body .el-descriptions__label{min-width:90px;text-align:right;background:transparent;color:#606266;font-weight:400}.el-descriptions .is-bordered th[data-v-4d4566fc],.info-descriptions[data-v-4d4566fc] .el-descriptions .is-bordered td{border:transparent;max-width:25vw}.tree-line .el-tree-node{position:relative;padding-left:16px}.tree-line .el-tree-node__content{line-height:18px;font-size:14px}.tree-line .el-tree-node__children{padding-left:16px}.tree-line .el-tree-node:before{content:"";height:100%;width:1px;position:absolute;left:-3px;top:-26px;border-width:1px;border-left:1px dashed #52627c}.tree-line .el-tree-node:last-child:before{height:38px}.tree-line .el-tree-node:after{content:"";width:24px;height:20px;position:absolute;left:-3px;top:12px;border-width:1px;border-top:1px dashed #52627c}.tree-line>.el-tree-node:after{border-top:none}.tree-line>.el-tree-node:before{border-left:none}.tree-line .el-tree-node__expand-icon{font-size:18px;color:#000}.tree-line .el-tree-node__expand-icon.is-leaf{color:transparent}.dialog-box .el-descriptions__header{margin:20px 0 5px}.dialog-box .el-descriptions__body{background:#fff}.textarea-box *{word-break:break-all;white-space:pre-wrap}.textarea-box table{width:100%!important}.textarea-box img{max-width:80%!important}.textarea-box::-webkit-scrollbar-thumb{height:5px;background-color:rgba(0,0,0,.2)!important}.el-dialog{margin:auto!important;top:50%;transform:translateY(-50%)}.el-dialog-div{height:75vh;overflow:auto}.el-dialog__body{padding-top:15px;padding-bottom:45px}.el-dialog-div .el-tabs__header{position:absolute;left:1px;top:69px;width:calc(90vw - 42px);margin:0 20px;z-index:1}.el-dialog-div .el-tabs__content{padding-top:50px}.el-dialog-div .el-affix--fixed{bottom:20vh}.el-dialog-div .el-affix--fixed .el-form-item{padding:0!important;background:transparent!important}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.full-screen-container[data-v-12e6b782]{z-index:10000}.not-show-tab-label .el-tabs__header{display:none}.el-descriptions__body{background:#f0f0f0}.not-show-tab-search{display:none}.el-table__body-wrapper{margin-bottom:4px;padding-bottom:2px}.el-table__body-wrapper::-webkit-scrollbar{width:8px;height:8px}.el-table__body-wrapper::-webkit-scrollbar-track{border-radius:10px;-webkit-box-shadow:inset 0 0 6px hsla(0,0%,93.3%,.3);background-color:#eee}.el-table__body-wrapper::-webkit-scrollbar-thumb{border-radius:10px;-webkit-box-shadow:inset 0 0 6px rgba(145,143,143,.3);background-color:#918f8f}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

View File

@ -1,3 +1,3 @@
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>hotime</title><style>body{
margin: 0px;
}</style><link href="css/chunk-038340db.e4ca99de.css" rel="prefetch"><link href="css/chunk-0524801b.1e910850.css" rel="prefetch"><link href="css/chunk-1c438cad.2fd7d31d.css" rel="prefetch"><link href="css/chunk-1d1a12b6.8c684de3.css" rel="prefetch"><link href="css/chunk-2c1d9b2f.78c69bda.css" rel="prefetch"><link href="css/chunk-5ccac4d0.5f1c91ca.css" rel="prefetch"><link href="css/chunk-c569a38e.01bc1b83.css" rel="prefetch"><link href="css/chunk-c7a51d14.4a0871eb.css" rel="prefetch"><link href="js/chunk-038340db.3c8b0cb6.js" rel="prefetch"><link href="js/chunk-0524801b.de9b433f.js" rel="prefetch"><link href="js/chunk-14f17cfa.c5104e8c.js" rel="prefetch"><link href="js/chunk-1c438cad.72a22c19.js" rel="prefetch"><link href="js/chunk-1d1a12b6.6900cc01.js" rel="prefetch"><link href="js/chunk-2c1d9b2f.39065c9e.js" rel="prefetch"><link href="js/chunk-5b2ead63.af868ff8.js" rel="prefetch"><link href="js/chunk-5ccac4d0.98ff45de.js" rel="prefetch"><link href="js/chunk-68815fbc.04152d5f.js" rel="prefetch"><link href="js/chunk-c569a38e.16d55c64.js" rel="prefetch"><link href="js/chunk-c7a51d14.3cd28dc4.js" rel="prefetch"><link href="css/app.5e2eb449.css" rel="preload" as="style"><link href="js/app.f5f26baa.js" rel="preload" as="script"><link href="css/app.5e2eb449.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but hotime doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/app.f5f26baa.js"></script></body></html>
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><script src="js/manage.js"></script><script src="https://api.map.baidu.com/api?v=2.0&ak=bF4Y6tQg94hV2vesn2ZIaUIXO4aRxxRk"></script><title></title><style>body{
margin: 0px;
}</style><link href="css/chunk-0de923e9.c4e8272a.css" rel="prefetch"><link href="css/chunk-1a458102.466135f0.css" rel="prefetch"><link href="css/chunk-291edee4.508cb3c8.css" rel="prefetch"><link href="css/chunk-4aefa5ec.fcc75990.css" rel="prefetch"><link href="css/chunk-4f81d902.91f1ef17.css" rel="prefetch"><link href="css/chunk-856f3c38.9b9508b8.css" rel="prefetch"><link href="css/chunk-e3f8e5a6.7876554f.css" rel="prefetch"><link href="js/chunk-0de923e9.1f0fca7e.js" rel="prefetch"><link href="js/chunk-1a458102.9a54e9ae.js" rel="prefetch"><link href="js/chunk-25ddb50b.55ec750b.js" rel="prefetch"><link href="js/chunk-291edee4.e8dbe8c8.js" rel="prefetch"><link href="js/chunk-4aefa5ec.c237610d.js" rel="prefetch"><link href="js/chunk-4f81d902.c5fdb7dd.js" rel="prefetch"><link href="js/chunk-7ea17297.38d572ef.js" rel="prefetch"><link href="js/chunk-856f3c38.29c2fcc0.js" rel="prefetch"><link href="js/chunk-e3f8e5a6.ff58e6f8.js" rel="prefetch"><link href="js/chunk-e624c1ca.62513cbc.js" rel="prefetch"><link href="css/app.abfb5de2.css" rel="preload" as="style"><link href="js/app.25e49e88.js" rel="preload" as="script"><link href="css/app.abfb5de2.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but hotime doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/app.25e49e88.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-0de923e9"],{"578a":function(o,n,t){"use strict";t.r(n);t("b0c0");var i=t("f2bf"),s={class:"login-item"},r={class:"right-content"},u={class:"login-title"},l={style:{height:"60px"}},d=Object(i.r)(" 账号:"),b=Object(i.r)(" 密码:");var e=t("2934"),c={name:"Login",data:function(){return{showLog:!1,showLogInfo:"",label:"HoTime DashBoard",form:{name:"",password:""},backgroundImage:window.Hotime.data.name+"/hotime/wallpaper?random=1&type=1",focusName:!1,focusPassword:!1}},methods:{login:function(){var n=this;if(""==this.name||""==this.password)return this.showLogInfo="参数不足!",void(this.showLog=!0);Object(e.a)(window.Hotime.data.name+"/hotime/login",n.form).then(function(o){if(0!=o.status)return n.showLogInfo=o.error.msg,void(n.showLog=!0);location.hash="#/",location.reload()})},getBgImg:function(){var n=this;Object(e.e)(window.Hotime.data.name+"/hotime/wallpaper?random=1").then(function(o){0==o.status&&(n.backgroundImage=o.result.url)})},focusPrice:function(o){this["focus"+o]=!0},blurPrice:function(o){this["focus"+o]=!1}},mounted:function(){var n=this;this.label=window.Hotime.data.label,document.onkeydown=function(o){o=window.event||o;13==(o.keyCode||o.which||o.charCode)&&n.login()}}},a=(t("fad9"),t("6b0d")),t=t.n(a);n.default=t()(c,[["render",function(o,n,t,e,c,a){return Object(i.L)(),Object(i.n)("div",{class:"login",style:Object(i.C)({width:"100%",height:"100vh","background-image":"url("+c.backgroundImage+")"})},[Object(i.o)("div",s,[Object(i.o)("div",r,[Object(i.o)("p",u,Object(i.Y)(c.label),1),Object(i.o)("div",l,[Object(i.lb)(Object(i.o)("p",{class:"errorMsg"},Object(i.Y)(c.showLogInfo),513),[[i.hb,c.showLog]])]),Object(i.o)("p",{class:Object(i.B)(["inputWrap",{inputFocus:c.focusName}])},[d,Object(i.lb)(Object(i.o)("input",{type:"text","onUpdate:modelValue":n[0]||(n[0]=function(o){return c.form.name=o}),class:"accountVal",onKeyup:n[1]||(n[1]=Object(i.mb)(function(){return a.login&&a.login.apply(a,arguments)},["enter"])),onFocus:n[2]||(n[2]=function(o){return a.focusPrice("Name")}),onBlur:n[3]||(n[3]=function(o){return a.blurPrice("Name")})},null,544),[[i.gb,c.form.name]])],2),Object(i.o)("p",{class:Object(i.B)(["inputWrap",{inputFocus:c.focusPassword}])},[b,Object(i.lb)(Object(i.o)("input",{type:"password","onUpdate:modelValue":n[4]||(n[4]=function(o){return c.form.password=o}),class:"passwordVal",onKeyup:n[5]||(n[5]=Object(i.mb)(function(){return a.login&&a.login.apply(a,arguments)},["enter"])),onFocus:n[6]||(n[6]=function(o){return a.focusPrice("Password")}),onBlur:n[7]||(n[7]=function(o){return a.blurPrice("Password")})},null,544),[[i.gb,c.form.password]])],2),Object(i.o)("p",{class:"login-btn",onClick:n[8]||(n[8]=function(){return a.login&&a.login.apply(a,arguments)})},"登录")])])],4)}],["__scopeId","data-v-c08f3364"]])},dbeb:function(o,n,t){},fad9:function(o,n,t){"use strict";t("dbeb")}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-25ddb50b"],{"107c":function(t,e,n){var r=n("d039"),c=n("da84").RegExp;t.exports=r(function(){var t=c("(?<a>b)","g");return"b"!==t.exec("b").groups.a||"bc"!=="b".replace(t,"$<a>c")})},"129f":function(t,e){t.exports=Object.is||function(t,e){return t===e?0!==t||1/t==1/e:t!=t&&e!=e}},"14c3":function(t,e,n){var r=n("c6b6"),c=n("9263");t.exports=function(t,e){var n=t.exec;if("function"==typeof n){n=n.call(t,e);if("object"!=typeof n)throw TypeError("RegExp exec method returned something other than an Object or null");return n}if("RegExp"!==r(t))throw TypeError("RegExp#exec called on incompatible receiver");return c.call(t,e)}},"159b":function(t,e,n){var r,c=n("da84"),i=n("fdbc"),o=n("17c2"),a=n("9112");for(r in i){var l=c[r],l=l&&l.prototype;if(l&&l.forEach!==o)try{a(l,"forEach",o)}catch(t){l.forEach=o}}},"17c2":function(t,e,n){"use strict";var r=n("b727").forEach,n=n("a640")("forEach");t.exports=n?[].forEach:function(t){return r(this,t,1<arguments.length?arguments[1]:void 0)}},"83c5":function(t,e,n){"use strict";n("159b");e.a={list:{},constructor:function(){this.list={}},$on:function(t,e){this.list[t]=this.list[t]||[],this.list[t].push(e)},$emit:function(t,e){this.list[t]&&this.list[t].forEach(function(t){t(e)})},$off:function(t){this.list[t]&&delete this.list[t]}}},"841c":function(t,e,n){"use strict";var r=n("d784"),o=n("825a"),a=n("1d80"),l=n("129f"),s=n("577e"),u=n("14c3");r("search",function(r,c,i){return[function(t){var e=a(this),n=null==t?void 0:t[r];return void 0!==n?n.call(t,e):new RegExp(t)[r](s(e))},function(t){var e=o(this),t=s(t),n=i(c,e,t);if(n.done)return n.value;n=e.lastIndex,l(n,0)||(e.lastIndex=0),t=u(e,t);return l(e.lastIndex,n)||(e.lastIndex=n),null===t?-1:t.index}]})},9263:function(t,e,n){"use strict";var r,p=n("577e"),h=n("ad6d"),c=n("9f7f"),i=n("5692"),g=n("7c73"),v=n("69f3").get,o=n("fce3"),n=n("107c"),E=RegExp.prototype.exec,b=i("native-string-replace",String.prototype.replace),I=E,R=(i=/a/,r=/b*/g,E.call(i,"a"),E.call(r,"a"),0!==i.lastIndex||0!==r.lastIndex),y=c.UNSUPPORTED_Y||c.BROKEN_CARET,w=void 0!==/()??/.exec("")[1];(R||w||y||o||n)&&(I=function(t){var e,n,r,c,i,o,a=this,l=v(a),t=p(t),s=l.raw;if(s)return s.lastIndex=a.lastIndex,f=I.call(s,t),a.lastIndex=s.lastIndex,f;var u=l.groups,s=y&&a.sticky,f=h.call(a),l=a.source,d=0,x=t;if(s&&(-1===(f=f.replace("y","")).indexOf("g")&&(f+="g"),x=t.slice(a.lastIndex),0<a.lastIndex&&(!a.multiline||a.multiline&&"\n"!==t.charAt(a.lastIndex-1))&&(l="(?: "+l+")",x=" "+x,d++),e=new RegExp("^(?:"+l+")",f)),w&&(e=new RegExp("^"+l+"$(?!\\s)",f)),R&&(n=a.lastIndex),r=E.call(s?e:a,x),s?r?(r.input=r.input.slice(d),r[0]=r[0].slice(d),r.index=a.lastIndex,a.lastIndex+=r[0].length):a.lastIndex=0:R&&r&&(a.lastIndex=a.global?r.index+r[0].length:n),w&&r&&1<r.length&&b.call(r[0],e,function(){for(c=1;c<arguments.length-2;c++)void 0===arguments[c]&&(r[c]=void 0)}),r&&u)for(r.groups=i=g(null),c=0;c<u.length;c++)i[(o=u[c])[0]]=r[o[1]];return r}),t.exports=I},"9f7f":function(t,e,n){var r=n("d039"),c=n("da84").RegExp;e.UNSUPPORTED_Y=r(function(){var t=c("a","y");return t.lastIndex=2,null!=t.exec("abcd")}),e.BROKEN_CARET=r(function(){var t=c("^r","gy");return t.lastIndex=2,null!=t.exec("str")})},ac1f:function(t,e,n){"use strict";var r=n("23e7"),n=n("9263");r({target:"RegExp",proto:!0,forced:/./.exec!==n},{exec:n})},ad6d:function(t,e,n){"use strict";var r=n("825a");t.exports=function(){var t=r(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.dotAll&&(e+="s"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},d784:function(t,e,n){"use strict";n("ac1f");var l=n("6eeb"),s=n("9263"),u=n("d039"),f=n("b622"),d=n("9112"),x=f("species"),p=RegExp.prototype;t.exports=function(n,t,e,r){var o,c=f(n),a=!u(function(){var t={};return t[c]=function(){return 7},7!=""[n](t)}),i=a&&!u(function(){var t=!1,e=/a/;return"split"===n&&((e={constructor:{}}).constructor[x]=function(){return e},e.flags="",e[c]=/./[c]),e.exec=function(){return t=!0,null},e[c](""),!t});a&&i&&!e||(o=/./[c],i=t(c,""[n],function(t,e,n,r,c){var i=e.exec;return i===s||i===p.exec?a&&!c?{done:!0,value:o.call(e,n,r)}:{done:!0,value:t.call(n,e,r)}:{done:!1}}),l(String.prototype,n,i[0]),l(p,c,i[1])),r&&d(p[c],"sham",!0)}},fce3:function(t,e,n){var r=n("d039"),c=n("da84").RegExp;t.exports=r(function(){var t=c(".","s");return!(t.dotAll&&t.exec("\n")&&"s"===t.flags)})}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-e624c1ca"],{"4de4":function(t,n,r){"use strict";var e=r("23e7"),o=r("b727").filter;e({target:"Array",proto:!0,forced:!r("1dde")("filter")},{filter:function(t){return o(this,t,1<arguments.length?arguments[1]:void 0)}})},a640:function(t,n,r){"use strict";var e=r("d039");t.exports=function(t,n){var r=[][t];return!!r&&e(function(){r.call(null,n||function(){throw 1},1)})}}}]);

13
example/tpt/js/manage.js Normal file
View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2022/7/23 下午7:22
* AuthorHoTeas
*/
// eslint-disable-next-line no-unused-vars
var Hotime = {
vueComponent: {},
mapData: {},
pageRow:20,
tableMapData: {},
tableName:"admin"
}

View File

@ -0,0 +1,784 @@
package main
import (
"database/sql"
"fmt"
"log"
// 实际使用时请替换为正确的导入路径
// "code.hoteas.com/golang/hotime/cache"
// "code.hoteas.com/golang/hotime/common"
// "code.hoteas.com/golang/hotime/db"
"code.hoteas.com/golang/hotime/cache"
"code.hoteas.com/golang/hotime/common"
"code.hoteas.com/golang/hotime/db"
_ "github.com/go-sql-driver/mysql"
"github.com/sirupsen/logrus"
)
// HoTimeDB使用示例代码集合 - 修正版
// 本文件包含了各种常见场景的完整示例代码,所有条件查询语法已修正
// 示例1: 基本初始化和配置
func Example1_BasicSetup() {
// 创建数据库实例
database := &db.HoTimeDB{
Prefix: "app_", // 设置表前缀
Mode: 2, // 开发模式输出SQL日志
Type: "mysql", // 数据库类型
}
// 设置日志
logger := logrus.New()
database.Log = logger
// 设置连接函数
database.SetConnect(func(err ...*common.Error) (master, slave *sql.DB) {
// 主数据库连接
master, dbErr := sql.Open("mysql", "root:password@tcp(localhost:3306)/testdb?charset=utf8&parseTime=true")
if dbErr != nil {
log.Fatal("数据库连接失败:", dbErr)
}
// 从数据库连接(可选,用于读写分离)
slave = master // 这里使用同一个连接,实际项目中可以连接到从库
return master, slave
})
fmt.Println("数据库初始化完成")
}
// 示例2: 基本CRUD操作修正版
func Example2_BasicCRUD_Fixed(db *db.HoTimeDB) {
// 创建用户
fmt.Println("=== 创建用户 ===")
userId := db.Insert("user", common.Map{
"name": "张三",
"email": "zhangsan@example.com",
"age": 25,
"status": 1,
"balance": 1000.50,
"created_time[#]": "NOW()",
})
fmt.Printf("新用户ID: %d\n", userId)
// 查询用户单条件可以不用AND
fmt.Println("\n=== 查询用户 ===")
user := db.Get("user", "*", common.Map{
"id": userId,
})
if user != nil {
fmt.Printf("用户信息: %+v\n", user)
}
// 更新用户多条件必须用AND包装
fmt.Println("\n=== 更新用户 ===")
affected := db.Update("user", common.Map{
"name": "李四",
"age": 26,
"updated_time[#]": "NOW()",
}, common.Map{
"AND": common.Map{
"id": userId,
"status": 1, // 确保只更新正常状态的用户
},
})
fmt.Printf("更新记录数: %d\n", affected)
// 软删除用户
fmt.Println("\n=== 软删除用户 ===")
affected = db.Update("user", common.Map{
"deleted_at[#]": "NOW()",
"status": 0,
}, common.Map{
"id": userId, // 单条件不需要AND
})
fmt.Printf("软删除记录数: %d\n", affected)
}
// 示例3: 条件查询语法(修正版)
func Example3_ConditionQuery_Fixed(db *db.HoTimeDB) {
fmt.Println("=== 条件查询语法示例 ===")
// ✅ 正确:单个条件
users1 := db.Select("user", "*", common.Map{
"status": 1,
})
fmt.Printf("活跃用户: %d个\n", len(users1))
// ✅ 正确多个条件用AND包装
users2 := db.Select("user", "*", common.Map{
"AND": common.Map{
"status": 1,
"age[>]": 18,
"age[<=]": 60,
},
})
fmt.Printf("活跃的成年用户: %d个\n", len(users2))
// ✅ 正确OR条件
users3 := db.Select("user", "*", common.Map{
"OR": common.Map{
"level": "vip",
"balance[>]": 5000,
},
})
fmt.Printf("VIP或高余额用户: %d个\n", len(users3))
// ✅ 正确:条件 + 特殊参数
users4 := db.Select("user", "*", common.Map{
"AND": common.Map{
"status": 1,
"age[>=]": 18,
},
"ORDER": "created_time DESC",
"LIMIT": 10,
})
fmt.Printf("最近的活跃成年用户: %d个\n", len(users4))
// ✅ 正确:复杂嵌套条件
users5 := db.Select("user", "*", common.Map{
"AND": common.Map{
"status": 1,
"OR": common.Map{
"age[<]": 30,
"level": "vip",
},
},
"ORDER": []string{"level DESC", "created_time DESC"},
"LIMIT": []int{0, 20},
})
fmt.Printf("年轻或VIP的活跃用户: %d个\n", len(users5))
// ✅ 正确:模糊查询
users6 := db.Select("user", "*", common.Map{
"AND": common.Map{
"name[~]": "张", // 姓名包含"张"
"email[~!]": "gmail", // 邮箱以gmail开头
"status": 1,
},
})
fmt.Printf("姓张的gmail活跃用户: %d个\n", len(users6))
// ✅ 正确:范围查询
users7 := db.Select("user", "*", common.Map{
"AND": common.Map{
"age[<>]": []int{18, 35}, // 年龄在18-35之间
"balance[><]": []float64{0, 100}, // 余额不在0-100之间
"status": 1,
},
})
fmt.Printf("18-35岁且余额>100的活跃用户: %d个\n", len(users7))
// ✅ 正确IN查询
users8 := db.Select("user", "*", common.Map{
"AND": common.Map{
"id": []int{1, 2, 3, 4, 5}, // ID在指定范围内
"status[!]": []int{0, -1}, // 状态不为0或-1
},
})
fmt.Printf("指定ID的活跃用户: %d个\n", len(users8))
}
// 示例4: 链式查询操作(正确版)
func Example4_ChainQuery_Fixed(db *db.HoTimeDB) {
fmt.Println("=== 链式查询示例 ===")
// 链式查询链式语法允许单独的Where然后用And添加更多条件
users := db.Table("user").
Where("status", 1). // 链式中可以单独Where
And("age[>=]", 18). // 然后用And添加条件
And("age[<=]", 60). // 再添加条件
Or(common.Map{ // 或者用Or添加OR条件组
"level": "vip",
"balance[>]": 5000,
}).
Order("created_time DESC", "id ASC"). // 排序
Limit(0, 10). // 限制结果
Select("id,name,email,age,balance,level")
fmt.Printf("链式查询到 %d 个用户\n", len(users))
for i, user := range users {
fmt.Printf("用户%d: %s (年龄:%v, 余额:%v)\n",
i+1,
user.GetString("name"),
user.Get("age"),
user.Get("balance"))
}
// 链式统计查询
count := db.Table("user").
Where("status", 1).
And("age[>=]", 18).
Count()
fmt.Printf("符合条件的用户总数: %d\n", count)
}
// 示例5: JOIN查询操作修正版
func Example5_JoinQuery_Fixed(db *db.HoTimeDB) {
fmt.Println("=== JOIN查询示例 ===")
// 链式JOIN查询
orders := db.Table("order").
LeftJoin("user", "order.user_id = user.id").
LeftJoin("product", "order.product_id = product.id").
Where("order.status", "paid"). // 链式中单个条件可以直接Where
And("order.created_time[>]", "2023-01-01"). // 用And添加更多条件
Order("order.created_time DESC").
Select(`
order.id as order_id,
order.amount,
order.status,
order.created_time,
user.name as user_name,
user.email as user_email,
product.title as product_title,
product.price as product_price
`)
fmt.Printf("链式JOIN查询到 %d 个订单\n", len(orders))
for _, order := range orders {
fmt.Printf("订单ID:%v, 用户:%s, 商品:%s, 金额:%v\n",
order.Get("order_id"),
order.GetString("user_name"),
order.GetString("product_title"),
order.Get("amount"))
}
// 传统JOIN语法多个条件必须用AND包装
orders2 := db.Select("order",
common.Slice{
common.Map{"[>]user": "order.user_id = user.id"},
common.Map{"[>]product": "order.product_id = product.id"},
},
"order.*, user.name as user_name, product.title as product_title",
common.Map{
"AND": common.Map{
"order.status": "paid",
"order.created_time[>]": "2023-01-01",
},
})
fmt.Printf("传统JOIN语法查询到 %d 个订单\n", len(orders2))
}
// 示例6: 分页查询(修正版)
func Example6_PaginationQuery_Fixed(db *db.HoTimeDB) {
fmt.Println("=== 分页查询示例 ===")
page := 2
pageSize := 10
// 获取总数(单条件)
total := db.Count("user", common.Map{
"AND": common.Map{
"status": 1,
"deleted_at": nil,
},
})
// 分页数据(链式方式)
users := db.Table("user").
Where("status", 1).
And("deleted_at", nil).
Order("created_time DESC").
Page(page, pageSize).
Select("id,name,email,created_time")
// 使用传统方式的分页查询
users2 := db.Page(page, pageSize).PageSelect("user", "*", common.Map{
"AND": common.Map{
"status": 1,
"deleted_at": nil,
},
"ORDER": "created_time DESC",
})
// 计算分页信息
totalPages := (total + pageSize - 1) / pageSize
offset := (page - 1) * pageSize
fmt.Printf("总记录数: %d\n", total)
fmt.Printf("总页数: %d\n", totalPages)
fmt.Printf("当前页: %d\n", page)
fmt.Printf("每页大小: %d\n", pageSize)
fmt.Printf("偏移量: %d\n", offset)
fmt.Printf("链式查询当前页记录数: %d\n", len(users))
fmt.Printf("传统查询当前页记录数: %d\n", len(users2))
for i, user := range users {
fmt.Printf(" %d. %s (%s) - %v\n",
offset+i+1,
user.GetString("name"),
user.GetString("email"),
user.Get("created_time"))
}
}
// 示例7: 聚合函数查询(修正版)
func Example7_AggregateQuery_Fixed(db *db.HoTimeDB) {
fmt.Println("=== 聚合函数查询示例 ===")
// 基本统计
userCount := db.Count("user")
activeUserCount := db.Count("user", common.Map{"status": 1})
totalBalance := db.Sum("user", "balance", common.Map{"status": 1})
fmt.Printf("总用户数: %d\n", userCount)
fmt.Printf("活跃用户数: %d\n", activeUserCount)
fmt.Printf("活跃用户总余额: %.2f\n", totalBalance)
// 分组统计(正确语法)
stats := db.Select("user",
"level, COUNT(*) as user_count, AVG(age) as avg_age, SUM(balance) as total_balance",
common.Map{
"status": 1, // 单条件不需要AND
"GROUP": "level",
"ORDER": "user_count DESC",
})
fmt.Println("\n按等级分组统计:")
for _, stat := range stats {
fmt.Printf("等级:%v, 用户数:%v, 平均年龄:%v, 总余额:%v\n",
stat.Get("level"),
stat.Get("user_count"),
stat.Get("avg_age"),
stat.Get("total_balance"))
}
// 关联统计(修正版)
orderStats := db.Select("order",
common.Slice{
common.Map{"[>]user": "order.user_id = user.id"},
},
"user.level, COUNT(order.id) as order_count, SUM(order.amount) as total_amount",
common.Map{
"AND": common.Map{
"order.status": "paid",
"order.created_time[>]": "2023-01-01",
},
"GROUP": "user.level",
"ORDER": "total_amount DESC",
})
fmt.Println("\n用户等级订单统计:")
for _, stat := range orderStats {
fmt.Printf("等级:%v, 订单数:%v, 总金额:%v\n",
stat.Get("level"),
stat.Get("order_count"),
stat.Get("total_amount"))
}
}
// 示例8: 事务处理(修正版)
func Example8_Transaction_Fixed(db *db.HoTimeDB) {
fmt.Println("=== 事务处理示例 ===")
// 模拟转账操作
fromUserId := int64(1)
toUserId := int64(2)
amount := 100.0
success := db.Action(func(tx db.HoTimeDB) bool {
// 检查转出账户余额(单条件)
fromUser := tx.Get("user", "balance", common.Map{"id": fromUserId})
if fromUser == nil {
fmt.Println("转出用户不存在")
return false
}
fromBalance := fromUser.GetFloat64("balance")
if fromBalance < amount {
fmt.Println("余额不足")
return false
}
// 扣减转出账户余额多条件必须用AND
affected1 := tx.Update("user", common.Map{
"balance[#]": fmt.Sprintf("balance - %.2f", amount),
"updated_time[#]": "NOW()",
}, common.Map{
"AND": common.Map{
"id": fromUserId,
"balance[>=]": amount, // 再次确保余额足够
},
})
if affected1 == 0 {
fmt.Println("扣减余额失败")
return false
}
// 增加转入账户余额(单条件)
affected2 := tx.Update("user", common.Map{
"balance[#]": fmt.Sprintf("balance + %.2f", amount),
"updated_time[#]": "NOW()",
}, common.Map{
"id": toUserId,
})
if affected2 == 0 {
fmt.Println("增加余额失败")
return false
}
// 记录转账日志
logId := tx.Insert("transfer_log", common.Map{
"from_user_id": fromUserId,
"to_user_id": toUserId,
"amount": amount,
"status": "success",
"created_time[#]": "NOW()",
})
if logId == 0 {
fmt.Println("记录日志失败")
return false
}
fmt.Printf("转账成功: 用户%d -> 用户%d, 金额:%.2f\n", fromUserId, toUserId, amount)
return true
})
if success {
fmt.Println("事务执行成功")
} else {
fmt.Println("事务回滚")
if db.LastErr.GetError() != nil {
fmt.Println("错误原因:", db.LastErr.GetError())
}
}
}
// 示例9: 缓存机制(修正版)
func Example9_CacheSystem_Fixed(db *db.HoTimeDB) {
fmt.Println("=== 缓存机制示例 ===")
// 设置缓存(实际项目中需要配置缓存参数)
db.HoTimeCache = &cache.HoTimeCache{}
// 第一次查询(会缓存结果)
fmt.Println("第一次查询(会缓存)...")
users1 := db.Select("user", "*", common.Map{
"status": 1, // 单条件
"LIMIT": 10,
})
fmt.Printf("查询到 %d 个用户\n", len(users1))
// 第二次相同查询(从缓存获取)
fmt.Println("第二次相同查询(从缓存获取)...")
users2 := db.Select("user", "*", common.Map{
"status": 1, // 单条件
"LIMIT": 10,
})
fmt.Printf("查询到 %d 个用户\n", len(users2))
// 更新操作会清除缓存
fmt.Println("执行更新操作(会清除缓存)...")
affected := db.Update("user", common.Map{
"updated_time[#]": "NOW()",
}, common.Map{
"id": 1, // 单条件
})
fmt.Printf("更新 %d 条记录\n", affected)
// 再次查询(重新从数据库获取并缓存)
fmt.Println("更新后再次查询(重新缓存)...")
users3 := db.Select("user", "*", common.Map{
"status": 1, // 单条件
"LIMIT": 10,
})
fmt.Printf("查询到 %d 个用户\n", len(users3))
}
// 示例10: 性能优化技巧(修正版)
func Example10_PerformanceOptimization_Fixed(db *db.HoTimeDB) {
fmt.Println("=== 性能优化技巧示例 ===")
// IN查询优化连续数字自动转为BETWEEN
fmt.Println("IN查询优化示例...")
users := db.Select("user", "*", common.Map{
"id": []int{1, 2, 3, 4, 5, 10, 11, 12, 13, 20}, // 单个IN条件会被优化
})
fmt.Printf("查询到 %d 个用户\n", len(users))
fmt.Println("执行的SQL:", db.LastQuery)
// 批量插入(使用事务)
fmt.Println("\n批量插入示例...")
success := db.Action(func(tx db.HoTimeDB) bool {
for i := 1; i <= 100; i++ {
id := tx.Insert("user_batch", common.Map{
"name": fmt.Sprintf("批量用户%d", i),
"email": fmt.Sprintf("batch%d@example.com", i),
"status": 1,
"created_time[#]": "NOW()",
})
if id == 0 {
return false
}
// 每10个用户输出一次进度
if i%10 == 0 {
fmt.Printf("已插入 %d 个用户\n", i)
}
}
return true
})
if success {
fmt.Println("批量插入完成")
} else {
fmt.Println("批量插入失败")
}
// 索引友好的查询(修正版)
fmt.Println("\n索引友好的查询...")
recentUsers := db.Select("user", "*", common.Map{
"AND": common.Map{
"created_time[>]": "2023-01-01", // 假设created_time有索引
"status": 1, // 假设status有索引
},
"ORDER": "created_time DESC", // 利用索引排序
"LIMIT": 20,
})
fmt.Printf("查询到 %d 个近期用户\n", len(recentUsers))
}
// 完整的应用示例(修正版)
func CompleteExample_Fixed() {
fmt.Println("=== HoTimeDB完整应用示例修正版 ===")
// 初始化数据库
database := &db.HoTimeDB{
Prefix: "app_",
Mode: 1, // 测试模式
Type: "mysql",
}
// 设置连接
database.SetConnect(func(err ...*common.Error) (master, slave *sql.DB) {
// 这里使用实际的数据库连接字符串
dsn := "root:password@tcp(localhost:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"
master, dbErr := sql.Open("mysql", dsn)
if dbErr != nil {
log.Fatal("数据库连接失败:", dbErr)
}
return master, master
})
// 用户管理系统示例
fmt.Println("\n=== 用户管理系统 ===")
// 1. 创建用户
userId := database.Insert("user", common.Map{
"name": "示例用户",
"email": "example@test.com",
"password": "hashed_password",
"age": 28,
"status": 1,
"level": "normal",
"balance": 500.00,
"created_time[#]": "NOW()",
})
fmt.Printf("创建用户成功ID: %d\n", userId)
// 2. 用户登录更新多条件用AND
database.Update("user", common.Map{
"last_login[#]": "NOW()",
"login_count[#]": "login_count + 1",
}, common.Map{
"AND": common.Map{
"id": userId,
"status": 1,
},
})
// 3. 创建订单
orderId := database.Insert("order", common.Map{
"user_id": userId,
"amount": 299.99,
"status": "pending",
"created_time[#]": "NOW()",
})
fmt.Printf("创建订单成功ID: %d\n", orderId)
// 4. 订单支付(使用事务,修正版)
paymentSuccess := database.Action(func(tx db.HoTimeDB) bool {
// 更新订单状态(单条件)
affected1 := tx.Update("order", common.Map{
"status": "paid",
"paid_time[#]": "NOW()",
}, common.Map{
"id": orderId,
})
if affected1 == 0 {
return false
}
// 扣减用户余额多条件用AND
affected2 := tx.Update("user", common.Map{
"balance[#]": "balance - 299.99",
}, common.Map{
"AND": common.Map{
"id": userId,
"balance[>=]": 299.99, // 确保余额足够
},
})
if affected2 == 0 {
fmt.Println("余额不足或用户不存在")
return false
}
// 记录支付日志
logId := tx.Insert("payment_log", common.Map{
"user_id": userId,
"order_id": orderId,
"amount": 299.99,
"type": "order_payment",
"status": "success",
"created_time[#]": "NOW()",
})
return logId > 0
})
if paymentSuccess {
fmt.Println("订单支付成功")
} else {
fmt.Println("订单支付失败")
}
// 5. 查询用户订单列表(链式查询)
userOrders := database.Table("order").
LeftJoin("user", "order.user_id = user.id").
Where("order.user_id", userId). // 链式中单个条件可以直接Where
Order("order.created_time DESC").
Select(`
order.id,
order.amount,
order.status,
order.created_time,
order.paid_time,
user.name as user_name
`)
fmt.Printf("\n用户订单列表 (%d个订单):\n", len(userOrders))
for _, order := range userOrders {
fmt.Printf(" 订单ID:%v, 金额:%v, 状态:%s, 创建时间:%v\n",
order.Get("id"),
order.Get("amount"),
order.GetString("status"),
order.Get("created_time"))
}
// 6. 生成统计报表(修正版)
stats := database.Select("order",
common.Slice{
common.Map{"[>]user": "order.user_id = user.id"},
},
`
DATE(order.created_time) as date,
COUNT(order.id) as order_count,
SUM(order.amount) as total_amount,
AVG(order.amount) as avg_amount
`,
common.Map{
"AND": common.Map{
"order.status": "paid",
"order.created_time[>]": "2023-01-01",
},
"GROUP": "DATE(order.created_time)",
"ORDER": "date DESC",
"LIMIT": 30,
})
fmt.Printf("\n最近30天订单统计:\n")
for _, stat := range stats {
fmt.Printf("日期:%v, 订单数:%v, 总金额:%v, 平均金额:%v\n",
stat.Get("date"),
stat.Get("order_count"),
stat.Get("total_amount"),
stat.Get("avg_amount"))
}
fmt.Println("\n示例执行完成")
}
// 语法对比示例
func SyntaxComparison() {
fmt.Println("=== HoTimeDB语法对比 ===")
// 模拟数据库对象
var db *db.HoTimeDB
fmt.Println("❌ 错误语法示例(不支持):")
fmt.Println(`
// 这样写是错误的多个条件不能直接放在根Map中
wrongUsers := db.Select("user", "*", common.Map{
"status": 1, // ❌ 错误
"age[>]": 18, // ❌ 错误
"ORDER": "id DESC",
})
`)
fmt.Println("✅ 正确语法示例:")
fmt.Println(`
// 单个条件可以直接写
correctUsers1 := db.Select("user", "*", common.Map{
"status": 1, // ✅ 正确,单个条件
})
// 多个条件必须用AND包装
correctUsers2 := db.Select("user", "*", common.Map{
"AND": common.Map{ // ✅ 正确多个条件用AND包装
"status": 1,
"age[>]": 18,
},
"ORDER": "id DESC", // ✅ 正确,特殊参数与条件同级
})
// OR条件
correctUsers3 := db.Select("user", "*", common.Map{
"OR": common.Map{ // ✅ 正确OR条件
"level": "vip",
"balance[>]": 1000,
},
})
// 嵌套条件
correctUsers4 := db.Select("user", "*", common.Map{
"AND": common.Map{ // ✅ 正确,嵌套条件
"status": 1,
"OR": common.Map{
"age[<]": 30,
"level": "vip",
},
},
"ORDER": "created_time DESC",
"LIMIT": 20,
})
`)
// 实际不执行查询,只是展示语法
_ = db
}
// 运行所有修正后的示例
func RunAllFixedExamples() {
fmt.Println("开始运行HoTimeDB所有修正后的示例...")
fmt.Println("注意:实际运行时需要确保数据库连接正确,并且相关表存在")
// 展示语法对比
SyntaxComparison()
fmt.Println("请根据实际环境配置数据库连接后运行相应示例")
fmt.Println("所有示例代码已修正完毕,语法正确!")
}
func main() {
// 运行语法对比示例
RunAllFixedExamples()
}

17
go.mod Normal file
View File

@ -0,0 +1,17 @@
module code.hoteas.com/golang/hotime
go 1.16
require (
github.com/360EntSecGroup-Skylar/excelize v1.4.1
github.com/garyburd/redigo v1.6.3
github.com/go-pay/gopay v1.5.78
github.com/go-sql-driver/mysql v1.6.0
github.com/mattn/go-sqlite3 v1.14.12
github.com/silenceper/wechat/v2 v2.1.2
github.com/sirupsen/logrus v1.8.1
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.364
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr v1.0.364
go.mongodb.org/mongo-driver v1.10.1
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
)

107
go.sum Normal file
View File

@ -0,0 +1,107 @@
github.com/360EntSecGroup-Skylar/excelize v1.4.1 h1:l55mJb6rkkaUzOpSsgEeKYtS6/0gHwBYyfo5Jcjv/Ks=
github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE=
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/garyburd/redigo v1.6.3 h1:HCeeRluvAgMusMomi1+6Y5dmFOdYV/JzoRrrbFlkGIc=
github.com/garyburd/redigo v1.6.3/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
github.com/go-pay/gopay v1.5.78 h1:wIHp8g/jK0ik5bZo2MWt3jAQsktT3nkdXZxlRZvljko=
github.com/go-pay/gopay v1.5.78/go.mod h1:M6Nlk2VdZHCbWphOw3rtbnz4SiOk6Xvxg6mxwDfg+Ps=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/silenceper/wechat/v2 v2.1.2 h1:+QfIMiYfwST2ZloTwmYp0O0p5Y1LYRZxfLWfMuSE30k=
github.com/silenceper/wechat/v2 v2.1.2/go.mod h1:0OprxYCCp2CZAKw06BBlnaczInTk2KxOLsKeiopshGg=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.364 h1:X1Jws4XqrTH+p7FBQ7BpjW4qFXObKHWm0/XhW/GvqRs=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.364/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr v1.0.364 h1:kbor60vo37v7Hu+i17gooox9Rw281fVHNna8zwtDG1w=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr v1.0.364/go.mod h1:LeIUBOLhc+Y5YCEpZrULPD9lgoXXV4/EmIcoEvmHz9c=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
go.mongodb.org/mongo-driver v1.10.1 h1:NujsPveKwHaWuKUer/ceo9DzEe7HIj1SlJ6uvXZG0S4=
go.mongodb.org/mongo-driver v1.10.1/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0=
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -82,10 +82,29 @@ func findCaller(skip int) string {
for i := 0; i < 10; i++ {
file, line = getCaller(skip + i)
if !strings.HasPrefix(file, "logrus") {
if file == "common/error.go" {
file, line = getCaller(skip + i + 1)
j := 0
for true {
j++
if file == "common/error.go" {
file, line = getCaller(skip + i + j)
}
if file == "db/hotimedb.go" {
file, line = getCaller(skip + i + j)
}
if file == "code/makecode.go" {
file, line = getCaller(skip + i + j)
}
if strings.Index(file, "common/") == 0 {
file, line = getCaller(skip + i + j)
}
if strings.Contains(file, "application.go") {
file, line = getCaller(skip + i + j)
}
if j == 5 {
break
}
}
break
}
}

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