Compare commits

..

169 Commits

Author SHA1 Message Date
橙子
f203c53e19 Merge branch 'abp' into digital-collectibles 2025-02-04 15:40:13 +08:00
橙子
8a9a0c8396 fix: 修复跳转刷新问题 2025-02-04 15:40:00 +08:00
橙子
813b08bf1c Merge branch 'abp' into digital-collectibles
# Conflicts:
#	Yi.Bbs.Vue3/src/views/home/Index.vue
2025-02-04 15:28:23 +08:00
橙子
bce9b58265 perf: 优化bbs前端整体显示 2025-02-04 15:23:20 +08:00
橙子
85223629c1 Merge branch 'refs/heads/abp' into digital-collectibles 2025-02-03 10:30:26 +08:00
橙子
9a73789788 feat: 全面支持deepseek 2025-02-03 01:18:15 +08:00
橙子
25929483c3 feat: 支持多ai聊天 2025-02-02 00:22:27 +08:00
橙子
0e90c54dbb Merge remote-tracking branch 'origin/abp' into abp 2025-02-01 21:53:12 +08:00
橙子
5dea4ab18c feat: 支持分布式锁 2025-02-01 21:53:05 +08:00
橙子
7187397687 !87 update Yi.RuoYi.Vue3/src/views/system/role/index.vue.
Merge pull request !87 from YangHaiPing/N/A
2025-01-31 13:58:12 +00:00
橙子
bf8454a963 !84 拼写错误
Merge pull request !84 from 高级CV工程师/abp
2025-01-31 13:57:21 +00:00
橙子
2b2ac9b924 !86 refactor(tool): 使工具支持跨平台运行
Merge pull request !86 from a2008q/abp
2025-01-31 13:56:36 +00:00
YangHaiPing
78b874936c update Yi.RuoYi.Vue3/src/views/system/role/index.vue.
系统管理-角色管理-数据权限:数据回显时“权限范围”字段信息展示的为对应索引值,不是下拉选项值

Signed-off-by: YangHaiPing <yang1426251993@163.com>
2025-01-30 19:10:35 +00:00
易昊弘
b9866af6cd refactor(tool): 优化模块添加命令执行逻辑
- 优化了路径组合的方式,使代码更加简洁
- 修复AddModule在mac/linux下只能添加一个文件夹的问题
2025-01-22 17:58:46 +08:00
易昊弘
350e4a5753 refactor(tool): 使工具支持跨平台运行
- 在 AddModuleCommand 和 CloneCommand 中增加了对操作系统类型的判断
- 为 Windows、macOS 和 Linux 系统分别设置了不同的进程启动信息
-优化了路径组合方式,使用 Path.Combine 以确保跨平台兼容性
2025-01-21 19:35:30 +08:00
橙子
2544d03434 Merge branch 'refs/heads/abp' into digital-collectibles 2025-01-19 18:53:20 +08:00
橙子
d1c1eed52e fix: 修复权限校验报错 2025-01-19 18:53:09 +08:00
橙子
2329cfd1da Merge branch 'refs/heads/abp' into digital-collectibles 2025-01-19 18:41:03 +08:00
橙子
9960c63f59 feat: 新增角色查看主题权限 2025-01-19 18:40:42 +08:00
橙子
680f9ae246 Merge branch 'abp' into digital-collectibles 2025-01-19 15:42:10 +08:00
橙子
7994e66283 fix: 修复有序及无序标签显示 2025-01-19 15:41:59 +08:00
橙子
2c9d344b76 feat: 完善标签分类功能 2025-01-19 15:17:48 +08:00
橙子
6a9e28700b Merge branch 'refs/heads/abp' into digital-collectibles 2025-01-19 13:23:23 +08:00
橙子
811e5c1a8c fix: 删除多余types 2025-01-19 13:23:12 +08:00
橙子
545cef34a9 feat: 新增知识宝典 2025-01-19 13:20:09 +08:00
橙子
950c89a8bc Merge branch 'refs/heads/abp' into digital-collectibles 2025-01-19 13:14:24 +08:00
橙子
7b5bc0fe3e perf: 优化主题权限 2025-01-19 13:14:08 +08:00
橙子
e05514bc41 chorm: 修改包 2025-01-19 03:32:17 +08:00
橙子
438abf6cea feat: 新增标签模块 2025-01-19 03:31:48 +08:00
橙子
5d5ebb559b Merge branch 'refs/heads/abp' into digital-collectibles 2025-01-18 01:09:42 +08:00
橙子
3be5675828 perf: 优化主题查询 2025-01-18 01:07:38 +08:00
橙子
6482218a68 fix: 修复sqlsguar删除事件 2025-01-17 17:09:50 +08:00
橙子
8d6824b03d fix: 修复授权接口 2025-01-04 17:29:05 +08:00
橙子
69ab65dbc6 Merge branch 'refs/heads/abp' into digital-collectibles 2024-12-26 23:05:18 +08:00
橙子
4b0b0e4451 fix: 修正file为空捕获 2024-12-26 23:02:10 +08:00
橙子
5d21fd0f7c Merge branch 'refs/heads/abp' into digital-collectibles 2024-12-26 21:58:53 +08:00
橙子
0184015ba8 feat:仓储支持工作单元 2024-12-26 21:58:42 +08:00
橙子
ffb329a0d9 feat:支持双开关切换 2024-12-26 21:57:27 +08:00
高级CV工程师
03a712fcfe 优化token输入 2024-12-23 19:25:56 +08:00
高级CV工程师
652c2b6fd0 拼写错误 2024-12-23 12:15:16 +08:00
橙子
f0093499d1 Merge branch 'refs/heads/abp' into digital-collectibles 2024-12-21 23:31:17 +08:00
橙子
c00ada5aee refactor: 完成文件模块优化重构 2024-12-21 23:00:43 +08:00
橙子
6c409bfa00 refactor: 重构文件模块 2024-12-21 18:00:43 +08:00
橙子
1c7637d28b Merge branch 'refs/heads/abp' into digital-collectibles 2024-12-21 15:06:15 +08:00
橙子
48dc89c43d feat: 支持对不同数据库的guid设置方式 2024-12-21 15:04:54 +08:00
橙子
b60cc50508 Merge remote-tracking branch 'origin/abp' into abp 2024-12-21 14:49:58 +08:00
橙子
4e66762036 fix: 修复问题权限赋值 2024-12-21 14:49:51 +08:00
橙子
ff4e1dd182 !82 docker 构建
Merge pull request !82 from fenngmr/feat-docker-build
2024-12-21 06:46:08 +00:00
橙子
36442072ba !83 options 拼写错误
Merge pull request !83 from 高级CV工程师/N/A
2024-12-21 06:45:35 +00:00
高级CV工程师
ea134f52be options 拼写错误
Signed-off-by: 高级CV工程师 <2535688890@qq.com>
2024-12-21 03:33:37 +00:00
fengxian.guo
fe97ba1c19 feat: docker 构建失败问题解决,及docker构建文档 2024-12-21 08:57:23 +08:00
fengxian.guo
2cd8b73aa3 feat: docker 构建失败问题解决,及docker构建文档 2024-12-21 08:37:10 +08:00
橙子
07a5b69511 !81 数据字典详情页重复代码修复
Merge pull request !81 from canye/abp
2024-12-15 09:15:23 +00:00
canye
da0e207b44 数据字典详情页重复代码修复 2024-12-15 17:02:36 +08:00
橙子
fb0edc0ee0 fix: 修复pure问题 2024-12-15 11:32:41 +08:00
橙子
8a26a4aeec fix: 修复pure若干问题 2024-12-15 11:32:04 +08:00
橙子
723ce1bd5d Merge branch 'refs/heads/abp' into digital-collectibles 2024-12-11 19:49:46 +08:00
橙子
8408b39fbb style: 文件未找到,不提示 2024-12-11 19:48:37 +08:00
橙子
5dfaf75440 feat: 新增实体领域事件 2024-12-10 22:04:46 +08:00
橙子
bb3b3702e1 fix: 支持缓存 2024-12-10 00:08:04 +08:00
橙子
81138fcaef Merge branch 'refs/heads/abp' into digital-collectibles 2024-12-10 00:06:14 +08:00
橙子
6be5398114 perf: 优化等级处理 2024-12-08 03:43:04 +08:00
chenchun
365ae8ef0a Merge branch 'refs/heads/abp' into digital-collectibles 2024-12-02 10:11:55 +08:00
chenchun
3932b24fda fix: 修复审计日志无工作单元 2024-12-02 10:11:25 +08:00
橙子
f44737216f feat: 合并 2024-11-30 23:53:24 +08:00
橙子
e4180a0c1a Merge branch 'refs/heads/abp' into digital-collectibles
# Conflicts:
#	Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
2024-11-30 23:52:33 +08:00
橙子
356938d6d3 pref: 优化db工作单元 2024-11-30 23:45:19 +08:00
chenchun
1090907178 perf: 优化动态api启动 2024-11-29 18:01:54 +08:00
chenchun
da2f7073f9 style: 优化abp-cli提示 2024-11-29 15:25:16 +08:00
chenchun
57fe0e702c Merge remote-tracking branch 'origin/digital-collectibles' into digital-collectibles 2024-11-29 15:01:10 +08:00
chenchun
90d4a98e1e perf: 优化购买商品 2024-11-29 15:00:57 +08:00
chenchun
d047f8aa32 Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-29 14:58:27 +08:00
chenchun
f656ec32c1 perf: 优化在线hub 2024-11-29 14:58:10 +08:00
橙子
3415543175 feat: 支持自动刷新价值调整 2024-11-24 19:07:42 +08:00
chenchun
4191bc86ef Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-20 16:11:53 +08:00
chenchun
1cc0ef916f feat:去除SqlSugarDbContextFactory的缓存 2024-11-20 16:11:33 +08:00
chenchun
fdbee4562a Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-20 13:44:30 +08:00
chenchun
5d793344cd fix: 修复移除属性注入 2024-11-20 13:43:35 +08:00
橙子
559a45c917 Merge branch 'refs/heads/abp' into digital-collectibles
# Conflicts:
#	Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarCoreExtensions.cs
#	Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
2024-11-19 21:48:48 +08:00
橙子
cadbc09846 update Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlsugarCoreExtensions.cs.
Signed-off-by: 橙子 <454313500@qq.com>
2024-11-19 13:45:54 +00:00
橙子
bcaca0b782 Merge branch 'refs/heads/multipleDbContext' into abp
# Conflicts:
#	Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarCoreExtensions.cs
2024-11-19 21:44:57 +08:00
橙子
5cee7319c6 update Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlsugarCoreExtensions.cs.
Signed-off-by: 橙子 <454313500@qq.com>
2024-11-19 13:43:25 +00:00
橙子
d8286fb005 style: 新增背景,部分页面bbs适配移动端 2024-11-17 12:19:48 +08:00
橙子
a7bf5e8873 Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-16 13:10:17 +08:00
橙子
a2e2072634 Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-16 11:07:35 +08:00
橙子
32e4145927 Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-16 11:01:18 +08:00
橙子
e94c65d24a fix: 增加判断 2024-11-16 10:54:14 +08:00
橙子
e72c0d4480 chorm: 构建 2024-11-15 22:08:48 +08:00
橙子
1a7f1c3d15 fix: 新增商品内容 2024-11-15 22:06:15 +08:00
橙子
ace5374813 Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-15 21:39:14 +08:00
橙子
644045b307 feat: 支持hangfire 2024-11-15 20:24:17 +08:00
橙子
0bf53a1c0d Merge branch 'refs/heads/abp' into digital-collectibles
# Conflicts:
#	Yi.Abp.Net8/Yi.Abp.sln
#	Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogCacheJob.cs
#	Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/DemoResetJob.cs
#	Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
2024-11-15 20:16:23 +08:00
橙子
05ca1aa224 feat: 支持商品自动流拍 2024-11-14 20:30:48 +08:00
chenchun
02d45bb6a7 feat: 支持自动下架商品 2024-11-14 18:56:10 +08:00
橙子
8e805a4cf8 Merge remote-tracking branch 'origin/digital-collectibles' into digital-collectibles
# Conflicts:
#	Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/Analyses/BbsUserAnalyseService.cs
#	Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/Analyses/ValueAnalyseService.cs
#	Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Managers/CollectiblesManager.cs
2024-11-13 22:34:18 +08:00
chenchun
43c4c03832 feat: 完成积分、价值排行榜 2024-11-13 22:32:42 +08:00
chenchun
bf2bcd1395 feat: 完成积分、价值排行榜 2024-11-13 19:01:23 +08:00
橙子
f9217dc066 style: 新增shop 2024-11-12 22:29:06 +08:00
橙子
dad4ca4ab4 fix: 修复钱钱保留两位小数 2024-11-11 23:40:20 +08:00
橙子
b282ee8273 style: 新增wxss支持 2024-11-10 22:31:56 +08:00
橙子
3dcb7d0a39 style: 修改概率 2024-11-10 20:21:08 +08:00
橙子
6703897fb1 feat: 完善小程序通知 2024-11-10 20:17:36 +08:00
橙子
eef2ed0d64 Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-10 17:33:34 +08:00
橙子
7c13ed6497 fix: 修复依赖注入问题 2024-11-10 17:14:50 +08:00
橙子
93dea4fa46 feat: 支持微信通知 2024-11-10 13:41:04 +08:00
橙子
83fb93da11 feat: 完成微信小程序消息推送 2024-11-09 19:05:42 +08:00
橙子
3fbaffe9a2 feat: 优化账号绑定逻辑 2024-11-09 01:20:53 +08:00
橙子
3b93e8b8ec fix: 修复缓存批量删除 2024-11-09 00:00:02 +08:00
chenchun
24cf087320 Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-08 13:58:13 +08:00
chenchun
81f9fd7473 fix:修复矿池刷新数量 2024-11-04 18:54:35 +08:00
橙子
e2091eb986 chorm: 构建 2024-11-03 21:16:01 +08:00
橙子
22a8703978 feat: 完成bbs商城 2024-11-03 18:01:47 +08:00
橙子
1468a7b878 feat: 完成商城系统 2024-11-03 15:49:41 +08:00
橙子
fe7211860f feat: 搭建商城基础业务 2024-11-03 15:27:01 +08:00
橙子
fddf80e74a feat: 新增商城领域 2024-11-03 02:38:05 +08:00
橙子
5054391f6b feat: 完成账号绑定功能 2024-11-03 01:38:12 +08:00
橙子
5e096a277c Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-02 21:06:59 +08:00
橙子
a21f2342d8 Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-02 15:48:40 +08:00
橙子
ab6563899c Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-02 15:35:10 +08:00
橙子
f82122edf0 Merge branch 'refs/heads/abp' into digital-collectibles 2024-11-02 15:29:07 +08:00
橙子
76d94c0bc9 fix: 修复定时任务 2024-11-02 13:31:18 +08:00
chenchun
31dceec787 feat: 新增邀请码 2024-11-01 18:37:46 +08:00
橙子
a2106bba3e Merge branch 'refs/heads/abp' into digital-collectibles 2024-10-31 21:21:52 +08:00
chenchun
b321283f99 fix: 修复code生成规则 2024-10-31 14:27:34 +08:00
chenchun
505e4b6586 feat: 完成 2024-10-30 18:25:44 +08:00
chenchun
b2efd065be feat: 新增记录 2024-10-30 12:02:34 +08:00
chenchun
050af30acb Merge branch 'refs/heads/abp' into digital-collectibles 2024-10-30 11:49:15 +08:00
chenchun
677dca2231 feat: 新增记录 2024-10-30 11:48:13 +08:00
橙子
47ca08e432 Merge branch 'refs/heads/abp' into digital-collectibles 2024-10-29 22:40:38 +08:00
chenchun
1cb396aa14 feat: 支持接口控制 2024-10-29 14:26:23 +08:00
橙子
a47d271a33 feat: 完善,调整矿物刷新 2024-10-28 22:40:23 +08:00
橙子
363be13d12 fix: 修复上架物品问题 2024-10-28 20:56:33 +08:00
chenchun
3bc044e148 feat: 新增挖矿成功事件 2024-10-28 18:37:15 +08:00
chenchun
b8e6dfcd99 feat:新增成功挖到矿物事件 2024-10-28 16:29:38 +08:00
chenchun
4b320c2af2 fix: 修复个人仓库 2024-10-28 13:53:09 +08:00
橙子
dc28d701ba Merge branch 'refs/heads/abp' into digital-collectibles 2024-10-27 21:48:58 +08:00
橙子
77c423f421 Merge branch 'refs/heads/abp' into digital-collectibles 2024-10-26 20:27:11 +08:00
橙子
8a157ba472 Merge branch 'refs/heads/abp' into digital-collectibles
# Conflicts:
#	Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
2024-10-26 15:52:33 +08:00
橙子
779e84213e feat: 支持手机号为空的临时账号 2024-10-26 10:21:16 +08:00
橙子
254975fcd3 fix: 修复登录 2024-10-25 20:45:35 +08:00
chenchun
e5773df1ab fix: 修复bug 2024-10-25 17:55:18 +08:00
chenchun
c2290f95cf feat: 兼容支持用户名_ 2024-10-25 17:36:23 +08:00
chenchun
6eb72c0303 Merge branch 'refs/heads/abp' into digital-collectibles 2024-10-25 17:31:36 +08:00
chenchun
c4e79e46cf Merge branch 'refs/heads/pr_74' into digital-collectibles
# Conflicts:
#	Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/DictionaryService.cs
2024-10-25 17:30:10 +08:00
橙子
4fadba27dc style: 优化样式 2024-10-24 21:39:20 +08:00
chenchun
7eab4dd5b1 feat: 完成账号逻辑处理 2024-10-22 12:20:53 +08:00
橙子
0e6d380b7e feat: 补充绑定逻辑 2024-10-21 23:35:10 +08:00
橙子
1a73f7bef3 Merge branch 'refs/heads/abp' into digital-collectibles 2024-10-21 23:29:09 +08:00
橙子
a518e7b210 Merge branch 'refs/heads/abp' into digital-collectibles
# Conflicts:
#	Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
2024-10-21 23:08:21 +08:00
橙子
e2dae1c4ab Merge remote-tracking branch 'refs/remotes/origin/abp-dev-10-21' into digital-collectibles 2024-10-21 20:08:15 +08:00
橙子
0d00f91b31 style: 开启审计日志 2024-10-20 23:43:35 +08:00
橙子
d3b87e8984 style: 调整概率 2024-10-20 22:37:13 +08:00
橙子
fcaad5c6cc feat: 新增用户信息 2024-10-20 22:31:39 +08:00
橙子
8ca741792a fix: 修复挖矿计算问题 2024-10-19 22:44:50 +08:00
橙子
0f687a7e34 feat: 完成微信小程序账户应用服务 2024-10-19 16:17:26 +08:00
橙子
736995c35b feat: 新增微信小程序模块 2024-10-19 14:02:29 +08:00
chenchun
4ae548cc5b Merge branch 'refs/heads/abp' into digital-collectibles 2024-10-18 13:25:57 +08:00
橙子
942868f17f fix: 修复依赖注入问题 2024-10-17 23:45:38 +08:00
橙子
8a57bf52f9 Merge branch 'refs/heads/abp' into digital-collectibles 2024-10-17 23:03:49 +08:00
橙子
260d87c97e feat: 完成 2024-10-17 00:27:20 +08:00
橙子
cb1bac25a3 style: 修改概率 2024-10-16 22:48:11 +08:00
橙子
ef20ef7014 feat: 完成搭建基础功能 2024-10-16 22:47:04 +08:00
chenchun
b88cad7b80 feat: 新增配置 2024-10-16 17:49:47 +08:00
橙子
3383e86064 feat: 完成基础接口搭建 2024-10-15 22:14:14 +08:00
橙子
a0ef3af155 feat: 完成基础框架搭建 2024-10-15 21:50:31 +08:00
chenchun
e8fcab4c6b feat: 新增矿池机制 2024-10-15 18:32:50 +08:00
橙子
1c6a795061 feat: 框架搭建 2024-10-14 23:31:08 +08:00
橙子
36246c2945 feat: 新增数字藏品模块 2024-10-14 22:40:28 +08:00
橙子
7af54f600f feat: 搭建模块 2024-10-14 21:45:14 +08:00
253 changed files with 7238 additions and 1689 deletions

1
.gitignore vendored
View File

@@ -275,3 +275,4 @@ database_backup
/Yi.Abp.Net8/src/Yi.Abp.Web/logs/
/Yi.Abp.Net8/src/Yi.Abp.Web/yi-abp-dev.db
package-lock.json

View File

@@ -156,6 +156,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.HttpApi.Client"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.SettingManagement.Application", "module\setting-management\Yi.Framework.SettingManagement.Application\Yi.Framework.SettingManagement.Application.csproj", "{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "digital-collectibles", "digital-collectibles", "{B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.Application", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.Application\Yi.Framework.DigitalCollectibles.Application.csproj", "{236B88D4-F018-4A5F-A506-7458F2308C70}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.Application.Contracts", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.Application.Contracts\Yi.Framework.DigitalCollectibles.Application.Contracts.csproj", "{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.Domain", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.Domain\Yi.Framework.DigitalCollectibles.Domain.csproj", "{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.Domain.Shared", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.Domain.Shared\Yi.Framework.DigitalCollectibles.Domain.Shared.csproj", "{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.SqlSugarCore", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.SqlSugarCore\Yi.Framework.DigitalCollectibles.SqlSugarCore.csproj", "{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.WeChat.MiniProgram", "framework\Yi.Framework.WeChat.MiniProgram\Yi.Framework.WeChat.MiniProgram.csproj", "{81CEA2ED-917B-41D8-BE0D-39A785B050C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.BackgroundWorkers.Hangfire", "framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj", "{862CA181-BEE6-4870-82D2-B662E527ED8C}"
EndProject
Global
@@ -392,6 +406,30 @@ Global
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.Build.0 = Release|Any CPU
{236B88D4-F018-4A5F-A506-7458F2308C70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{236B88D4-F018-4A5F-A506-7458F2308C70}.Debug|Any CPU.Build.0 = Debug|Any CPU
{236B88D4-F018-4A5F-A506-7458F2308C70}.Release|Any CPU.ActiveCfg = Release|Any CPU
{236B88D4-F018-4A5F-A506-7458F2308C70}.Release|Any CPU.Build.0 = Release|Any CPU
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}.Release|Any CPU.Build.0 = Release|Any CPU
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}.Release|Any CPU.Build.0 = Release|Any CPU
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}.Release|Any CPU.Build.0 = Release|Any CPU
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Release|Any CPU.Build.0 = Release|Any CPU
{81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.Build.0 = Release|Any CPU
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -465,6 +503,13 @@ Global
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{C8F97775-D903-4365-A4FF-3DA97E318CD2} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
{B8F76A6B-2EEB-4E64-9F26-D84584E16B9C} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
{236B88D4-F018-4A5F-A506-7458F2308C70} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
{81CEA2ED-917B-41D8-BE0D-39A785B050C0} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{862CA181-BEE6-4870-82D2-B662E527ED8C} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution

View File

@@ -9,84 +9,89 @@ using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Options;
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
{
public static class SwaggerAddExtensions
{
public static IServiceCollection AddYiSwaggerGen<Program>(this IServiceCollection services, Action<SwaggerGenOptions>? action=null)
public static IServiceCollection AddYiSwaggerGen<Program>(this IServiceCollection services,
Action<SwaggerGenOptions>? action = null)
{
var serviceProvider = services.BuildServiceProvider();
var mvcOptions = serviceProvider.GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>();
var mvcSettings = mvcOptions.Value.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
var mvcOptions = services.GetPreConfigureActions<AbpAspNetCoreMvcOptions>().Configure();
var mvcSettings =
mvcOptions.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
services.AddAbpSwaggerGen(
options =>
{
if (action is not null)
options =>
{
action.Invoke(options);
}
// 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
{
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
if (action is not null)
{
options.SwaggerDoc(setting.RemoteServiceName, new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
action.Invoke(options);
}
}
// 根据分组名称过滤 API 文档
options.DocInclusionPredicate((docName, apiDesc) =>
{
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
// 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
{
var settingOrNull = mvcSettings.Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly).FirstOrDefault();
if (settingOrNull is not null)
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
{
return docName == settingOrNull.RemoteServiceName;
options.SwaggerDoc(setting.RemoteServiceName,
new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
}
}
return false;
});
options.CustomSchemaIds(type => type.FullName);
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
if (basePath is not null)
{
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
// 根据分组名称过滤 API 文档
options.DocInclusionPredicate((docName, apiDesc) =>
{
options.IncludeXmlComments(item, true);
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
{
var settingOrNull = mvcSettings
.Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly)
.FirstOrDefault();
if (settingOrNull is not null)
{
return docName == settingOrNull.RemoteServiceName;
}
}
return false;
});
options.CustomSchemaIds(type => type.FullName);
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
if (basePath is not null)
{
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
{
options.IncludeXmlComments(item, true);
}
}
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
{
Description = "直接输入Token即可",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer"
});
var scheme = new OpenApiSecurityScheme()
{
Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
};
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
[scheme] = new string[0]
});
options.OperationFilter<AddRequiredHeaderParameter>();
options.SchemaFilter<EnumSchemaFilter>();
}
);
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
{
Description = "直接输入Token即可",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer"
});
var scheme = new OpenApiSecurityScheme()
{
Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
};
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
[scheme] = new string[0]
});
options.OperationFilter<AddRequiredHeaderParameter>();
options.SchemaFilter<EnumSchemaFilter>();
}
);
return services;
}
@@ -103,7 +108,6 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
/// </summary>
/// <param name="model"></param>
/// <param name="context"></param>
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type.IsEnum)
@@ -112,7 +116,7 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
model.Type = "string";
model.Format = null;
StringBuilder stringBuilder = new StringBuilder();
Enum.GetNames(context.Type)
.ToList()
@@ -121,9 +125,10 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
Enum e = (Enum)Enum.Parse(context.Type, name);
var descrptionOrNull = GetEnumDescription(e);
model.Enum.Add(new OpenApiString(name));
stringBuilder.Append($"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
stringBuilder.Append(
$"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
});
model.Description= stringBuilder.ToString();
model.Description = stringBuilder.ToString();
}
}
@@ -133,13 +138,13 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : null;
}
}
public class AddRequiredHeaderParameter : IOperationFilter
{
public static string HeaderKey { get; set; } = "__tenant";
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (operation.Parameters == null)
@@ -150,8 +155,8 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
In = ParameterLocation.Header,
Required = false,
AllowEmptyValue = true,
Description="租户id或者租户名称可空为默认租户"
Description = "租户id或者租户名称可空为默认租户"
});
}
}
}
}

View File

@@ -75,6 +75,7 @@ public class YiTokenAuthorizationFilter : IDashboardAsyncAuthorizationFilter, IT
function sendToken() {
// 获取输入的 token
var token = document.getElementById("tokenInput").value;
token = token.replace('Bearer ','');
// 构建请求 URL
var url = "/hangfire";
// 发送 GET 请求
@@ -107,7 +108,7 @@ public class YiTokenAuthorizationFilter : IDashboardAsyncAuthorizationFilter, IT
<body style="text-align: center;">
<h1>Yi-hangfire</h1>
<h1>Token</h1>
<input type="text" id="tokenInput" placeholder="请输入 token" />
<textarea id="tokenInput" placeholder="请输入 token" style="width: 80%;height: 120px;margin: 0 10%;"></textarea>
<button onclick="sendToken()"></button>
</body>
</html>

View File

@@ -11,10 +11,10 @@ namespace Yi.Framework.Core.Enums
/// </summary>
public enum FileTypeEnum
{
File,
Image,
Thumbnail,
Excel,
Temp
file,
image,
thumbnail,
excel,
temp
}
}

View File

@@ -45,8 +45,8 @@ namespace Yi.Framework.Core.Helper
{
var extension = Path.GetExtension(fileName);
if (ImageType.Contains(extension.ToLower()))
return FileTypeEnum.Image;
return FileTypeEnum.File;
return FileTypeEnum.image;
return FileTypeEnum.file;
}

View File

@@ -14,7 +14,7 @@ namespace Yi.Framework.SqlSugarCore.Abstractions
/// SqlSugarDb
/// </summary>
ISqlSugarClient SqlSugarClient { get; }
/// <summary>
/// 数据库备份
/// </summary>

View File

@@ -2,11 +2,12 @@
using SqlSugar;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
public interface ISqlSugarRepository<TEntity>:IRepository<TEntity> where TEntity : class, IEntity,new ()
public interface ISqlSugarRepository<TEntity>:IRepository<TEntity>,IUnitOfWorkEnabled where TEntity : class, IEntity,new ()
{
ISqlSugarClient _Db { get; }
ISugarQueryable<TEntity> _DbQueryable { get; }

View File

@@ -12,6 +12,7 @@ using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
using Volo.Abp.Users;
using Yi.Framework.SqlSugarCore.Abstractions;
@@ -19,19 +20,23 @@ namespace Yi.Framework.SqlSugarCore;
public class DefaultSqlSugarDbContext : SqlSugarDbContext
{
protected DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
protected ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
protected IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>();
protected ILoggerFactory Logger => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
protected IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
public IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled<IMultiTenant>() ?? false;
protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false;
protected IEntityChangeEventHelper EntityChangeEventHelper =>
LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
public DefaultSqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
{
}
protected override void CustomDataFilter(ISqlSugarClient sqlSugarClient)
{
if (IsSoftDeleteFilterEnabled)
@@ -120,7 +125,7 @@ public class DefaultSqlSugarDbContext : SqlSugarDbContext
}
//领域事件
//实体变更领域事件
switch (entityInfo.OperationType)
{
case DataFilterType.InsertByObject:
@@ -149,9 +154,10 @@ public class DefaultSqlSugarDbContext : SqlSugarDbContext
break;
case DataFilterType.DeleteByObject:
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
{
// if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
// {
//这里sqlsugar有个特殊删除会返回批量的结果
//这里sqlsugar有第二个特殊删除事件是行级事件
if (entityInfo.EntityValue is IEnumerable entityValues)
{
foreach (var entityValue in entityValues)
@@ -159,10 +165,18 @@ public class DefaultSqlSugarDbContext : SqlSugarDbContext
EntityChangeEventHelper.PublishEntityDeletedEvent(entityValue);
}
}
}
// }
break;
}
//实体领域事件-所有操作类型
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
{
var eventReport = CreateEventReport(entityInfo.EntityValue);
PublishEntityEvents(eventReport);
}
}
public override void OnLogExecuting(string sql, SugarParameter[] pars)
@@ -204,4 +218,74 @@ public class DefaultSqlSugarDbContext : SqlSugarDbContext
entityColumnInfo.IsPrimarykey = true;
}
}
/// <summary>
/// 创建领域事件报告
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
protected virtual EntityEventReport? CreateEventReport(object entity)
{
var eventReport = new EntityEventReport();
//判断是否为领域事件-聚合根
var generatesDomainEventsEntity = entity as IGeneratesDomainEvents;
if (generatesDomainEventsEntity == null)
{
return eventReport;
}
var localEvents = generatesDomainEventsEntity.GetLocalEvents()?.ToArray();
if (localEvents != null && localEvents.Any())
{
eventReport.DomainEvents.AddRange(
localEvents.Select(
eventRecord => new DomainEventEntry(
entity,
eventRecord.EventData,
eventRecord.EventOrder
)
)
);
generatesDomainEventsEntity.ClearLocalEvents();
}
var distributedEvents = generatesDomainEventsEntity.GetDistributedEvents()?.ToArray();
if (distributedEvents != null && distributedEvents.Any())
{
eventReport.DistributedEvents.AddRange(
distributedEvents.Select(
eventRecord => new DomainEventEntry(
entity,
eventRecord.EventData,
eventRecord.EventOrder)
)
);
generatesDomainEventsEntity.ClearDistributedEvents();
}
return eventReport;
}
/// <summary>
/// 发布领域事件
/// </summary>
/// <param name="changeReport"></param>
private void PublishEntityEvents(EntityEventReport changeReport)
{
foreach (var localEvent in changeReport.DomainEvents)
{
UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(
new UnitOfWorkEventRecord(localEvent.EventData.GetType(), localEvent.EventData, localEvent.EventOrder)
);
}
foreach (var distributedEvent in changeReport.DistributedEvents)
{
UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(
new UnitOfWorkEventRecord(distributedEvent.EventData.GetType(), distributedEvent.EventData, distributedEvent.EventOrder)
);
}
}
}

View File

@@ -7,8 +7,14 @@ namespace Yi.Framework.SqlSugarCore;
public abstract class SqlSugarDbContext : ISqlSugarDbContextDependencies
{
//属性注入
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
protected IAbpLazyServiceProvider LazyServiceProvider { get; }
public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
{
this.LazyServiceProvider = lazyServiceProvider;
}
protected ISqlSugarClient SqlSugarClient { get;private set; }
public int ExecutionOrder => 0;

View File

@@ -37,14 +37,18 @@ namespace Yi.Framework.SqlSugarCore
LazyServiceProvider = lazyServiceProvider;
var connectionString = GetCurrentConnectionString();
//获取连接配置操作,需要进行缓存
var connectionConfig = ConnectionConfigCache.GetOrAdd(connectionString, (_) =>
BuildConnectionConfig(action: options =>
{
options.ConnectionString = connectionString;
options.DbType = GetCurrentDbType();
}));
var connectionConfig =BuildConnectionConfig(action: options =>
{
options.ConnectionString = connectionString;
options.DbType = GetCurrentDbType();
});
// var connectionConfig = ConnectionConfigCache.GetOrAdd(connectionString, (_) =>
// BuildConnectionConfig(action: options =>
// {
// options.ConnectionString = connectionString;
// options.DbType = GetCurrentDbType();
// }));
SqlSugarClient = new SqlSugarClient(connectionConfig);
//生命周期以下都可以直接使用sqlsugardb了
@@ -247,7 +251,6 @@ namespace Yi.Framework.SqlSugarCore
return null;
}
public virtual void BackupDataBase()
{
string directoryName = "database_backup";

View File

@@ -17,4 +17,4 @@ namespace Yi.Framework.SqlSugarCore.Uow
DbContext = dbContext;
}
}
}
}

View File

@@ -35,8 +35,7 @@ namespace Yi.Framework.SqlSugarCore.Uow
CurrentTenant = currentTenant;
Logger = NullLogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>>.Instance;
}
//private static object _databaseApiLock = new object();
public virtual async Task<TDbContext> GetDbContextAsync()
{
@@ -48,19 +47,16 @@ namespace Yi.Framework.SqlSugarCore.Uow
var unitOfWork = UnitOfWorkManager.Current;
if (unitOfWork == null /*|| unitOfWork.Options.IsTransactional == false*/)
if (unitOfWork == null )
{
var dbContext = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
//提高体验,取消工作单元强制性
//throw new AbpException("A DbContext can only be created inside a unit of work!");
//var dbContext = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
//如果不启用工作单元创建一个新的db不开启事务即可
return dbContext;
//return dbContext;
//2024-11-30改回强制性使用工作单元否则容易造成歧义
throw new AbpException("DbContext 只能在工作单元内工作当前DbContext没有工作单元如需创建新线程并发操作请手动创建工作单元");
}
//尝试当前工作单元获取db
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);

View File

@@ -9,6 +9,7 @@ using SqlSugar;
using Volo.Abp.Data;
using Volo.Abp.Domain;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Guids;
using Yi.Framework.SqlSugarCore.Abstractions;
using Yi.Framework.SqlSugarCore.Repositories;
using Yi.Framework.SqlSugarCore.Uow;
@@ -24,7 +25,32 @@ namespace Yi.Framework.SqlSugarCore
var configuration = service.GetConfiguration();
var section = configuration.GetSection("DbConnOptions");
Configure<DbConnOptions>(section);
var dbConnOptions = new DbConnOptions();
section.Bind(dbConnOptions);
//很多人遗漏了这一点,不同的数据库,对于主键的使用规约不一样,需要根据数据库进行判断
SequentialGuidType guidType;
switch (dbConnOptions.DbType)
{
case DbType.MySql:
case DbType.PostgreSQL:
guidType= SequentialGuidType.SequentialAsString;
break;
case DbType.SqlServer:
guidType = SequentialGuidType.SequentialAtEnd;
break;
case DbType.Oracle:
guidType = SequentialGuidType.SequentialAsBinary;
break;
default:
guidType = SequentialGuidType.SequentialAtEnd;
break;
}
Configure<AbpSequentialGuidGeneratorOptions>(options =>
{
options.DefaultSequentialGuidType = guidType;
});
service.TryAddScoped<ISqlSugarDbContext, SqlSugarDbContextFactory>();
//不开放sqlsugarClient

View File

@@ -0,0 +1,6 @@
namespace Yi.Framework.WeChat.MiniProgram.Abstract;
public interface IErrorObjct: IHasErrcode, IHasErrmsg
{
}

View File

@@ -0,0 +1,6 @@
namespace Yi.Framework.WeChat.MiniProgram.Abstract;
public interface IHasErrcode
{
public int errcode { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Yi.Framework.WeChat.MiniProgram.Abstract;
public interface IHasErrmsg
{
string errmsg { get; set; }
}

View File

@@ -0,0 +1,15 @@
namespace Yi.Framework.WeChat.MiniProgram.HttpModels;
public class AccessTokenResponse
{
public string access_token { get; set; }
public int expires_in { get; set; }
}
public class AccessTokenRequest
{
public string grant_type { get; set; }
public string appid { get; set; }
public string secret { get; set; }
}

View File

@@ -0,0 +1,31 @@
using Yi.Framework.WeChat.MiniProgram.Abstract;
namespace Yi.Framework.WeChat.MiniProgram.HttpModels;
public class Code2SessionResponse: IErrorObjct
{
public string openid { get; set; }
public string session_key { get; set; }
public string unionid { get; set; }
public int errcode { get; set; }
public string errmsg { get; set; }
}
public class Code2SessionRequest
{
public string appid { get; set; }
public string secret { get; set; }
public string js_code { get; set; }
public string grant_type => "authorization_code";
}
public class Code2SessionInput
{
public Code2SessionInput(string js_code)
{
this.js_code=js_code;
}
public string js_code { get; set; }
}

View File

@@ -0,0 +1,79 @@
using Yi.Framework.WeChat.MiniProgram.Abstract;
namespace Yi.Framework.WeChat.MiniProgram.HttpModels;
public class SubscribeNoticeRequest
{
/// <summary>
///用户openid可以是小程序的openid也可以是mp_template_msg.appid对应的公众号的openid
/// </summary>
public string touser { get; set; }
/// <summary>
/// 小程序模板id
/// </summary>
public string template_id { get; set; }
/// <summary>
/// 跳转页面
/// </summary>
public string page { get; set; }
/// <summary>
/// 小程序模板消息的数据
/// </summary>
public Dictionary<string, keyValueItem> data { get; set; }
/// <summary>
/// 默认为正式版
/// </summary>
public string miniprogram_state { get; set; } = "formal";
/// <summary>
/// 默认为中文
/// </summary>
public string lang { get; set; } = "zh_CN";
}
public class SubscribeNoticeInput
{
/// <summary>
///用户openid可以是小程序的openid也可以是mp_template_msg.appid对应的公众号的openid
/// </summary>
public string touser { get; set; }
/// <summary>
/// 小程序模板id
/// </summary>
public string template_id { get; set; }
/// <summary>
/// 跳转页面
/// </summary>
public string page { get; set; }
/// <summary>
/// 公众号模板消息的数据
/// </summary>
public Dictionary<string, keyValueItem> data { get; set; }
}
public class SubscribeNoticeResponse : IErrorObjct
{
public int errcode { get; set; }
public string errmsg { get; set; }
}
public class keyValueItem
{
public keyValueItem(string value)
{
this.value = value;
}
public string value { get; set; }
}

View File

@@ -0,0 +1,20 @@
using Yi.Framework.WeChat.MiniProgram.HttpModels;
namespace Yi.Framework.WeChat.MiniProgram;
public interface IWeChatMiniProgramManager
{
/// <summary>
/// 获取用户openid
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<Code2SessionResponse> Code2SessionAsync(Code2SessionInput input);
/// <summary>
/// 向用户发送订阅消息要openid
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task SendSubscribeNoticeAsync(SubscribeNoticeInput input);
}

View File

@@ -0,0 +1,28 @@
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
namespace Yi.Framework.WeChat.MiniProgram.Token;
internal class CacheMiniProgramToken : DefaultMinProgramToken, IMiniProgramToken
{
private IDistributedCache<string> _cache;
private const string CacheKey = "MiniProgramToken";
public CacheMiniProgramToken(IOptions<WeChatMiniProgramOptions> options, IDistributedCache<string> cache) :
base(options)
{
_cache = cache;
}
public async Task<string> GetTokenAsync()
{
return await _cache.GetOrAddAsync("MiniProgramToken", async () => { return await base.GetTokenAsync(); }, () =>
{
return new DistributedCacheEntryOptions()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2) - TimeSpan.FromMinutes(1)
};
});
}
}

View File

@@ -0,0 +1,40 @@
using System.Net.Http.Json;
using Microsoft.Extensions.Options;
using Yi.Framework.Core.Extensions;
using Yi.Framework.WeChat.MiniProgram.HttpModels;
namespace Yi.Framework.WeChat.MiniProgram.Token;
internal class DefaultMinProgramToken:IMiniProgramToken
{
private const string Url = "https://api.weixin.qq.com/cgi-bin/token";
private WeChatMiniProgramOptions _options;
public DefaultMinProgramToken(IOptions<WeChatMiniProgramOptions> options)
{
_options = options.Value;
}
public async Task<string> GetTokenAsync()
{
var token = await this.GetAccessToken();
return token.access_token;
}
public async Task<AccessTokenResponse> GetAccessToken()
{
var req = new AccessTokenRequest();
req.appid = _options.AppID;
req.secret = _options.AppSecret;
req.grant_type = "client_credential";
using (HttpClient httpClient = new HttpClient())
{
string queryString = req.ToQueryString();
var builder = new UriBuilder(Url);
builder.Query = queryString;
HttpResponseMessage response = await httpClient.GetAsync(builder.ToString());
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadFromJsonAsync<AccessTokenResponse>();
return responseBody;
}
}
}

View File

@@ -0,0 +1,6 @@
namespace Yi.Framework.WeChat.MiniProgram.Token;
public interface IMiniProgramToken
{
public Task<string> GetTokenAsync();
}

View File

@@ -0,0 +1,27 @@
namespace Yi.Framework.WeChat.MiniProgram;
public class WeChatMiniProgramException: Exception
{
public override string Message
{
get
{
// 加上前缀
return "微信Api异常: " + base.Message;
}
}
public WeChatMiniProgramException()
{
}
public WeChatMiniProgramException(string message)
: base(message)
{
}
public WeChatMiniProgramException(string message, Exception innerException)
: base(message, innerException)
{
}
}

View File

@@ -0,0 +1,50 @@
using System.Reflection;
using System.Web;
using Yi.Framework.WeChat.MiniProgram.Abstract;
namespace Yi.Framework.WeChat.MiniProgram;
public static class WeChatMiniProgramExtensions
{
/// <summary>
/// 效验请求是否成功
/// </summary>
/// <param name="response"></param>
/// <returns></returns>
internal static void ValidateSuccess(this IErrorObjct response)
{
if (response.errcode != 0)
{
throw new WeChatMiniProgramException(response.errmsg);
}
}
internal static string ToQueryString<T>(this T obj)
{
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
var queryParams = new List<string>();
foreach (var prop in properties)
{
var value = prop.GetValue(obj, null);
if (value != null)
{
// 处理集合
if (value is IEnumerable<object> enumerable)
{
foreach (var item in enumerable)
{
queryParams.Add($"{HttpUtility.UrlEncode(prop.Name)}={HttpUtility.UrlEncode(item.ToString())}");
}
}
else
{
queryParams.Add($"{HttpUtility.UrlEncode(prop.Name)}={HttpUtility.UrlEncode(value.ToString())}");
}
}
}
return string.Join("&", queryParams);
}
}

View File

@@ -0,0 +1,77 @@
using System.Net.Http.Json;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Volo.Abp.DependencyInjection;
using Yi.Framework.Core.Extensions;
using Yi.Framework.WeChat.MiniProgram.HttpModels;
using Yi.Framework.WeChat.MiniProgram.Token;
namespace Yi.Framework.WeChat.MiniProgram;
public class WeChatMiniProgramManager : IWeChatMiniProgramManager, ISingletonDependency
{
private IMiniProgramToken _weChatToken;
private WeChatMiniProgramOptions _options;
public WeChatMiniProgramManager(IMiniProgramToken weChatToken, IOptions<WeChatMiniProgramOptions> options)
{
_weChatToken = weChatToken;
_options = options.Value;
}
/// <summary>
/// 获取用户openid
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<Code2SessionResponse> Code2SessionAsync(Code2SessionInput input)
{
string url = "https://api.weixin.qq.com/sns/jscode2session";
var req = new Code2SessionRequest();
req.js_code = input.js_code;
req.secret = _options.AppSecret;
req.appid = _options.AppID;
using (HttpClient httpClient = new HttpClient())
{
string queryString = req.ToQueryString();
var builder = new UriBuilder(url);
builder.Query = queryString;
HttpResponseMessage response = await httpClient.GetAsync(builder.ToString());
var responseBody = await response.Content.ReadFromJsonAsync<Code2SessionResponse>();
responseBody.ValidateSuccess();
return responseBody;
}
}
/// <summary>
/// 发送模板订阅消息
/// </summary>
/// <param name="input"></param>
public async Task SendSubscribeNoticeAsync(SubscribeNoticeInput input)
{
var token = await _weChatToken.GetTokenAsync();
string url = $"https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={token}";
var req = new SubscribeNoticeRequest
{
touser = input.touser,
template_id = input.template_id,
page = input.page,
data = input.data,
miniprogram_state = _options.Notice?.State??"formal"
};
req.template_id=req.template_id?? _options.Notice?.TemplateId;
using (HttpClient httpClient = new HttpClient())
{
var body =new StringContent(JsonConvert.SerializeObject(req));
HttpResponseMessage response = await httpClient.PostAsync(url, body);
var responseBody = await response.Content.ReadFromJsonAsync<SubscribeNoticeResponse>();
responseBody.ValidateSuccess();
}
}
}

View File

@@ -0,0 +1,30 @@
namespace Yi.Framework.WeChat.MiniProgram;
public class WeChatMiniProgramOptions
{
/// <summary>
/// AppId
/// </summary>
public string AppID { get; set; }
/// <summary>
/// App密钥
/// </summary>
public string AppSecret { get; set; }
/// <summary>
/// 消息
/// </summary>
public WeChatMiniProgramNoticeItem Notice { get; set; }
}
public class WeChatMiniProgramNoticeItem
{
/// <summary>
/// 模板id
/// </summary>
public string TemplateId { get; set; }
public string State { get; set; }
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
<PackageReference Include="Volo.Abp.Caching" Version="$(AbpVersion)" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,19 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Caching;
using Yi.Framework.Core;
using Yi.Framework.WeChat.MiniProgram.Token;
namespace Yi.Framework.WeChat.MiniProgram;
[DependsOn(typeof(YiFrameworkCoreModule),
typeof(AbpCachingModule))]
public class YiFrameworkWeChatMiniProgramModule: AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
var configuration = context.Services.GetConfiguration();
Configure<WeChatMiniProgramOptions>(configuration.GetSection("WeChatMiniProgram"));
services.AddSingleton<IMiniProgramToken, CacheMiniProgramToken>();
}
}

View File

@@ -53,10 +53,10 @@ public class AuditingStore : IAuditingStore, ITransientDependency
protected virtual async Task SaveLogAsync(AuditLogInfo auditInfo)
{
Logger.LogDebug("Yi-请求追踪:" + JsonHelper.ObjToStr(auditInfo, "yyyy-MM-dd HH:mm:ss"));
// using (var uow = UnitOfWorkManager.Begin(true,isTransactional:false))
// {
await AuditLogRepository.InsertAsync(await Converter.ConvertAsync(auditInfo));
// await uow.CompleteAsync();
// }
using (var uow = UnitOfWorkManager.Begin())
{
await AuditLogRepository.InsertAsync(await Converter.ConvertAsync(auditInfo));
await uow.CompleteAsync();
}
}
}

View File

@@ -1,12 +1,15 @@
using Yi.Framework.Bbs.Domain.Shared.Enums;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.BbsUser;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Analyse;
public class MoneyTopUserDto
/// <summary>
/// 用户排行榜
/// </summary>
public class BaseAnalyseTopUserDto
{
public Guid UserId { get; set; }
public string UserName { get; set; }
public string? Nick { get; set; }
public decimal Money { get; set; }
public int Order { get; set; }
public string? Icon { get; set; }
public int Level { get; set; }
@@ -18,5 +21,4 @@ public class MoneyTopUserDto
/// 用户限制
/// </summary>
public UserLimitEnum UserLimit { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Analyse;
public class MoneyTopUserDto:BaseAnalyseTopUserDto
{
public decimal Money { get; set; }
}

View File

@@ -0,0 +1,8 @@
using Yi.Framework.Bbs.Domain.Shared.Enums;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Analyse;
public class PointsTopUserDto:BaseAnalyseTopUserDto
{
public int Points { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Analyse;
public class ValueTopUserDto:BaseAnalyseTopUserDto
{
public decimal Value { get; set; }
}

View File

@@ -4,8 +4,6 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article
{
public class ArticleGetListOutputDto : EntityDto<Guid>
{
//批量查询,不给内容,性能考虑
//public string Content { get; set; }
public string Name { get; set; }
public Guid DiscussId { get; set; }

View File

@@ -1,4 +1,5 @@
using Volo.Abp.Application.Dtos;
using Yi.Framework.Bbs.Domain.Shared.Consts;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article
{
@@ -10,5 +11,23 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article
public Guid ParentId { get; set; }
public DateTime CreationTime { get; set; }
public bool HasPermission { get;internal set; }
/// <summary>
/// 设置权限
/// </summary>
public void SetPassPermission()
{
HasPermission = true;
}
/// <summary>
/// 设置无权限
/// </summary>
public void SetNoPermission()
{
HasPermission = false;
Content=DiscussConst.Privacy;
}
}
}

View File

@@ -31,5 +31,15 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
/// 是否禁止评论创建功能
/// </summary>
public bool IsDisableCreateComment { get; set; }
/// <summary>
/// 标签
/// </summary>
public List<Guid>? DiscussLableIds { get; set; }
/// <summary>
/// 角色
/// </summary>
public List<string>? PermissionRoleCodes { get; set; } = new List<string>();
}
}

View File

@@ -6,7 +6,7 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
public class DiscussGetListInputVo : PagedAndSortedResultRequestDto
{
/// <summary>
/// 创建者的用户名
/// 创建者的用户名
/// </summary>
public string? UserName { get; set; }
public Guid? UserId { get; set; }
@@ -15,11 +15,11 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
public Guid? PlateId { get; set; }
//默认查询非置顶
//默认查询非置顶
public bool? IsTop { get; set; }
//查询方式
//查询方式
public QueryDiscussTypeEnum Type { get; set; } = QueryDiscussTypeEnum.New;
}
}

View File

@@ -1,5 +1,6 @@
using Volo.Abp.Application.Dtos;
using Yi.Framework.Bbs.Application.Contracts.Dtos.BbsUser;
using Yi.Framework.Bbs.Application.Contracts.Dtos.DiscussLable;
using Yi.Framework.Bbs.Domain.Shared.Consts;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.Rbac.Application.Contracts.Dtos.User;
@@ -17,7 +18,6 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
/// </summary>
public bool IsAgree { get; set; } = false;
public string Title { get; set; }
public string Types { get; set; }
public string? Introduction { get; set; }
public int AgreeNum { get; set; }
@@ -41,57 +41,16 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
/// 封面
/// </summary>
public string? Cover { get; set; }
//私有需要判断code权限
public string? PrivateCode { get; set; }
public DateTime CreationTime { get; set; }
public List<Guid>? PermissionUserIds { get; set; }
/// <summary>
/// 所需角色
/// </summary>
public List<string>? PermissionRoleCodes { get; set; } = new List<string>();
public BbsUserGetListOutputDto User { get; set; }
public void SetBan()
{
Title = DiscussConst.Privacy;
Introduction = "";
Cover = null;
//被禁止
IsBan = true;
}
public List<Guid>? DiscussLableIds { get; set; } = new List<Guid>();
public List<DiscussLableGetOutputDto> Lables { get; set; } = new List<DiscussLableGetOutputDto>();
}
public static class DiscussGetListOutputDtoExtension
{
public static void ApplyPermissionTypeFilter(this List<DiscussGetListOutputDto> dtos, Guid userId)
{
dtos?.ForEach(dto =>
{
switch (dto.PermissionType)
{
case DiscussPermissionTypeEnum.Public:
break;
case DiscussPermissionTypeEnum.Oneself:
//当前主题是仅自己可见,同时不是当前登录用户
if (dto.User.Id != userId)
{
dto.SetBan();
}
break;
case DiscussPermissionTypeEnum.User:
//当前主题为部分可见,同时不是当前登录用户 也 不在可见用户列表中
if (dto.User.Id != userId && !dto.PermissionUserIds.Contains(userId))
{
dto.SetBan();
}
break;
default:
break;
}
});
}
}
}

View File

@@ -1,6 +1,8 @@
using Volo.Abp.Application.Dtos;
using Yi.Framework.Bbs.Application.Contracts.Dtos.BbsUser;
using Yi.Framework.Bbs.Application.Contracts.Dtos.DiscussLable;
using Yi.Framework.Bbs.Application.Contracts.Dtos.Plate;
using Yi.Framework.Bbs.Domain.Shared.Consts;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.Rbac.Application.Contracts.Dtos.User;
@@ -9,11 +11,10 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
public class DiscussGetOutputDto : EntityDto<Guid>
{
/// <summary>
/// 是否禁止评论创建功能
/// 是否禁止评论创建功能
/// </summary>
public bool IsDisableCreateComment { get; set; }
public string Title { get; set; }
public string? Types { get; set; }
public string? Introduction { get; set; }
public int AgreeNum { get; set; }
public int SeeNum { get; set; }
@@ -21,24 +22,48 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
public string? Color { get; set; }
public Guid PlateId { get; set; }
//是否置顶默认false
//是否置顶默认false
public bool IsTop { get; set; }
/// <summary>
/// 封面
/// 封面
/// </summary>
public string? Cover { get; set; }
//是否私有默认false
//是否私有默认false
public bool IsPrivate { get; set; }
//私有需要判断code权限
//私有需要判断code权限
public string? PrivateCode { get; set; }
public DateTime CreationTime { get; set; }
public DiscussPermissionTypeEnum PermissionType { get; set; }
public bool IsAgree { get; set; } = false;
public List<Guid>? PermissionUserIds { get; set; }
public List<string> PermissionRoleCodes { get; set; } = new List<string>();
public BbsUserGetListOutputDto User { get; set; }
public PlateGetOutputDto Plate { get; set; }
public List<Guid>? DiscussLableIds { get; set; } = new List<Guid>();
public List<DiscussLableGetOutputDto> Lables { get; set; } =new List<DiscussLableGetOutputDto>();
public bool HasPermission { get;internal set; }
/// <summary>
/// 设置权限
/// </summary>
public void SetPassPermission()
{
HasPermission = true;
}
/// <summary>
/// 设置无权限
/// </summary>
public void SetNoPermission()
{
HasPermission = false;
Content=DiscussConst.Privacy;
}
}
}

View File

@@ -15,15 +15,25 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
public DiscussPermissionTypeEnum PermissionType { get; set; }
/// <summary>
/// 封面
/// 封面
/// </summary>
public string? Cover { get; set; }
public int OrderNum { get; set; }
/// <summary>
/// 是否禁止评论创建功能
/// 是否禁止评论创建功能
/// </summary>
public bool IsDisableCreateComment { get; set; }
/// <summary>
/// 标签
/// </summary>
public List<Guid>? DiscussLableIds { get; set; }
/// <summary>
/// 需求角色
/// </summary>
public List<string>? PermissionRoleCodes { get; set; } = new List<string>();
}
}

View File

@@ -0,0 +1,11 @@
using Volo.Abp.Application.Dtos;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.DiscussLable;
public class DiscussLableGetOutputDto:EntityDto<Guid>
{
public Guid Id { get; set; }
public string Name { get; set; }
public string? Color { get; set; }
public string? BackgroundColor { get; set; }
}

View File

@@ -3,7 +3,7 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.MyType
/// <summary>
/// Label输入创建对象
/// </summary>
public class MyTypeCreateInputVo
public class DiscussLableCreateInputVo
{
public string Name { get; set; }
public string? Color { get; set; }

View File

@@ -0,0 +1,9 @@
using Volo.Abp.Application.Dtos;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.MyType
{
public class DiscussLableGetListInputVo : PagedAndSortedResultRequestDto
{
public string? Name { get; set; }
}
}

View File

@@ -2,11 +2,10 @@ using Volo.Abp.Application.Dtos;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.MyType
{
public class MyTypeGetListOutputDto : EntityDto<Guid>
public class DiscussLableGetListOutputDto : EntityDto<Guid>
{
public string Name { get; set; }
public string? Color { get; set; }
public string? BackgroundColor { get; set; }
public Guid UserId { get; set; }
}
}

View File

@@ -2,7 +2,7 @@ using Volo.Abp.Application.Dtos;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.MyType
{
public class MyTypeOutputDto : EntityDto<Guid>
public class DiscussLableOutputDto : EntityDto<Guid>
{
public string Name { get; set; }
public string? Color { get; set; }

View File

@@ -1,10 +1,9 @@
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.MyType
{
public class MyTypeUpdateInputVo
public class DiscussLableUpdateInputVo
{
public string Name { get; set; }
public string? Color { get; set; }
public string? BackgroundColor { get; set; }
public Guid UserId { get; set; }
}
}

View File

@@ -1,12 +0,0 @@
using Volo.Abp.Application.Dtos;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.MyType
{
public class MyTypeGetListInputVo : PagedAndSortedResultRequestDto
{
public string? Name { get; set; }
public string? Color { get; set; }
public string? BackgroundColor { get; set; }
public Guid? UserId { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Shop;
public class BbsShopAccountDto
{
/// <summary>
/// 钱钱
/// </summary>
public decimal Money { get; set; }
/// <summary>
/// 积分
/// </summary>
public int Points { get; set; }
/// <summary>
/// 价值
/// </summary>
public decimal Value { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Shop;
public class BuyShopInputDto
{
public Guid GoodsId { get; set; }
public string ContactInformation { get; set; }
}

View File

@@ -0,0 +1,74 @@
using Volo.Abp.Application.Dtos;
using Yi.Framework.Bbs.Domain.Shared.Enums;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Shop;
public class ShopGetListOutput:EntityDto<Guid>
{
/// <summary>
/// 上架时间
/// </summary>
public DateTime CreationTime { get; set; }
/// <summary>
/// 商品类型
/// </summary>
public GoodsTypeEnum GoodsType{ get; set; }
/// <summary>
/// 下架时间
/// </summary>
public DateTime? EndTime { get; set; }
/// <summary>
/// 商品名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 每人限购数量
/// </summary>
public int LimitNumber { get; set; }
/// <summary>
/// 当前库存数量
/// </summary>
public int StockNumber { get; set; }
/// <summary>
/// 商品图片url
/// </summary>
public string ImageUrl { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Describe { get; set; }
/// <summary>
/// 编号
/// </summary>
public string Code { get; set; }
/// <summary>
/// 所需钱钱
/// </summary>
public decimal NeedMoney { get; set; }
/// <summary>
/// 所需价值
/// </summary>
public decimal NeedValue { get; set; }
/// <summary>
/// 所需积分
/// </summary>
public decimal NeedPoints { get; set; }
public int OrderNum { get; set; }
/// <summary>
/// 是否已限制
/// </summary>
public bool IsLimit { get; set; }
}

View File

@@ -5,7 +5,7 @@ namespace Yi.Framework.Bbs.Application.Contracts.IServices
/// <summary>
/// Label服务抽象
/// </summary>
public interface IMyTypeService : IYiCrudAppService<MyTypeOutputDto, MyTypeGetListOutputDto, Guid, MyTypeGetListInputVo, MyTypeCreateInputVo, MyTypeUpdateInputVo>
public interface IDiscussLableService : IYiCrudAppService<DiscussLableOutputDto, DiscussLableGetListOutputDto, Guid, DiscussLableGetListInputVo, DiscussLableCreateInputVo, DiscussLableUpdateInputVo>
{
}

View File

@@ -8,6 +8,5 @@ namespace Yi.Framework.Bbs.Application.Contracts.IServices
/// </summary>
public interface IDiscussService : IYiCrudAppService<DiscussGetOutputDto, DiscussGetListOutputDto, Guid, DiscussGetListInputVo, DiscussCreateInputVo, DiscussUpdateInputVo>
{
Task VerifyDiscussPermissionAsync(Guid discussId);
}
}

View File

@@ -3,6 +3,7 @@
<ItemGroup>
<ProjectReference Include="..\..\digital-collectibles\Yi.Framework.DigitalCollectibles.Application.Contracts\Yi.Framework.DigitalCollectibles.Application.Contracts.csproj" />
<ProjectReference Include="..\..\rbac\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj" />
<ProjectReference Include="..\Yi.Framework.Bbs.Domain.Shared\Yi.Framework.Bbs.Domain.Shared.csproj" />
</ItemGroup>

View File

@@ -77,6 +77,56 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
return output;
}
/// <summary>
/// 作者主题,返回当前作者最新的主题
/// </summary>
/// <returns></returns>
[HttpGet("analyse/bbs-discuss/author/{userId}")]
public async Task<List<DiscussGetListOutputDto>> GetAuthorDiscussAsync(
[FromRoute] Guid userId,
[FromQuery] PagedResultRequestDto input)
{
var output = await _forumManager._discussRepository._DbQueryable.Where(discuss=>discuss.CreatorId==userId)
.Where(discuss=>discuss.PermissionType== DiscussPermissionTypeEnum.Public)
.LeftJoin<UserAggregateRoot>((discuss, user) => discuss.CreatorId == user.Id)
.LeftJoin<BbsUserExtraInfoEntity>((discuss, user, info) => user.Id == info.UserId)
.OrderByDescending(discuss => discuss.CreationTime)
.Select((discuss, user, info) => new DiscussGetListOutputDto
{
Id = discuss.Id,
User = new BbsUserGetListOutputDto()
{
Id = user.Id,
UserName = user.UserName,
Nick = user.Nick,
Icon = user.Icon,
Level = info.Level,
UserLimit = info.UserLimit
}
}, true)
.ToPageListAsync(input.SkipCount, input.MaxResultCount);
var discussId = output.Select(x => x.Id);
//点赞字典key为主题idy为用户ids
var agreeDic =
(await _agreeRepository._DbQueryable.Where(x => discussId.Contains(x.DiscussId)).ToListAsync())
.GroupBy(x => x.DiscussId)
.ToDictionary(x => x.Key, y => y.Select(y => y.CreatorId).ToList());
//等级、是否点赞赋值
output?.ForEach(x =>
{
if (CurrentUser.Id is not null)
{
//默认fasle
if (agreeDic.TryGetValue(x.Id,out var userIds))
{
x.IsAgree = userIds.Contains(CurrentUser.Id);
}
}
});
return output;
}
}
}

View File

@@ -9,6 +9,7 @@ using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Entities.Integral;
using Yi.Framework.Bbs.Domain.Managers;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.DigitalCollectibles.Application.Contracts.IServices;
using Yi.Framework.Rbac.Application.Contracts.IServices;
using Yi.Framework.Rbac.Domain.Authorization;
using Yi.Framework.Rbac.Domain.Shared.Consts;
@@ -20,11 +21,16 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
{
private BbsUserManager _bbsUserManager;
private IOnlineService _onlineService;
private readonly IPointAnalyseService _pointAnalyseService;
private readonly IValueAnalyseService _valueAnalyseService;
public BbsUserAnalyseService(BbsUserManager bbsUserManager, IOnlineService onlineService)
public BbsUserAnalyseService(BbsUserManager bbsUserManager, IOnlineService onlineService,
IPointAnalyseService pointAnalyseService, IValueAnalyseService valueAnalyseService)
{
_bbsUserManager = bbsUserManager;
_onlineService = onlineService;
_pointAnalyseService = pointAnalyseService;
_valueAnalyseService = valueAnalyseService;
}
@@ -110,7 +116,9 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
)
.ToPageListAsync(pageIndex, input.MaxResultCount, total);
output.ForEach(x => { x.LevelName = _bbsUserManager._levelCacheDic[x.Level].Name; });
var levelCache = await _bbsUserManager.GetLevelCacheMapAsync();
output.ForEach(x => { x.LevelName = levelCache[x.Level].Name; });
return new PagedResultDto<MoneyTopUserDto>
{
Items = output,
@@ -169,5 +177,118 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
return output;
}
}
/// <summary>
/// 积分排行榜
/// </summary>
/// <returns></returns>
[HttpGet("analyse/dc-user/points-top/{userId?}")]
public async Task<PagedResultDto<PointsTopUserDto>> GetPointsTopAsync([FromQuery] PagedResultRequestDto input,
[FromRoute] Guid? userId)
{
var result = await _pointAnalyseService.GetValueTopAsync(input, null);
var userIds = result.Items.Select(x => x.UserId).ToList();
var baseOutput = await _bbsUserManager._userRepository._DbQueryable
.Where(u => userIds.Contains(u.Id))
.LeftJoin<BbsUserExtraInfoEntity>((u, info) => u.Id == info.UserId)
.Select((u, info) =>
new BaseAnalyseTopUserDto
{
UserName = u.UserName,
Nick = u.Nick,
Icon = u.Icon,
Level = info.Level,
UserLimit = info.UserLimit,
UserId = info.UserId
}
).ToListAsync();
var output = new List<PointsTopUserDto>();
var levelCache = await _bbsUserManager.GetLevelCacheMapAsync();
result.Items.ToList().ForEach(x =>
{
var currentUserInfo = baseOutput.Where(u => u.UserId == x.UserId).FirstOrDefault();
if (currentUserInfo is not null)
{
output.Add(new PointsTopUserDto
{
UserName = currentUserInfo.UserName,
Nick = currentUserInfo.Nick,
Order = x.Order,
Icon = currentUserInfo.Icon,
Level = currentUserInfo.Level,
LevelName = levelCache[currentUserInfo.Level].Name,
UserLimit = UserLimitEnum.Normal,
Points = x.Points
});
}
});
return new PagedResultDto<PointsTopUserDto>
{
Items = output,
TotalCount = result.TotalCount
};
}
/// <summary>
/// 价值排行榜
/// </summary>
/// <returns></returns>
[HttpGet("analyse/dc-user/value-top/{userId?}")]
public async Task<PagedResultDto<ValueTopUserDto>> GetValueTopAsync([FromQuery] PagedResultRequestDto input,
[FromRoute] Guid? userId)
{
var result = await _valueAnalyseService.GetValueTopAsync(input, null);
var userIds = result.Items.Select(x => x.UserId).ToList();
var baseOutput = await _bbsUserManager._userRepository._DbQueryable
.Where(u => userIds.Contains(u.Id))
.LeftJoin<BbsUserExtraInfoEntity>((u, info) => u.Id == info.UserId)
.Select((u, info) =>
new BaseAnalyseTopUserDto
{
UserName = u.UserName,
Nick = u.Nick,
Icon = u.Icon,
Level = info.Level,
UserLimit = info.UserLimit,
UserId = info.UserId
}
).ToListAsync();
var output = new List<ValueTopUserDto>();
var levelCache = await _bbsUserManager.GetLevelCacheMapAsync();
result.Items.ToList().ForEach(x =>
{
var currentUserInfo = baseOutput.Where(u => u.UserId == x.UserId).FirstOrDefault();
if (currentUserInfo is not null)
{
output.Add(new ValueTopUserDto
{
UserName = currentUserInfo.UserName,
Nick = currentUserInfo.Nick,
Order = x.Order,
Icon = currentUserInfo.Icon,
Level = currentUserInfo.Level,
LevelName =levelCache[currentUserInfo.Level].Name,
UserLimit = UserLimitEnum.Normal,
Value = x.Value
});
}
});
return new PagedResultDto<ValueTopUserDto>
{
Items = output,
TotalCount = result.TotalCount
};
}
}
}

View File

@@ -30,22 +30,21 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
/// <summary>
/// Article服务实现
/// </summary>
public class ArticleService : YiCrudAppService<ArticleAggregateRoot, ArticleGetOutputDto, ArticleGetListOutputDto, Guid, ArticleGetListInputVo, ArticleCreateInputVo, ArticleUpdateInputVo>,
IArticleService
public class ArticleService : YiCrudAppService<ArticleAggregateRoot, ArticleGetOutputDto, ArticleGetListOutputDto,
Guid, ArticleGetListInputVo, ArticleCreateInputVo, ArticleUpdateInputVo>,
IArticleService
{
public ArticleService(IArticleRepository articleRepository,
ISqlSugarRepository<DiscussAggregateRoot> discussRepository,
IDiscussService discussService,
ForumManager forumManager) : base(articleRepository)
{
_articleRepository = articleRepository;
_discussRepository = discussRepository;
_discussService = discussService;
_forumManager = forumManager;
}
private ForumManager _forumManager;
private IArticleRepository _articleRepository;
private ISqlSugarRepository<DiscussAggregateRoot> _discussRepository;
@@ -55,13 +54,34 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
{
RefAsync<int> total = 0;
var entities = await _articleRepository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.Name), x => x.Name.Contains(input.Name!))
//.WhereIF(!string.IsNullOrEmpty(input.Code), x => x.Name.Contains(input.Code!))
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
var entities = await _articleRepository._DbQueryable
.WhereIF(!string.IsNullOrEmpty(input.Name), x => x.Name.Contains(input.Name!))
.WhereIF(input.StartTime is not null && input.EndTime is not null,
x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
return new PagedResultDto<ArticleGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
}
/// <summary>
/// 查询文章
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public override async Task<ArticleGetOutputDto> GetAsync(Guid id)
{
var entity = await _articleRepository.GetAsync(id);
var output = entity.Adapt<ArticleGetOutputDto>();
if (!await _forumManager.VerifyDiscussPermissionAsync(entity.DiscussId, CurrentUser.Id, CurrentUser.Roles))
{
output.SetNoPermission();
}
else
{
output.SetPassPermission();
}
return output;
}
/// <summary>
/// 获取文章全部树级信息
@@ -72,17 +92,13 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
[Route("article/all/discuss-id/{discussId}")]
public async Task<List<ArticleAllOutputDto>> GetAllAsync([FromRoute] Guid discussId)
{
await _discussService.VerifyDiscussPermissionAsync(discussId);
var entities = await _articleRepository.GetTreeAsync(x => x.DiscussId == discussId);
//var result = entities.Tile();
var items = entities.Adapt<List<ArticleAllOutputDto>>();
return items;
}
/// <summary>
/// 查询文章
/// 查询文章概述
/// </summary>
/// <param name="discussId"></param>
/// <returns></returns>
@@ -109,7 +125,7 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
[Authorize]
public async override Task<ArticleGetOutputDto> CreateAsync(ArticleCreateInputVo input)
{
await VerifyDiscussCreateIdAsync(input.DiscussId);
await VerifyPermissionAsync(input.DiscussId);
return await base.CreateAsync(input);
}
@@ -122,7 +138,7 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
public override async Task<ArticleGetOutputDto> UpdateAsync(Guid id, ArticleUpdateInputVo input)
{
var entity = await _articleRepository.GetByIdAsync(id);
await VerifyDiscussCreateIdAsync(entity.DiscussId);
await VerifyPermissionAsync(entity.DiscussId);
return await base.UpdateAsync(id, input);
}
@@ -135,7 +151,7 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
public override async Task DeleteAsync(Guid id)
{
var entity = await _articleRepository.GetByIdAsync(id);
await VerifyDiscussCreateIdAsync(entity.DiscussId);
await VerifyPermissionAsync(entity.DiscussId);
await base.DeleteAsync(id);
}
@@ -144,8 +160,10 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
/// 导入文章
/// </summary>
/// <returns></returns>
public async Task PostImportAsync([FromQuery] ArticleImprotDto input, [FromForm][Required] IFormFileCollection file)
public async Task PostImportAsync([FromQuery] ArticleImprotDto input,
[FromForm] [Required] IFormFileCollection file)
{
await VerifyPermissionAsync(input.DiscussId);
var fileObjs = new List<FileObject>();
if (file.Count > 0)
{
@@ -172,45 +190,18 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
{
throw new UserFriendlyException("未选择文件");
}
//使用简单工厂根据传入的类型进行判断
await _forumManager.PostImportAsync(input.DiscussId, input.ArticleParentId, fileObjs, input.ImportType);
}
/// <summary>
/// 校验创建权限userId为主题创建者
/// </summary>
/// <param name="disucssId"></param>
/// <returns></returns>
private async Task VerifyDiscussCreateIdAsync(Guid disucssId)
private async Task VerifyPermissionAsync(Guid discussId)
{
var discuss = await _discussRepository.GetFirstAsync(x => x.Id == disucssId);
if (discuss is null)
if (!await _forumManager.VerifyDiscussPermissionAsync(discussId, CurrentUser.Id, isVerifyLook: false))
{
throw new UserFriendlyException(DiscussConst.No_Exist);
}
//这块有点绕,这个版本的写法比较清晰
bool result = false;
if (CurrentUser.GetPermissions().Contains(UserConst.AdminPermissionCode))
{
//如果是超管,直接跳过
result = true;
}
else
{
//如果不是超管,必须满足作者是自己,同时还有发布的权限
if (discuss.CreatorId == CurrentUser.Id)
{
result = true;
}
}
if (!result)
{
throw new UserFriendlyException("权限不足,请联系主题作者或管理员申请开通");
throw new UserFriendlyException("您无权限进行操作", "403");
}
}
}
}
}

View File

@@ -44,14 +44,13 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
private IDiscussService _discussService { get; set; }
/// <summary>
/// 获取改主题下的评论,结构为二维列表,该查询无分页
/// Todo: 可放入领域层
/// </summary>
/// <param name="discussId"></param>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PagedResultDto<CommentGetListOutputDto>> GetDiscussIdAsync([FromRoute] Guid discussId, [FromQuery] CommentGetListInputVo input)
{
await _discussService.VerifyDiscussPermissionAsync(discussId);
await _forumManager.VerifyDiscussPermissionAsync(discussId,CurrentUser.Id);
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.Content), x => x.Content.Contains(input.Content))
.Where(x => x.DiscussId == discussId)
@@ -64,15 +63,7 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
List<Guid> userIds = entities.Where(x => x.CreatorId != null).Select(x => x.CreatorId ?? Guid.Empty).ToList();
var bbsUserInfoDic = (await _bbsUserManager.GetBbsUserInfoAsync(userIds)).ToDictionary(x => x.Id);
//------数据查询完成------
//------数据查询完成------,以下只是dto的简单组装
//从根目录开始组装
//结果初始值,第一层等于全部根节点
@@ -117,11 +108,7 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
rootOutoutDto?.ForEach(x =>
{
x.Children = x.Children.OrderByDescending(x => x.CreationTime).ToList();
});
return new PagedResultDto<CommentGetListOutputDto>(entities.Count(), rootOutoutDto);
}

View File

@@ -0,0 +1,53 @@
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Yi.Framework.Bbs.Application.Contracts.Dtos.MyType;
using Yi.Framework.Bbs.Application.Contracts.IServices;
using Yi.Framework.Bbs.Domain.Entities.Forum;
using Yi.Framework.Ddd.Application;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Application.Services.Forum
{
/// <summary>
/// DiscussLable服务实现
/// </summary>
public class DiscussLableService : YiCrudAppService<DiscussLableAggregateRoot, DiscussLableOutputDto,
DiscussLableGetListOutputDto, Guid, DiscussLableGetListInputVo, DiscussLableCreateInputVo,
DiscussLableUpdateInputVo>,
IDiscussLableService
{
private ISqlSugarRepository<DiscussLableAggregateRoot, Guid> _repository;
public DiscussLableService(ISqlSugarRepository<DiscussLableAggregateRoot, Guid> repository) : base(repository)
{
_repository = repository;
}
[HttpGet("discuss-lable/all")]
public async Task<ListResultDto<DiscussLableGetListOutputDto>> GetAllListAsync(DiscussLableGetListInputVo input)
{
var order = input.Sorting ?? nameof(DiscussLableAggregateRoot.Name);
var output = await _repository._DbQueryable
.WhereIF(input.Name is not null, x => x.Name.Contains(input.Name))
.OrderBy(order)
.Select(x => new DiscussLableGetListOutputDto(), true)
.ToListAsync();
return new ListResultDto<DiscussLableGetListOutputDto>(output);
}
public override async Task<PagedResultDto<DiscussLableGetListOutputDto>> GetListAsync(
DiscussLableGetListInputVo input)
{
RefAsync<int> total = 0;
var order = input.Sorting ?? nameof(DiscussLableAggregateRoot.Name);
var output = await _repository._DbQueryable
.WhereIF(input.Name is not null, x => x.Name.Contains(input.Name))
.OrderBy(order)
.Select(x => new DiscussLableGetListOutputDto(), true)
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
return new PagedResultDto<DiscussLableGetListOutputDto>(total, output);
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Linq;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
@@ -9,10 +10,12 @@ using Volo.Abp.EventBus.Local;
using Volo.Abp.Users;
using Yi.Framework.Bbs.Application.Contracts.Dtos.BbsUser;
using Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss;
using Yi.Framework.Bbs.Application.Contracts.Dtos.DiscussLable;
using Yi.Framework.Bbs.Application.Contracts.IServices;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Entities.Forum;
using Yi.Framework.Bbs.Domain.Managers;
using Yi.Framework.Bbs.Domain.Repositories;
using Yi.Framework.Bbs.Domain.Shared.Consts;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.Bbs.Domain.Shared.Etos;
@@ -36,16 +39,17 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
private ISqlSugarRepository<DiscussTopEntity> _discussTopRepository;
private ISqlSugarRepository<AgreeEntity> _agreeRepository;
private BbsUserManager _bbsUserManager;
private IDiscussLableRepository _discussLableRepository;
public DiscussService(BbsUserManager bbsUserManager, ForumManager forumManager,
ISqlSugarRepository<DiscussTopEntity> discussTopRepository,
ISqlSugarRepository<PlateAggregateRoot> plateEntityRepository, ILocalEventBus localEventBus,
ISqlSugarRepository<AgreeEntity> agreeRepository) : base(forumManager._discussRepository)
ISqlSugarRepository<AgreeEntity> agreeRepository, IDiscussLableRepository discussLableRepository) : base(forumManager._discussRepository)
{
_forumManager = forumManager;
_plateEntityRepository = plateEntityRepository;
_localEventBus = localEventBus;
_agreeRepository = agreeRepository;
_discussLableRepository = discussLableRepository;
_discussTopRepository = discussTopRepository;
_bbsUserManager = bbsUserManager;
}
@@ -55,8 +59,7 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
private ISqlSugarRepository<PlateAggregateRoot> _plateEntityRepository { get; set; }
/// <summary>
/// 单查
/// </summary>
@@ -65,15 +68,14 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
public async override Task<DiscussGetOutputDto> GetAsync(Guid id)
{
//查询主题发布 浏览主题 事件,浏览数+1
var item = await _forumManager._discussRepository._DbQueryable
var output = await _forumManager._discussRepository._DbQueryable
.LeftJoin<UserAggregateRoot>((discuss, user) => discuss.CreatorId == user.Id)
.LeftJoin<BbsUserExtraInfoEntity>((discuss, user, info) => user.Id == info.UserId)
.LeftJoin<PlateAggregateRoot>((discuss, user, info, plate) => plate.Id == discuss.PlateId)
.Select((discuss, user, info, plate) => new DiscussGetOutputDto
{
Id = discuss.Id,
IsAgree = SqlFunc.Subqueryable<AgreeEntity>().WhereIF(CurrentUser.Id != null,
x => x.CreatorId == CurrentUser.Id && x.DiscussId == discuss.Id).Any(),
IsAgree = false,
User = new BbsUserGetListOutputDto()
{
UserName = user.UserName,
@@ -94,16 +96,45 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
Logo = plate.Logo
}
}, true)
.SingleAsync(discuss => discuss.Id == id);
.FirstAsync(discuss => discuss.Id == id);
if (item is not null)
if (output is null)
{
await VerifyDiscussPermissionAsync(item.Id);
await _localEventBus.PublishAsync(new SeeDiscussEventArgs
{ DiscussId = item.Id, OldSeeNum = item.SeeNum });
throw new UserFriendlyException("该主题不存在", "404");
}
//组装点赞
var agreeCreatorList =
(await _agreeRepository._DbQueryable.Where(x => x.DiscussId == output.Id).Select(x=>x.CreatorId).ToListAsync());
//已登录
if (CurrentUser.Id is not null)
{
output.IsAgree = agreeCreatorList.Contains(CurrentUser.Id);
}
//组装标签
var lableDic=await _discussLableRepository.GetDiscussLableCacheMapAsync();
foreach (var lableId in output.DiscussLableIds)
{
if (lableDic.TryGetValue(lableId,out var item))
{
output.Lables.Add(item.Adapt<DiscussLableGetOutputDto>());
}
}
return item;
//如果没有权限
if (!await _forumManager.VerifyDiscussPermissionAsync(output.Id,CurrentUser.Id, CurrentUser.Roles))
{
output.SetNoPermission();
}
else
{
output.SetPassPermission();
}
await _localEventBus.PublishAsync(new SeeDiscussEventArgs
{ DiscussId = output.Id, OldSeeNum = output.SeeNum });
return output;
}
@@ -154,14 +185,14 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
(await _agreeRepository._DbQueryable.Where(x => discussId.Contains(x.DiscussId)).ToListAsync())
.GroupBy(x => x.DiscussId)
.ToDictionary(x => x.Key, y => y.Select(y => y.CreatorId).ToList());
//查询完主题之后,要过滤一下私有的主题信息
items.ApplyPermissionTypeFilter(CurrentUser.Id ?? Guid.Empty);
//等级、是否点赞赋值
var levelCacheDic= await _bbsUserManager.GetLevelCacheMapAsync();
var lableDic=await _discussLableRepository.GetDiscussLableCacheMapAsync();
//组装等级、是否点赞赋值、标签
items?.ForEach(x =>
{
x.User.LevelName = _bbsUserManager._levelCacheDic[x.User.Level].Name;
x.User.LevelName = levelCacheDic[x.User.Level].Name;
if (CurrentUser.Id is not null)
{
//默认fasle
@@ -170,6 +201,15 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
x.IsAgree = userIds.Contains(CurrentUser.Id);
}
}
foreach (var lableId in x.DiscussLableIds)
{
if (lableDic.TryGetValue(lableId,out var item))
{
x.Lables.Add(item.Adapt<DiscussLableGetOutputDto>());
}
}
});
return new PagedResultDto<DiscussGetListOutputDto>(total, items);
}
@@ -199,7 +239,6 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
Address = user.Address,
Age = user.Age,
CreationTime = user.CreationTime,
Level = info.Level,
Introduction = user.Introduction,
Icon = user.Icon,
@@ -212,7 +251,20 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
}
}, true)
.ToListAsync();
output?.ForEach(x => x.User.LevelName = _bbsUserManager._levelCacheDic[x.User.Level].Name);
var levelCacheDic= await _bbsUserManager.GetLevelCacheMapAsync();
var lableDic=await _discussLableRepository.GetDiscussLableCacheMapAsync();
output?.ForEach(x =>
{
x.User.LevelName = levelCacheDic[x.User.Level].Name;
foreach (var lableId in x.DiscussLableIds)
{
if (lableDic.TryGetValue(lableId,out var item))
{
x.Lables.Add(item.Adapt<DiscussLableGetOutputDto>());
}
}
});
return output;
}
@@ -250,36 +302,10 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
return await MapToGetOutputDtoAsync(entity);
}
/// <summary>
/// 校验主题查询权限
/// </summary>
/// <param name="discussId"></param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
public async Task VerifyDiscussPermissionAsync(Guid discussId)
public override Task<DiscussGetOutputDto> UpdateAsync(Guid id, DiscussUpdateInputVo input)
{
var discuss = await _forumManager._discussRepository.GetFirstAsync(x => x.Id == discussId);
if (discuss is null)
{
throw new UserFriendlyException(DiscussConst.No_Exist);
}
if (discuss.PermissionType == DiscussPermissionTypeEnum.Oneself)
{
if (discuss.CreatorId != CurrentUser.Id)
{
throw new UserFriendlyException(DiscussConst.Privacy);
}
}
if (discuss.PermissionType == DiscussPermissionTypeEnum.User)
{
if (discuss.CreatorId != CurrentUser.Id &&
!discuss.PermissionUserIds.Contains(CurrentUser.Id ?? Guid.Empty))
{
throw new UserFriendlyException(DiscussConst.Privacy);
}
}
return base.UpdateAsync(id, input);
}
}
}

View File

@@ -1,54 +0,0 @@
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Yi.Framework.Bbs.Application.Contracts.Dtos.MyType;
using Yi.Framework.Bbs.Application.Contracts.IServices;
using Yi.Framework.Bbs.Domain.Entities.Forum;
using Yi.Framework.Ddd.Application;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Application.Services.Forum
{
/// <summary>
/// Label服务实现
/// </summary>
public class MyTypeService : YiCrudAppService<MyTypeEntity, MyTypeOutputDto, MyTypeGetListOutputDto, Guid, MyTypeGetListInputVo, MyTypeCreateInputVo, MyTypeUpdateInputVo>,
IMyTypeService
{
private ISqlSugarRepository<MyTypeEntity, Guid> _repository;
public MyTypeService(ISqlSugarRepository<MyTypeEntity, Guid> repository, IDataFilter dataFilter) : base(repository)
{
_repository = repository;
_dataFilter = dataFilter;
}
private IDataFilter _dataFilter { get; set; }
/// <summary>
/// 获取当前用户的主题类型
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public Task<PagedResultDto<MyTypeGetListOutputDto>> GetListCurrentAsync(MyTypeGetListInputVo input)
{
//过滤器需要更换
//_dataFilter.Enable<MyTypeEntity>(x => x.UserId == CurrentUser.Id);
//_dataFilter.AddFilter<MyTypeEntity>(x => x.UserId == CurrentUser.Id);
return base.GetListAsync(input);
}
/// <summary>
/// 创建
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public override async Task<MyTypeOutputDto> CreateAsync(MyTypeCreateInputVo input)
{
var entity = await MapToEntityAsync(input);
entity.UserId = CurrentUser.Id ?? Guid.Empty;
entity.IsDeleted = false;
var outputEntity = await _repository.InsertReturnEntityAsync(entity);
return await MapToGetOutputDtoAsync(outputEntity);
}
}
}

View File

@@ -0,0 +1,100 @@
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Users;
using Yi.Framework.Bbs.Application.Contracts.Dtos.Shop;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Entities.Shop;
using Yi.Framework.Bbs.Domain.Managers;
using Yi.Framework.Bbs.Domain.Managers.Shop;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.Bbs.Domain.Shared.Etos;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Application.Services.Shop;
/// <summary>
/// bbs商城服务
/// </summary>
public class BbsShopService : ApplicationService
{
private readonly ISqlSugarRepository<BbsGoodsAggregateRoot> _repository;
private readonly ISqlSugarRepository<BbsGoodsApplyAggregateRoot> _applyRepository;
private readonly BbsShopManager _bbsShopManager;
private readonly ISqlSugarRepository<BbsUserExtraInfoEntity> _bbsUserRepository;
private ILocalEventBus LocalEventBus => LazyServiceProvider.LazyGetRequiredService<ILocalEventBus>();
public BbsShopService(ISqlSugarRepository<BbsGoodsAggregateRoot> repository,
ISqlSugarRepository<BbsGoodsApplyAggregateRoot> applyRepository, BbsShopManager bbsShopManager,
ISqlSugarRepository<BbsUserExtraInfoEntity> bbsUserRepository)
{
_repository = repository;
_applyRepository = applyRepository;
_bbsShopManager = bbsShopManager;
_bbsUserRepository = bbsUserRepository;
}
//商城列表
[Authorize]
public async Task<PagedResultDto<ShopGetListOutput>> GetListAsync(PagedAndSortedResultRequestDto input)
{
var output = new List<ShopGetListOutput>();
var userId = CurrentUser.GetId();
RefAsync<int> total = 0;
var entities = await _repository._DbQueryable
.Where(x => x.EndTime > DateTime.Now)
.OrderBy(x => x.OrderNum)
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
var applyEntities = await _applyRepository.GetListAsync(x => x.UserId == userId);
foreach (var entity in entities)
{
var dto = entity.Adapt<ShopGetListOutput>();
if (entity.GoodsType == GoodsTypeEnum.Apply)
{
//大于限购数量
if (applyEntities.Count(x => x.GoodsId == entity.Id) >= entity.LimitNumber)
{
dto.IsLimit = true;
}
}
output.Add(dto);
}
return new PagedResultDto<ShopGetListOutput>(total, output);
}
/// <summary>
/// 购买商品
/// </summary>
[Authorize]
public async Task PostBuyAsync([FromBody] BuyShopInputDto input)
{
var userId = CurrentUser.GetId();
await _bbsShopManager.BuyAsync(userId, input.GoodsId, input.ContactInformation);
}
/// <summary>
/// 获取该用户汇总信息(钱钱、积分、价值)
/// </summary>
[Authorize]
public async Task<BbsShopAccountDto> GetAccountAsync()
{
var userId = CurrentUser.GetId();
var output = new BbsShopAccountDto();
var money = await _bbsUserRepository._DbQueryable.Where(x => x.UserId == userId).Select(x => x.Money)
.FirstAsync();
var eto = new SetAccountInfoEto(userId);
await LocalEventBus.PublishAsync(eto, false);
//钱钱累加
output.Money =money+ eto.Money;
output.Points = eto.Points;
output.Value = eto.Value;
return output;
}
}

View File

@@ -0,0 +1,9 @@
namespace Yi.Framework.Bbs.Domain.Shared.Caches;
public class DiscussLableCacheItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public string? Color { get; set; }
public string? BackgroundColor { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Yi.Framework.Bbs.Domain.Shared.Consts;
public class DiscussLableConst
{
public const string DiscussLableCacheKey="DiscussLable:All";
}

View File

@@ -14,14 +14,9 @@ namespace Yi.Framework.Bbs.Domain.Shared.Enums
Public = 0,
/// <summary>
/// 仅自己可见
/// 角色要求可见
/// </summary>
Oneself,
/// <summary>
/// 部分用户可见
/// </summary>
User
Role=1
}
}

View File

@@ -0,0 +1,10 @@
namespace Yi.Framework.Bbs.Domain.Shared.Etos;
/// <summary>
/// 临时用户绑定到正式用户
/// </summary>
public class BindAccountEto
{
public Guid NewUserId { get; set; }
public Guid OldUserId { get; set; }
}

View File

@@ -0,0 +1,27 @@
namespace Yi.Framework.Bbs.Domain.Shared.Etos;
public class SetAccountInfoEto
{
public SetAccountInfoEto(Guid userId)
{
UserId = userId;
}
public Guid UserId { get; set; }
/// <summary>
/// 钱钱
/// </summary>
public decimal Money { get; set; }
/// <summary>
/// 积分
/// </summary>
public int Points { get; set; }
/// <summary>
/// 价值
/// </summary>
public decimal Value { get; set; }
}

View File

@@ -10,7 +10,7 @@ using Yi.Framework.Bbs.Domain.Shared.Enums;
namespace Yi.Framework.Bbs.Domain.Entities
{
/// <summary>
/// 评论
/// bbs用户
/// </summary>
[SugarTable("BbsUserExtraInfo")]
[SugarIndex($"index_{nameof(UserId)}", nameof(UserId), OrderByType.Asc)]

View File

@@ -8,9 +8,12 @@ namespace Yi.Framework.Bbs.Domain.Entities.Forum
{
[SugarTable("Discuss")]
[SugarIndex($"index_{nameof(Title)}", nameof(Title), OrderByType.Asc)]
[SugarIndex($"index_{nameof(PlateId)}", nameof(PlateId), OrderByType.Asc)]
[SugarIndex($"index_{nameof(CreatorId)}", nameof(CreatorId), OrderByType.Asc)]
[SugarIndex($"index_{nameof(CreationTime)}", nameof(CreationTime), OrderByType.Desc)]
[SugarIndex($"index_{nameof(IsDeleted)}_{nameof(PlateId)}_{nameof(CreatorId)}",
nameof(IsDeleted), OrderByType.Asc,
nameof(PlateId), OrderByType.Asc,
nameof(CreatorId), OrderByType.Asc
)]
public class DiscussAggregateRoot : AggregateRoot<Guid>, ISoftDelete, IAuditedObject
{
public DiscussAggregateRoot()
@@ -24,7 +27,6 @@ namespace Yi.Framework.Bbs.Domain.Entities.Forum
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; }
public string? Title { get; set; }
public string? Types { get; set; }
public string? Introduction { get; set; }
public int AgreeNum { get; set; }
public int SeeNum { get; set; }
@@ -59,11 +61,14 @@ namespace Yi.Framework.Bbs.Domain.Entities.Forum
/// <summary>
/// 当PermissionType为部分用户时候,以下列表中的用户+创建者 代表拥有权限
/// 当PermissionType为角色时候,以下列表中的角色+创建者 代表拥有权限
/// </summary>
[SugarColumn(IsJson = true)]//使用json处理
public List<Guid>? PermissionUserIds { get; set; }
[SugarColumn(IsJson = true)] //使用json处理
public List<string>? PermissionRoleCodes { get; set; } = new List<string>();
[SugarColumn(IsJson = true)]//使用json处理
public List<Guid>? DiscussLableIds{ get; set; }
/// <summary>
/// 是否禁止评论创建功能
/// </summary>

View File

@@ -4,17 +4,13 @@ using Volo.Abp.Domain.Entities;
namespace Yi.Framework.Bbs.Domain.Entities.Forum
{
[SugarTable("MyType")]
public class MyTypeEntity : Entity<Guid>, ISoftDelete
[SugarTable("DiscussLable")]
public class DiscussLableAggregateRoot : AggregateRoot<Guid>, ISoftDelete
{
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; }
public bool IsDeleted { get; set; }
public string Name { get; set; }
public string? Color { get; set; }
public string? BackgroundColor { get; set; }
public Guid UserId { get; set; }
}
}

View File

@@ -1,16 +0,0 @@
using SqlSugar;
using Volo.Abp.Domain.Entities;
namespace Yi.Framework.Bbs.Domain.Entities.Forum
{
[SugarTable("DiscussMyType")]
public class DiscussMyTypeEntity : Entity<Guid>
{
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; }
public Guid DiscussId { get; set; }
public Guid MyTypeId { get; set; }
}
}

View File

@@ -2,6 +2,7 @@
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.Core.Data;
namespace Yi.Framework.Bbs.Domain.Entities.Shop;
@@ -9,7 +10,7 @@ namespace Yi.Framework.Bbs.Domain.Entities.Shop;
/// 商品定义表
/// </summary>
[SugarTable("BbsGoods")]
public class BbsGoodsAggregateRoot: AggregateRoot<Guid>, IHasCreationTime
public class BbsGoodsAggregateRoot: AggregateRoot<Guid>, IHasCreationTime,IOrderNum
{
/// <summary>
/// 上架时间
@@ -70,4 +71,6 @@ public class BbsGoodsAggregateRoot: AggregateRoot<Guid>, IHasCreationTime
/// 所需积分
/// </summary>
public decimal NeedPoints { get; set; }
public int OrderNum { get; set; }
}

View File

@@ -0,0 +1,47 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Shared.Etos;
using Yi.Framework.Rbac.Domain.Entities;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Domain.EventHandlers;
/// <summary>
/// 临时账号绑定到正式账号,钱钱 (累加),禁用临时账号(修改)
/// </summary>
public class BindAccountForBbsEventHandler : ILocalEventHandler<BindAccountEto>, ITransientDependency
{
private readonly ISqlSugarRepository<BbsUserExtraInfoEntity> _bbsUserRepository;
private readonly ISqlSugarRepository<UserAggregateRoot> _userRepository;
public BindAccountForBbsEventHandler(ISqlSugarRepository<BbsUserExtraInfoEntity> bbsUserRepository,
ISqlSugarRepository<UserAggregateRoot> userRepository)
{
_bbsUserRepository = bbsUserRepository;
_userRepository = userRepository;
}
public async Task HandleEventAsync(BindAccountEto eventData)
{
//禁用临时用户
var oldUser = await _userRepository.GetFirstAsync(x => x.Id == eventData.OldUserId);
if (oldUser is null || oldUser.State == false)
{
throw new UserFriendlyException("无法将无效用户进行绑定");
}
oldUser.State = false;
await _userRepository.UpdateAsync(oldUser);
//账户钱转移
var bbsOldUser = await _bbsUserRepository.GetFirstAsync(x => x.UserId == eventData.OldUserId);
var bbsNewUser = await _bbsUserRepository.GetFirstAsync(x => x.UserId == eventData.NewUserId);
if (bbsNewUser is not null)
{
bbsNewUser.Money += bbsOldUser?.Money ?? 0;
await _bbsUserRepository.UpdateAsync(bbsNewUser);
}
}
}

View File

@@ -1,11 +0,0 @@
using Volo.Abp.Domain.Services;
namespace Yi.Framework.Bbs.Domain.Managers;
/// <summary>
/// bbs商品领域
/// </summary>
public class BbsShopManager: DomainService
{
}

View File

@@ -14,7 +14,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
{
public ISqlSugarRepository<UserAggregateRoot> _userRepository;
public ISqlSugarRepository<BbsUserExtraInfoEntity> _bbsUserInfoRepository;
public Dictionary<int, LevelCacheItem> _levelCacheDic;
// public Dictionary<int, LevelCacheItem> _levelCacheDic;
private LevelManager _levelManager;
public BbsUserManager(ISqlSugarRepository<UserAggregateRoot> userRepository,
ISqlSugarRepository<BbsUserExtraInfoEntity> bbsUserInfoRepository,
@@ -23,7 +24,12 @@ namespace Yi.Framework.Bbs.Domain.Managers
{
_userRepository = userRepository;
_bbsUserInfoRepository = bbsUserInfoRepository;
_levelCacheDic = levelManager.GetCacheMapAsync().Result;
_levelManager = levelManager;
}
public async Task<Dictionary<int, LevelCacheItem>> GetLevelCacheMapAsync()
{
return await _levelManager.GetCacheMapAsync();
}
public async Task<BbsUserInfoDto?> GetBbsUserInfoAsync(Guid userId)
@@ -44,7 +50,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
}, true)
.FirstAsync(user => user.Id == userId);
userInfo.LevelName = _levelCacheDic[userInfo.Level].Name;
var levelCacheDic= await GetLevelCacheMapAsync();
userInfo.LevelName = levelCacheDic[userInfo.Level].Name;
return userInfo;
}
@@ -66,7 +73,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
DiscussNumber = info.DiscussNumber
}, true)
.ToListAsync();
userInfos?.ForEach(userInfo => userInfo.LevelName = _levelCacheDic[userInfo.Level].Name);
var levelCacheDic= await GetLevelCacheMapAsync();
userInfos?.ForEach(userInfo => userInfo.LevelName =levelCacheDic[userInfo.Level].Name);
return userInfos ?? new List<BbsUserInfoDto>();
}

View File

@@ -1,10 +1,13 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Domain.Services;
using Volo.Abp.Users;
using Yi.Framework.Bbs.Domain.Entities.Forum;
using Yi.Framework.Bbs.Domain.Managers.ArticleImport;
using Yi.Framework.Bbs.Domain.Shared.Consts;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.Bbs.Domain.Shared.Model;
using Yi.Framework.Rbac.Domain.Shared.Consts;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Domain.Managers
@@ -44,6 +47,60 @@ namespace Yi.Framework.Bbs.Domain.Managers
return await _commentRepository.InsertReturnEntityAsync(entity);
}
/// <summary>
/// 校验主题查询权限
/// </summary>
/// <param name="discussId"></param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
public async Task<bool> VerifyDiscussPermissionAsync(Guid discussId,Guid? userId,string[] roles=null,bool isVerifyLook=true)
{
var discuss = await _discussRepository.GetFirstAsync(x => x.Id == discussId);
if (discuss is null)
{
throw new UserFriendlyException(DiscussConst.No_Exist);
}
//作者是自己,直接有权限
if (discuss.CreatorId ==userId)
{
return true;
}
//管理员,直接放行
if (roles is not null&&roles.Contains(UserConst.AdminRolesCode))
{
return true;
}
//是否为校验 查看权限, 其他操作权限(增删改)
if (isVerifyLook)
{
//要求角色
if (discuss.PermissionType == DiscussPermissionTypeEnum.Role)
{
if (roles is null)
{
return false;
}
List<string> roleList = roles.ToList();
//所选角色,没有任何交集
if (!discuss.PermissionRoleCodes.Intersect(roleList).Any())
{
return false;
}
}
//通过了上面要求,剩下的都是有权限的,可以直接看
return true;
}
else
{
//通过了上面的要求,剩下的就是没有权限了,直接拦截
return false;
}
}
/// <summary>
/// 导入文章
/// </summary>

View File

@@ -0,0 +1,55 @@
using Volo.Abp.Domain.Services;
using Yi.Framework.Bbs.Domain.Entities.Shop;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Domain.Managers.Shop;
/// <summary>
/// bbs商城领域服务
/// </summary>
public class BbsShopManager : DomainService
{
private readonly ISqlSugarRepository<BbsGoodsAggregateRoot> _repository;
private readonly ISqlSugarRepository<BbsGoodsApplyAggregateRoot> _applyRepository;
public BbsShopManager(ISqlSugarRepository<BbsGoodsAggregateRoot> repository,
ISqlSugarRepository<BbsGoodsApplyAggregateRoot> applyRepository)
{
_repository = repository;
_applyRepository = applyRepository;
}
/// <summary>
/// 申请购买商品
/// </summary>
/// <param name="userId"></param>
/// <param name="goodsId"></param>
/// <param name="contactInformation"></param>
/// <exception cref="UserFriendlyException"></exception>
public async Task BuyAsync(Guid userId, Guid goodsId,string contactInformation)
{
var goods = await _repository.GetFirstAsync(x => x.Id == goodsId);
if (goods.GoodsType==GoodsTypeEnum.Apply)
{
var count= await _applyRepository.CountAsync(x => x.UserId == userId);
if (count>=goods.LimitNumber)
{
throw new UserFriendlyException("你已经达该商品最大限购次数");
}
await _applyRepository.InsertAsync(new BbsGoodsApplyAggregateRoot
{
GoodsId = goodsId,
UserId = userId,
ContactInformation = contactInformation
});
//更新库存
goods.StockNumber -= 1;
await _repository.UpdateAsync(goods);
}
}
}

View File

@@ -0,0 +1,14 @@
using Yi.Framework.Bbs.Domain.Entities.Forum;
using Yi.Framework.Bbs.Domain.Shared.Caches;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Domain.Repositories;
public interface IDiscussLableRepository: ISqlSugarRepository<DiscussLableAggregateRoot,Guid>
{
/// <summary>
/// 获取所有分类的字典
/// </summary>
/// <returns></returns>
Task<Dictionary<Guid, DiscussLableCacheItem>> GetDiscussLableCacheMapAsync();
}

View File

@@ -0,0 +1,37 @@
using Mapster;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Yi.Framework.Bbs.Domain.Entities.Forum;
using Yi.Framework.Bbs.Domain.Repositories;
using Yi.Framework.Bbs.Domain.Shared.Caches;
using Yi.Framework.Bbs.Domain.Shared.Consts;
using Yi.Framework.SqlSugarCore.Abstractions;
using Yi.Framework.SqlSugarCore.Repositories;
namespace Yi.Framework.Bbs.SqlSugarCore.Repositories;
public class DiscussLableRepository : SqlSugarRepository<DiscussLableAggregateRoot, Guid>, IDiscussLableRepository,
ITransientDependency
{
private readonly IDistributedCache<List<DiscussLableCacheItem>> _lableCache;
public DiscussLableRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider,
IDistributedCache<List<DiscussLableCacheItem>> lableCache) : base(sugarDbContextProvider)
{
_lableCache = lableCache;
}
/// <summary>
/// 获取所有分类的字典
/// </summary>
/// <returns></returns>
public async Task<Dictionary<Guid, DiscussLableCacheItem>> GetDiscussLableCacheMapAsync()
{
var cahce = await _lableCache.GetOrAddAsync(DiscussLableConst.DiscussLableCacheKey, async () =>
{
var entities = await _DbQueryable.ToListAsync();
return entities.Adapt<List<DiscussLableCacheItem>>();
});
return cahce.ToDictionary(x => x.Id);
}
}

View File

@@ -23,14 +23,13 @@ namespace Yi.Framework.ChatHub.Application.Services
/// <param name="chatContext"></param>
/// <returns></returns>
[Authorize]
[HttpPost]
public async Task ChatAsync([FromBody] List<AiChatContextDto> chatContext)
[HttpPost("ai-chat/chat/{model}")]
public async Task ChatAsync([FromRoute]string model, [FromBody] List<AiChatContextDto> chatContext)
{
const int maxChar = 10;
var contextId = Guid.NewGuid();
Queue<string> stringQueue = new Queue<string>();
await foreach (var aiResult in _aiManager.ChatAsStreamAsync(chatContext))
await foreach (var aiResult in _aiManager.ChatAsStreamAsync(model,chatContext))
{
stringQueue.Enqueue(aiResult);
@@ -42,7 +41,7 @@ namespace Yi.Framework.ChatHub.Application.Services
var str = stringQueue.Dequeue();
currentStr.Append(str);
}
await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(currentStr.ToString(), CurrentUser.Id!.Value, contextId));
await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(currentStr.ToString(), CurrentUser.Id!.Value, contextId),model);
}
}
@@ -52,9 +51,7 @@ namespace Yi.Framework.ChatHub.Application.Services
var str = stringQueue.Dequeue();
currentEndStr.Append(str);
}
await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(currentEndStr.ToString(), CurrentUser.Id!.Value, contextId));
//await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(null, CurrentUser.Id!.Value, contextId));
await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(currentEndStr.ToString(), CurrentUser.Id!.Value, contextId),model);
}
}
}

View File

@@ -24,19 +24,8 @@ namespace Yi.Framework.ChatHub.Domain.Managers
}
private OpenAIService OpenAIService { get; }
public async IAsyncEnumerable<string> ChatAsStreamAsync(List<AiChatContextDto> aiChatContextDtos)
public async IAsyncEnumerable<string> ChatAsStreamAsync(string model, List<AiChatContextDto> aiChatContextDtos)
{
//var temp = "站长正在接入ChatGpt,敬请期待~";
//for (var i = 0; i < temp.Length; i++)
//{
// await Task.Delay(200);
// yield return temp[i].ToString();
//}
if (aiChatContextDtos.Count == 0)
{
yield return null;
@@ -56,7 +45,7 @@ namespace Yi.Framework.ChatHub.Domain.Managers
var completionResult = OpenAIService.ChatCompletion.CreateCompletionAsStream(new ChatCompletionCreateRequest
{
Messages = messages,
Model = Models.Gpt_4o_mini
Model =model
});
HttpStatusCode? error = null;

View File

@@ -31,7 +31,14 @@ namespace Yi.Framework.ChatHub.Domain.Managers
private IRedisClient RedisClient => LazyServiceProvider.LazyGetRequiredService<IRedisClient>();
private string CacheKeyPrefix => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpDistributedCacheOptions>>().Value.KeyPrefix;
public async Task SendMessageAsync(MessageContext context)
/// <summary>
/// 发送消息
/// </summary>
/// <param name="context">消息内容</param>
/// <param name="relStr">关联字符</param>
/// <exception cref="NotImplementedException"></exception>
public async Task SendMessageAsync(MessageContext context,string relStr=null)
{
switch (context.MessageType)
{
@@ -39,20 +46,20 @@ namespace Yi.Framework.ChatHub.Domain.Managers
var userModel = await GetUserAsync(context.ReceiveId.Value);
if (userModel is not null)
{
await _hubContext.Clients.Client(userModel.ClientId).SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType, context);
await _hubContext.Clients.Client(userModel.ClientId).SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType,relStr, context);
}
break;
case MessageTypeEnum.Group:
throw new NotImplementedException();
break;
case MessageTypeEnum.All:
await _hubContext.Clients.All.SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType, context);
await _hubContext.Clients.All.SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType,relStr, context);
break;
case MessageTypeEnum.Ai:
var userModel2 = await GetUserAsync(context.ReceiveId.Value);
if (userModel2 is not null)
{
await _hubContext.Clients.Client(userModel2.ClientId).SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType, context);
await _hubContext.Clients.Client(userModel2.ClientId).SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType,relStr, context);
}
break;

View File

@@ -0,0 +1,18 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Account;
public class BindInput
{
public string JsCode { get; set; }
public long Phone { get; set; }
/// <summary>
/// 唯一标识码
/// </summary>
public string? Uuid { get; set; }
/// <summary>
/// 验证码
/// </summary>
public string? Code { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Account;
public class LoginInput
{
/// <summary>
/// 微信小程序jscode
/// </summary>
public string JsCode { get; set; }
}

View File

@@ -0,0 +1,11 @@
using Yi.Framework.DigitalCollectibles.Domain.Shared.Enums;
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Account;
public class LoginOutput
{
/// <summary>
/// 后端访问token
/// </summary>
public string? Token { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Account;
public class RegisterInput
{
/// <summary>
/// 微信小程序code
/// </summary>
public string JsCode { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Analyse;
public class DcPointsTopUserDto
{
public Guid UserId { get; set; }
public int Points { get; set; }
public int Order { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Analyse;
public class DcValueTopUserDto
{
public Guid UserId { get; set; }
public decimal Value { get; set; }
public int Order { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Collectibles;
public class CollectiblesAccountInfoDto
{
public decimal TotalValue { get; set; }
}

View File

@@ -0,0 +1,47 @@
using Volo.Abp.Application.Dtos;
using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts;
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Collectibles;
public class CollectiblesDto : EntityDto<Guid>
{
/// <summary>
/// 藏品编号
/// </summary>
public string Code { get; set; }
/// <summary>
/// 藏品名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 藏品描述
/// </summary>
public string? Describe { get; set; }
/// <summary>
/// 价值数
/// </summary>
public decimal ValueNumber { get; set; }
/// <summary>
/// 藏品地址
/// </summary>
public string Url { get; set; }
/// <summary>
/// 稀有度
/// </summary>
public RarityEnum Rarity{ get; set; }
/// <summary>
/// 总共出现次数
/// </summary>
public int FindTotal { get; set; }
/// <summary>
/// 排序
/// </summary>
public int OrderNum { get; set; }
}

View File

@@ -0,0 +1,8 @@
using Yi.Framework.Ddd.Application.Contracts;
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Collectibles;
public class CollectiblesUserGetInput:PagedAllResultRequestDto
{
}

View File

@@ -0,0 +1,16 @@
using Volo.Abp.Application.Dtos;
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Collectibles;
public class CollectiblesUserGetOutputDto : EntityDto<Guid>
{
/// <summary>
/// 藏品
/// </summary>
public CollectiblesDto Collectibles{ get; set; }
/// <summary>
/// 数量
/// </summary>
public int Number { get; set; }
}

View File

@@ -0,0 +1,20 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.InvitationCode;
public class InvitationCodeGetOutputDto
{
/// <summary>
/// 是否填写了邀请码(是否被邀请)
/// </summary>
public bool IsInvited { get; set; }
/// <summary>
/// 积分-邀请数量
/// </summary>
public int PointsNumber { get; set; }
/// <summary>
/// 邀请码
/// </summary>
public string InvitationCode { get; set; }
}

View File

@@ -0,0 +1,9 @@
using Volo.Abp.Application.Dtos;
using Yi.Framework.Ddd.Application.Contracts;
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Market;
public class MarketGetListInput:PagedAllResultRequestDto
{
}

View File

@@ -0,0 +1,30 @@
using Volo.Abp.Application.Dtos;
using Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Collectibles;
using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts;
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Market;
public class MarketGetListOutputDto:EntityDto<Guid>
{
/// <summary>
/// 上架时间
/// </summary>
public DateTime CreationTime{ get; set; }
/// <summary>
/// 出售者用户id
/// </summary>
public Guid SellUserId { get; set; }
/// <summary>
/// 出售数量
/// </summary>
public int SellNumber{ get; set; }
/// <summary>
/// 出售单价
/// </summary>
public decimal UnitPrice{ get; set; }
/// <summary>
/// 藏品
/// </summary>
public CollectiblesDto Collectibles{ get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Market;
public class PurchaseGoodsDto
{
public Guid MarketGoodsId{ get; set; }
public int Number{ get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Market;
public class ShelvedGoodsDto
{
public Guid CollectiblesId { get; set; }
public int Number { get; set; }
public decimal Money { get; set; }
}

View File

@@ -0,0 +1,44 @@
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.MiningPool;
public class MiningPoolGetOutput
{
/// <summary>
/// 普通藏品剩余数量
/// </summary>
public int I0_OrdinaryNumber { get; set; }
/// <summary>
/// 高级藏品剩余数量
/// </summary>
public int I1_SeniorNumber { get; set; }
/// <summary>
/// 稀有藏品剩余数量
/// </summary>
public int I2_RareNumber { get; set; }
/// <summary>
/// 珍品藏品剩余数量
/// </summary>
public int I3_GemNumber { get; set; }
/// <summary>
/// 传说藏品剩余数量
/// </summary>
public int I4_LegendNumber { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime StartTime{ get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime EndTime{ get; set; }
/// <summary>
/// 总共剩余藏品数量
/// </summary>
public int TotalNumber => I0_OrdinaryNumber + I1_SeniorNumber + I2_RareNumber + I3_GemNumber + I4_LegendNumber;
}

View File

@@ -0,0 +1,9 @@
using Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Collectibles;
using Yi.Framework.DigitalCollectibles.Domain.Shared.Enums;
namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.MiningPool;
public class MiningResultOutput
{
public CollectiblesDto? Collectibles{ get; set; }
}

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