250716提交

This commit is contained in:
yangxing 2025-07-16 17:20:39 +08:00
commit 5117cfa4c2
1679 changed files with 1191288 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/admin/dist
/admin/package-lock.json
/netcore/src/JT.Shop.Web.Entry/wwwroot/uploadfile
/netcore/src/JT.Shop.Web.Entry/App_Data
/.tgitconfig

173
README.md Normal file
View File

@ -0,0 +1,173 @@
### 门店管理系统
- 使用EFCORE+Furion+NET7
- 依赖redis
### 数据库
- mysql
- 数据库地址123.249.79.37
- 数据库端口号3306
### 服务器
- IP:123.249.79.37
-宝塔地址:<https://123.249.79.37:28351/8698ed07>
### 数据结构更新
1. 更改 CodeFirst 结构 [更改模型文档](https://learn.microsoft.com/zh-cn/ef/core/modeling/)
2. 在程序包管理器控制台默认项目中选择“src\JT.Shop.Database.Migrations”
```
//添加迁移架构代码
Add-Migration 新版本号 -Context DefaultDbContext
//以下应用适合生产环境的迁移方法
//方法一:生成一个从指定 from 迁移到指定 to 迁移的 SQL 脚本。警告:潜在的数据丢失方案。
Script-Migration 上个版本号 新版本号 -Context DefaultDbContext
//方法二:幂等 SQL 脚本。此类脚本将在内部检查已经应用哪些迁移(通过迁移历史记录表),并且只应用缺少的迁移。
Script-Migration -Idempotent
```
### 目录结构
├── doc 文档
└── netcore .NET7项目
└── src 源代码
├── JT.Shop.Application 业务模块
│   ├── JobService 定时任务
│   ├── Mapper DTO映射
│   └── Service 服务接口
│   ├── BaseCommon 基础服务
│   │   ├── Http http请求封装接口
│   │   ├── QrCode 二维码封装接口
│   │   ├── SMS 短信封装接口
│   │   └── Upload 文件上传接口
│   ├── Business 总部业务服务
│   │   ├── BodyType 身体部份管理
│   │   ├── Clerk 店员管理
│   │   ├── Device 设备管理
│   │   │   └── Type 设备类型管理
│   │   ├── Member 会员管理
│   │   ├── Org 组织管理
│   │   ├── OutProduct 出货管理
│   │   ├── Pos 职位管理
│   │   ├── Product 产品管理
│   │   ├── Retailer 分销管理,未使用
│   │   ├── Role 角色管理
│   │   ├── Serve 服务管理
│   │   ├── Shop 门店管理
│   │   └── WX 公众号管理
│   ├── Mch 门店业务服务
│   │   ├── Account 门店账号管理
│   │   ├── Body 门店部位管理
│   │   ├── Clerk 门店店员管理
│   │   ├── Conf 门店配置管理
│   │   ├── Device 门店设备管理
│   │   ├── Member 门店会员管理
│   │   ├── Product 门店产品管理
│   │   └── Serve 门店服务管理
│   ├── ShopApi 门店H5接口
│   │   ├── Device 门店设备管理
│   │   ├── MP 门店公众号管理
│   │   ├── Member 门店会员管理
│   │   ├── Notice 门店通知管理
│   │   ├── Report 门店报表管理
│   │   ├── Shop 门店管理
│   │   └── User 门店用户管理
│   ├── System 系统接口服务
│   │   ├── App 应用管理
│   │   ├── Auth 登录相关管理
│   │   ├── Base 通用方法
│   │   ├── Cache 缓存管理
│   │   ├── Captcha 验证码管理
│   │   │   ├── ClickWord
│   │   │   └── General
│   │   ├── Config 配置管理
│   │   ├── Dict 字典管理
│   │   ├── Emp 员工管理
│   │   ├── Enum 枚举管理
│   │   ├── File 文件管理
│   │   ├── Forms 表单管理
│   │   ├── Hubs 聊天管理
│   │   ├── Logger 日志管理
│   │   ├── Menu 菜单管理
│   │   ├── Message 消息管理
│   │   ├── Monitor 监控管理
│   │   ├── Notice 通知管理
│   │   ├── OnlineUser 在线用户管理
│   │   ├── Org 组织管理
│   │   ├── Pos 职位管理
│   │   ├── Role 角色管理
│   │   ├── StepBody 步骤管理
│   │   ├── System 系统管理
│   │   ├── Timer 定时任务管理
│   │   └── User 用户管理
│   ├── Test 测试单元
│   └── UserApi 门店用户H5接口
│   ├── Level 标准等级管理
│   ├── Result 测量结果管理
│   └── User 账户管理
├── JT.Shop.Core 框架核心,引用Nuget包
│   ├── Filter 拦截器
│   └── Util 辅助类
├── JT.Shop.Database.Migrations 数据库迁移
│   ├── Migrations 迁移文件
│   └── sql sql脚本
├── JT.Shop.Domain 领域模型
│   ├── Entity 数据库实体
│   │   ├── Business 业务层实体
│   │   ├── Client 用户层实体
│   │   ├── SeedData 种子数据
│   │   ├── Shop 门店层实体
│   │   └── System 系统层实体
│   │   └── WorkflowEntity
│   ├── ErrCode 错误码
│   ├── Options 选项配置
│   └── Properties 配置文件
├── JT.Shop.Domain.Shared 常用枚举和常量定义
│   ├── Const 常量定义
│   ├── Enum 枚举定义
│   └── Properties 配置文件
├── JT.Shop.EntityFramework.Core EntityFrameworkCore管理
│   ├── DbContexts 数据库配置
│   ├── Extensions 数据库扩展
│   └── Repository 仓储
├── JT.Shop.EventBus 事件总线
│   └── Service 订阅者
│   ├── Logger 日志订阅
│   └── Report 统计订阅
├── JT.Shop.HealthCheck 健康检查,未使用
│   └── Extensions
├── JT.Shop.Web.Entry web层
│   ├── App_Data 缓存文件
│   │   └── SenparcTraceLog
│   ├── Controllers 控制器
│   ├── Handlers 中间件
│   ├── Properties 发布配置
│   │   └── PublishProfiles
│   ├── Views 视图
│   │   ├── Auth 公众号授权相关
│   │   ├── Home 首页
│   │   ├── Qr 二维码入口相关
│   │   └── Shared 共享页面
│   └── wwwroot 静态资源
│   ├── css
│   ├── image
│   ├── js
│   ├── tpl
│   ├── uploadfile
│   │   └── images
│   │   ├── 20240309
│   │   ├── 20240417
│   │   └── share
│   │   └── 202404
│   └── vant
└── JT.Shop.WeiXin 微信公众号
└── Service 微信公众号服务
└── MP 微信公众号服务

Binary file not shown.

217
doc/uprade-20250110.sql Normal file
View File

@ -0,0 +1,217 @@
-- 步骤1开始————————————————
-- 结构更新前
ALTER TABLE `pc_shopdayreport` ADD COLUMN `UpdateTime` datetime(0) NULL COMMENT '统计时间' AFTER `SXBodypartsNum`;
Update pc_shopdayreport set UpdateTime = CreatedTime where UpdateTime is null;
ALTER TABLE `pc_shopregusermonthreport` ADD COLUMN `UpdateTime` datetime(0) NULL COMMENT '统计时间' AFTER `ShopUserWeightAvg`;
Update pc_shopregusermonthreport set UpdateTime = CreatedTime where UpdateTime is null;
TRUNCATE table pc_shopreguser_rank;
ALTER TABLE `pc_shopreguser_enter` ADD `Date` date NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '统计日期';
update pc_shopreguser_enter set Date=DATE(CreatedTime);
ALTER TABLE `pc_shopreguser_bodyresult` ADD `Date` date NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '统计日期';
Update `pc_shopreguser_bodyresult` set `Date` =Date(CreatedTime);
ALTER TABLE `pc_userresult` ADD `RecordDate` date NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '记录日期';
Update pc_userresult set RecordDate=Date(RecordTime);
-- 步骤1结束————————————————
-- 步骤2开始————————————————
-- 重复执行删除 开始 直至全部Affected rows 为 0 12次
delete from pc_shopaccountdayservereport where id in (select id from (select CreatedTime,ServeId,UserId,count(Id) qty,min(id) id from pc_shopaccountdayservereport group by CreatedTime,ServeId,UserId) t where t.qty>1);
delete from pc_shopregusersxdata where id in(select t.id from (select d.id from pc_shopregusersxdata d left join pc_shopreguser u on u.id=d.RegUserId where u.ShopId<>d.ShopId or u.id is null) t);
delete from pc_shopreguserdata where id in(select t.id from( select d.id from pc_shopreguserdata d left join pc_shopreguser u on u.id=d.RegUserId where u.ShopId<>d.ShopId or u.id is null) t);
delete from pc_shopreguser_enter where id in (select id from ( select `Date`, `RegUserId`, `ShopId`,count(*) qty,max(id) id from pc_shopreguser_enter group by `Date`, `RegUserId`, `ShopId`) t where t.qty>1);
delete from pc_shopreguserdata where id = 17064723041733;
delete from pc_shopreguser_bodyresult where id IN( select id from (select `Date`, `RegUserId`, `ShopId`,count(*) qty,max(id) id from `pc_shopreguser_bodyresult` group by `Date`, `RegUserId`, `ShopId`) t where t.qty>1);
delete from pc_result where id in(select id from ( select RecordDate,RegUserId,count(*) qty,min(r.id) id from pc_userresult ur join pc_result r on r.id=ur.ResultId group by RecordDate,RegUserId) t where t.qty>1);
delete from pc_userresult where id in(select id from ( select RecordDate,RegUserId,count(*) qty,min(id) id from pc_userresult group by RecordDate,RegUserId) t where t.qty>1);
DELETE from pc_shopdayreport t1 WHERE id in ( select id from (select `CreatedTime`, `ShopId`, `BusinessId`,count(*) qty,min(id) id from pc_shopdayreport group by `CreatedTime`, `ShopId`, `BusinessId` having count(*)>1)t);
delete from pc_shopregusermonthreport where id in(select id from ( select CreatedTime,ShopId,count(*) qty,min(id) id from pc_shopregusermonthreport group by CreatedTime,ShopId) t where t.qty>1);
delete from pc_shopreguserwx where openid in (select OpenId from ( select `OpenId`,count(*) qty from pc_shopreguserwx group by `OpenId`) t where t.qty>1);
delete from pc_shopreguserwx where RegUserId in (select RegUserId from ( select RegUserId,count(*) qty from pc_shopreguserwx group by RegUserId) t where t.qty>1);
DELETE FROM pc_shopreguser WHERE ID IN(
SELECT ID FROM( SELECT ID FROM pc_shopreguser WHERE SHOPID ='17000843870917' AND (PHONE='15592630916' OR PHONE='18391767793' OR PHONE='13609275138')
AND ( LastLoginIp IS NULL OR LastLoginIp='')) AS T );
delete from pc_shopaccountdayreport where id IN( select id from (select CreatedTime,UserId,count(*) qty,max(id) id from `pc_shopaccountdayreport` group by CreatedTime,UserId) t where t.qty>1);
delete from pc_shopreguserwx where id in (select id from (select OpenId,count(*) qty,min(id) id from pc_shopreguserwx group by OpenId having qty>1)t);
-- 重复执行删除 结束
-- 步骤2结束————————————————
-- 步骤3开始————————————————
-- 清理无用数据 开始 直至全部Affected rows 为 0
delete from pc_shopserviceresultclerk where id in (select id from (select r.id from pc_shopserviceresultclerk r left join pc_shop_account ru on ru.id=r.userid where ru.id is null )t);
delete from pc_shopaccountdayservereport where id in (select id from (select r.id from pc_shopaccountdayservereport r left join pc_shop_account ru on ru.id=r.userid where ru.id is null) t);
delete from pc_shopaccountdayservereport where id in (select id from (select r.id from pc_shopaccountdayservereport r left join pc_shopservice s on s.id=r.serveid where s.id is null )t);
delete from pc_shopaccountdayservereport where id in (select id from ( select r.id from pc_shopaccountdayservereport r left join pc_shopservice s on s.id=r.serveid where s.id is null) t);
delete from pc_shopaccountdayservereport where id IN( select id from (select CreatedTime,ServeId,UserId,count(*) qty,max(id) id from `pc_shopaccountdayservereport` group by CreatedTime,ServeId,UserId) t where t.qty>1);
-- 清理无用数据 结束
-- 步骤3结束————————————————
-- 步骤4开始————————————————
-- 开始使用“工具”-”结构同步...“更新
-- 线上测试库 jt_shop_v2_test ——> 本地新建的数据库 直接部署 保证没有错误
-- 结构更新后
-- 步骤4结束————————————————
-- 步骤5开始————————————————
-- 设置 JT.Shop.Upgrade.Host为启动项目
-- 修改 JT.Shop.Upgrade.Host的数据库配置文件
-- 打开 http://localhost:5041/api/v2/do
-- 步骤5结束————————————————
-- 步骤6开始————————————————
-- $2a$11$pSdA2iZzB0qr0tMELfCTs.OOG35xsmDRxsxyX2zdRMyxPMuEF6ddy
update sys_user set `Password` = '$2a$11$pSdA2iZzB0qr0tMELfCTs.OOG35xsmDRxsxyX2zdRMyxPMuEF6ddy',`Phone` = '15037185661' WHERE `Account` = 'superAdmin';
update pc_shophead_level set ParentId=0,`Level`=0 where HeadId=1;
update pc_shophead set ParentHeadId=0 where id=1;
update sys_menu set AccountIdentity=10 where Application='system' or Application='manage';
update sys_menu set AccountIdentity=10 where code like 'sys_%';
update pc_shop_account set AdminType=3 where AdminType=0;
update pc_shop_account set AdminType=1 where phone='15037185661';
update sys_menu set name='平台用户管理' where code='sys_user_mgr';
update pc_shopreguserdata set LastCycleOrderId =IFNULL( (select CycleOrderId from pc_shopregusersxdata d where d.RegUserId= pc_shopreguserdata.RegUserId ),0) where LastCycleOrderId=0 and RType<5;
update pc_shopreguserdata set ServiceStatus=0 where EXISTS (select * from pc_shopregusersxdata d where d.RegUserId=pc_shopreguserdata.RegUserId and d.CycleOrderId=0 and BodyOrderId=0);
update pc_shopreguserdata set ServiceStatus=1 where EXISTS (select * from pc_shopregusersxdata d where d.RegUserId=pc_shopreguserdata.RegUserId and (d.CycleOrderId>0 or BodyOrderId>0));
update pc_shopreguserdata set FirstWeightTime=( select CreatedTime from pc_shopreguser_sxorder o where o.id=pc_shopreguserdata.LastCycleOrderId ) where FirstWeightTime is null and LastCycleOrderId>0;
update pc_shopreguserdata set RType=6 where ServiceStatus=0 and RType<>6;
update pc_shopreguserdata set IsDB=false,DBTime=null where IsDB=true and StandWeight< LastWeight and RType<3 and Date(DBTime)=Date(DealTime);
update pc_shopreguserdata set IsDB=false,DBTime=null where IsDB=true and StandWeight< LastWeight and RType<3 and Date(DBTime)=Date(LastEntryTime);
update pc_shopreguserdata set IsDB=false,DBTime=null where IsDB=true and StandWeight< MinWeight;
update pc_shopregusersxdata set SerCnt=(select count(*) from pc_shopreguser_bodyresult r where r.RegUserId=pc_shopregusersxdata.RegUserId);
update pc_shop_body_type set Image=CONCAT('/image/body-type/',Image,'.png') where Image not like '%.png';
update pc_shopsetting set WXClientType=1; -- 默认门店客户端H5 WXClientType=0代表微信小程序
-- 步骤6结束————————————————
-- 步骤7开始————————————————
SET FOREIGN_KEY_CHECKS = 0;
INSERT INTO `sys_menu`(`Id`, `Pid`, `Pids`, `Name`, `Code`, `Type`, `Icon`, `Router`, `Component`, `Permission`, `Application`, `OpenType`, `Visible`, `Link`, `Redirect`, `Weight`, `Sort`, `Remark`, `Status`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `AccountIdentity`) VALUES (18803388670277, 0, '[0],', '平台财务', 'sys_finance', 0, 'money-collect', '/sys_finance', 'PageView', '', 'busiapp', 0, 'Y', NULL, NULL, 2, 10, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, 10);
INSERT INTO `sys_menu`(`Id`, `Pid`, `Pids`, `Name`, `Code`, `Type`, `Icon`, `Router`, `Component`, `Permission`, `Application`, `OpenType`, `Visible`, `Link`, `Redirect`, `Weight`, `Sort`, `Remark`, `Status`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `AccountIdentity`) VALUES (18803415503813, 18803388670277, '[0],[18803388670277],', '点数充值', 'sys_dianshu_recharge', 1, '', '/system/dianshu/recharge', 'system/dianshu/recharge-add', '', 'busiapp', 1, 'Y', NULL, NULL, 2, 100, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, 10);
INSERT INTO `sys_menu`(`Id`, `Pid`, `Pids`, `Name`, `Code`, `Type`, `Icon`, `Router`, `Component`, `Permission`, `Application`, `OpenType`, `Visible`, `Link`, `Redirect`, `Weight`, `Sort`, `Remark`, `Status`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `AccountIdentity`) VALUES (18803433923909, 18803415503813, '[0],[18803388670277],[18803415503813],', '充值', 'sys_dianshu_recharge_add', 2, '', '', '', 'sys:recharge:add', 'busiapp', 0, 'Y', NULL, NULL, 2, 100, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, 10);
INSERT INTO `sys_menu`(`Id`, `Pid`, `Pids`, `Name`, `Code`, `Type`, `Icon`, `Router`, `Component`, `Permission`, `Application`, `OpenType`, `Visible`, `Link`, `Redirect`, `Weight`, `Sort`, `Remark`, `Status`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `AccountIdentity`) VALUES (18803445885637, 18803388670277, '[0],[18803388670277],', '点数充值单', 'sys_dianshu_recharge_order', 1, '', '/system/dianshu/recharge-order', 'system/dianshu/recharge-order', '', 'busiapp', 1, 'Y', NULL, NULL, 2, 100, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, 10);
INSERT INTO `sys_menu`(`Id`, `Pid`, `Pids`, `Name`, `Code`, `Type`, `Icon`, `Router`, `Component`, `Permission`, `Application`, `OpenType`, `Visible`, `Link`, `Redirect`, `Weight`, `Sort`, `Remark`, `Status`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `AccountIdentity`) VALUES (18803469366597, 18803388670277, '[0],[18803388670277],', '目标点数', 'sys_dianshu_target', 1, '', '/system/dianshu/target-list', 'system/dianshu/target-list', '', 'busiapp', 1, 'Y', NULL, NULL, 2, 100, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, 10);
INSERT INTO `sys_menu`(`Id`, `Pid`, `Pids`, `Name`, `Code`, `Type`, `Icon`, `Router`, `Component`, `Permission`, `Application`, `OpenType`, `Visible`, `Link`, `Redirect`, `Weight`, `Sort`, `Remark`, `Status`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `AccountIdentity`) VALUES (18815692883141, 0, '[0],', '授权版本配置', 'sys_business-version', 0, 'setting', '/sys_business-version', 'PageView', '', 'busiapp', 0, 'Y', NULL, NULL, 2, 10, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, 10);
INSERT INTO `sys_menu`(`Id`, `Pid`, `Pids`, `Name`, `Code`, `Type`, `Icon`, `Router`, `Component`, `Permission`, `Application`, `OpenType`, `Visible`, `Link`, `Redirect`, `Weight`, `Sort`, `Remark`, `Status`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `AccountIdentity`) VALUES (18815708928197, 18815692883141, '[0],[18815692883141],', '添加配置', 'sys_business-version_add', 2, '', '/system/business-version/add', '', 'sys:systembusinessversion:add', 'busiapp', 0, 'Y', NULL, NULL, 2, 100, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, 10);
INSERT INTO `sys_menu`(`Id`, `Pid`, `Pids`, `Name`, `Code`, `Type`, `Icon`, `Router`, `Component`, `Permission`, `Application`, `OpenType`, `Visible`, `Link`, `Redirect`, `Weight`, `Sort`, `Remark`, `Status`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `AccountIdentity`) VALUES (18825046730181, 18815692883141, '[0],[18815692883141],', '编辑配置', 'sys_systembusinessversion_edit', 2, '', '', '', 'sys:systembusinessversion:edit', 'busiapp', 0, 'Y', NULL, NULL, 2, 100, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, 10);
INSERT INTO `sys_menu`(`Id`, `Pid`, `Pids`, `Name`, `Code`, `Type`, `Icon`, `Router`, `Component`, `Permission`, `Application`, `OpenType`, `Visible`, `Link`, `Redirect`, `Weight`, `Sort`, `Remark`, `Status`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `AccountIdentity`) VALUES (18825066889157, 18815692883141, '[0],[18815692883141],', '版本列表', 'sys_systembusinessversion_list', 1, '', '/system/business/version/list', 'system/business/version/list', '', 'busiapp', 1, 'Y', NULL, NULL, 2, 100, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, 10);
SET FOREIGN_KEY_CHECKS = 1;
INSERT INTO `pc_businessshopservice`(`Id`, `Name`, `ShowName`, `Code`, `SortCode`, `Status`, `Remark`, `IsWeight`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `BusinessId`, `ShareNameId`, `ComputeTimes`) VALUES (1, '减重', '减重美体师', '', 1, 2, '减重美体师', 1, curdate(), curdate(), NULL, NULL, NULL, NULL, 0, 1, 0, 1);
INSERT INTO `pc_businessshopservice`(`Id`, `Name`, `ShowName`, `Code`, `SortCode`, `Status`, `Remark`, `IsWeight`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `BusinessId`, `ShareNameId`, `ComputeTimes`) VALUES (2, '腹部', '腹部美体师', '', 2, 2, '腹部美体师', 0, curdate(), curdate(), NULL, NULL, NULL, NULL, 0, 1, 0, 1);
INSERT INTO `pc_businessshopservice`(`Id`, `Name`, `ShowName`, `Code`, `SortCode`, `Status`, `Remark`, `IsWeight`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `BusinessId`, `ShareNameId`, `ComputeTimes`) VALUES (3, '手臂', '手臂美体师', '', 3, 2, '手臂美体师', 0, curdate(), curdate(), NULL, NULL, NULL, NULL, 0, 1, 0, 1);
INSERT INTO `pc_businessshopservice`(`Id`, `Name`, `ShowName`, `Code`, `SortCode`, `Status`, `Remark`, `IsWeight`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `BusinessId`, `ShareNameId`, `ComputeTimes`) VALUES (4, '前大腿', '前大腿美体师', '', 4, 2, '前大腿美体师', 0, curdate(), curdate(), NULL, NULL, NULL, NULL, 0, 1, 0, 1);
INSERT INTO `pc_businessshopservice`(`Id`, `Name`, `ShowName`, `Code`, `SortCode`, `Status`, `Remark`, `IsWeight`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `BusinessId`, `ShareNameId`, `ComputeTimes`) VALUES (5, '后大腿', '后大腿美体师', '', 5, 2, '后大腿美体师', 0, curdate(), curdate(), NULL, NULL, NULL, NULL, 0, 1, 0, 1);
INSERT INTO `pc_businessshopservice`(`Id`, `Name`, `ShowName`, `Code`, `SortCode`, `Status`, `Remark`, `IsWeight`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `BusinessId`, `ShareNameId`, `ComputeTimes`) VALUES (6, '小腿', '小腿美体师', '', 6, 2, '小腿美体师', 0, curdate(), curdate(), NULL, NULL, NULL, NULL, 0, 1, 0, 1);
INSERT INTO `pc_businessshopservice`(`Id`, `Name`, `ShowName`, `Code`, `SortCode`, `Status`, `Remark`, `IsWeight`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `BusinessId`, `ShareNameId`, `ComputeTimes`) VALUES (7, '背部', '背部美体师', '', 7, 2, '背部美体师', 0, curdate(), curdate(), NULL, NULL, NULL, NULL, 0, 1, 0, 2);
INSERT INTO `pc_businessshopservice`(`Id`, `Name`, `ShowName`, `Code`, `SortCode`, `Status`, `Remark`, `IsWeight`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `BusinessId`, `ShareNameId`, `ComputeTimes`) VALUES (8, '臀部', '臀部美体师', '', 8, 2, '臀部美体师', 0, curdate(), curdate(), NULL, NULL, NULL, NULL, 0, 1, 0, 2);
INSERT INTO `pc_businessshopservice`(`Id`, `Name`, `ShowName`, `Code`, `SortCode`, `Status`, `Remark`, `IsWeight`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`, `BusinessId`, `ShareNameId`, `ComputeTimes`) VALUES (9, '胸部', '胸部美体师', '', 9, 2, '胸部美体师', 0, curdate(), curdate(), NULL, NULL, NULL, NULL, 0, 1, 0, 2);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (1, 142307070910557, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (2, 142307070910562, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (3, 142307070910561, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (4, 142307070910560, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (5, 142307070910559, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (6, 142307070910558, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (7, 142307070910554, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (8, 142307070910555, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (9, 142307070910556, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (10, 16822817362757, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (11, 16822816142533, 1);
INSERT INTO `pc_businessbody`(`Id`, `BodyId`, `BusinessId`) VALUES (12, 16822809742661, 1);
-- 步骤7结束————————————————
-- 步骤8开始————————————————
update pc_systembusinessversionconfig set UseTimes = (select count(id) from pc_dianshu_consume where SBV_ConfigId=pc_systembusinessversionconfig.id);
update pc_systembusinessversionconfig set UsingCount = (select count(id) from pc_shophead where SystemAuthorization_ConfigId=pc_systembusinessversionconfig.id) where SystemApp=2;
update pc_systembusinessversionconfig set UsingCount = (select count(id) from pc_shop where SystemAuthorization_ConfigId=pc_systembusinessversionconfig.id) where SystemApp=1;
update pc_shopreguserdata set UnIncreaseWeight= LastWeight - StandWeight where LastWeight > StandWeight;
update pc_shopreguserdata set UnIncreaseWeight=0 where LastWeight <= StandWeight;
--
UPDATE `pc_shopaccountdayservereport` SET `BusinessId` = (select BusinessId from `pc_shopservice` s where s.id=`pc_shopaccountdayservereport`.ServeId);
UPDATE `pc_shopaccountdayservereport` SET `ShopId` = (select ShopId from `pc_shopservice` s where s.id=`pc_shopaccountdayservereport`.ServeId);
UPDATE `pc_shopservice` SET `ComputeTimes` = 1;
update `pc_shopservice` set `ComputeTimes`=1,IsWeight=1 where name like '减重%';
update `pc_shopservice` set `ComputeTimes`=1,IsWeight=0 where name like '%腹部%' or name like '%手臂%' or name like '%胯部%' or name like '%大腿%' or name like '%小腿%';
update `pc_shopservice` set `ComputeTimes`=2,IsWeight=0 where name like '%背部%' or name like '%臀部%' or name like '%胸部%' or name like '%淋巴排毒%' or name like '%富贵包%';
UPDATE `pc_businessshopservice` SET `ComputeTimes` = 1;
update `pc_businessshopservice` set `ComputeTimes`=1,IsWeight=1 where name like '减重%';
update `pc_businessshopservice` set `ComputeTimes`=1,IsWeight=0 where name like '%腹部%' or name like '%手臂%' or name like '%胯部%' or name like '%大腿%' or name like '%小腿%';
update `pc_businessshopservice` set `ComputeTimes`=2,IsWeight=0 where name like '%背部%' or name like '%臀部%' or name like '%胸部%' or name like '%淋巴排毒%' or name like '%富贵包%';
INSERT INTO `pc_devicetype`(`Id`, `Name`, `Code`, `Pic`, `Desc`, `ProType`, `BleUrl`, `SupType`, `CreatedTime`, `UpdatedTime`, `CreatedUserId`, `CreatedUserName`, `UpdatedUserId`, `UpdatedUserName`, `IsDeleted`) VALUES (14942660236358, '蓝牙', 2, '', '', 1, 'mini', '', '2025-01-13 00:00:00.000000', NULL, NULL, NULL, NULL, NULL, 0);
update pc_shopreguserwx set shopid = IFNULL((select shopid from pc_shopreguser u where u.id=pc_shopreguserwx.RegUserId),0) ;
update pc_shopreguserwx set AppId='wxfcbb905e3b2b14fb' where AppId is null;
delete from pc_shopreguserwx where shopid=0;
-- 步骤8结束————————————————
-- 步骤9开始————————————————
-- 耗时脚本 开始
update pc_shopaccountdayservereport set Cnt = IFNULL((select count(rc.id)*IFNULL(s.ComputeTimes,1) from pc_shopserviceresultclerk rc join pc_shop_service_result sr on sr.id=rc.ResultId left join pc_shopservice s on s.id=rc.ServeId where rc.UserId=`pc_shopaccountdayservereport`.UserId and rc.ServeId=`pc_shopaccountdayservereport`.ServeId and sr.CreatedTime>=`pc_shopaccountdayservereport`.CreatedTime and sr.CreatedTime<DATE_ADD(`pc_shopaccountdayservereport`.CreatedTime,INTERVAL 1 DAY)),0);
UPDATE `pc_shopaccountdayreport` SET `ServeCnt` = IFNULL((select sum(ds.Cnt) from pc_shopaccountdayservereport ds join pc_shopservice s on s.id=ds.ServeId where ds.UserId=`pc_shopaccountdayreport`.UserId and ds.CreatedTime=`pc_shopaccountdayreport`.CreatedTime),0);
UPDATE `pc_shopaccountdayreport` SET `SXBodypartsNum` = IFNULL((select sum(ds.Cnt) from pc_shopaccountdayservereport ds join pc_shopservice s on s.id=ds.ServeId where s.IsWeight=false and ds.UserId=`pc_shopaccountdayreport`.UserId and ds.CreatedTime=`pc_shopaccountdayreport`.CreatedTime),0);
UPDATE `pc_shopdayreport` set SXBodypartsNum= IFNULL((select sum(IFNULL(SXBodypartsNum,0)) from PC_ShopAccountDayReport dr where dr.ShopId=`pc_shopdayreport`.ShopId and dr.CreatedTime=`pc_shopdayreport`.CreatedTime),0);
UPDATE `pc_shopregusermonthreport` set NewUserCnt = IFNULL((select Count(1) from pc_shopreguserdata dr where dr.ShopId=`pc_shopregusermonthreport`.ShopId and dr.DealTime>=`pc_shopregusermonthreport`.CreatedTime and dr.DealTime<DATE_ADD(`pc_shopregusermonthreport`.CreatedTime,INTERVAL 1 MONTH)),0);
-- 耗时脚本 结束
-- 步骤9结束————————————————
-- 切换到JT.Shop.Web.Entry 修改数据库 然后运行
-- https://localhost:7218/api/public/home/RegUserRankCreate?start=2025-01-01&end=2025-04-09 时间为当前时间的前三个月
-- 等队列消费完 进行数据同步(如果要合并数据,下面步骤可最后执行
-- https://localhost:7218/api/public/home/UpdateShareNames 登录平台端编辑版本功能项 部署自动任务)
--使Navicat Permium ->线 jt_shop_v2_test jt_shop_v2;
-- >(注意)选项中只勾选《插入记录》;
-- > 忽略插入表包括sys_log_ex、sys_role、
-- sys_role_menu、sys_user_role、
-- pc_businessbody、pc_bussinessshopproduct、
-- pc_businessshopservice、pc_share_name
-- > 增加更新表包括sys_user、pc_shop_body_type

BIN
doc/名称释义.xlsx Normal file

Binary file not shown.

BIN
doc/标准体重.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

25
netcore/src/.dockerignore Normal file
View File

@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

138
netcore/src/.editorconfig Normal file
View File

@ -0,0 +1,138 @@
# Rules in this file were initially inferred by Visual Studio IntelliCode from the C:\Baiqian\Workplaces\Gitee\Furion\framework codebase based on best match to current usage at 2021-5-16
# You can modify the rules from these initially generated values to suit your own policies
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
[*.cs]
#Core editorconfig formatting - indentation
#use soft tabs (spaces) for indentation
indent_style = space
#Formatting - indentation options
#indent switch case contents.
csharp_indent_case_contents = true
#labels are placed at one less indent to the current context
csharp_indent_labels = one_less_than_current
#indent switch labels
csharp_indent_switch_labels = true
#Formatting - new line options
#place catch statements on a new line
csharp_new_line_before_catch = true
#place else statements on a new line
csharp_new_line_before_else = true
#require finally statements to be on a new line after the closing brace
csharp_new_line_before_finally = true
#require members of object intializers to be on separate lines
csharp_new_line_before_members_in_object_initializers = true
#require braces to be on a new line for properties, accessors, methods, control_blocks, types, lambdas, and object_collection_array_initializers (also known as "Allman" style)
csharp_new_line_before_open_brace = properties, accessors, methods, control_blocks, types, lambdas, object_collection_array_initializers
#Formatting - organize using options
#do not place System.* using directives before other using directives
dotnet_sort_system_directives_first = false
#Formatting - spacing options
#require NO space between a cast and the value
csharp_space_after_cast = false
#require a space before the colon for bases or interfaces in a type declaration
csharp_space_after_colon_in_inheritance_clause = true
#require a space after a keyword in a control flow statement such as a for loop
csharp_space_after_keywords_in_control_flow_statements = true
#require a space before the colon for bases or interfaces in a type declaration
csharp_space_before_colon_in_inheritance_clause = true
#remove space within empty argument list parentheses
csharp_space_between_method_call_empty_parameter_list_parentheses = false
#remove space between method call name and opening parenthesis
csharp_space_between_method_call_name_and_opening_parenthesis = false
#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
csharp_space_between_method_call_parameter_list_parentheses = false
#remove space within empty parameter list parentheses for a method declaration
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
csharp_space_between_method_declaration_parameter_list_parentheses = false
#Formatting - wrapping options
#leave code block on single line
csharp_preserve_single_line_blocks = true
#leave statements and member declarations on the same line
csharp_preserve_single_line_statements = true
#Style - Code block preferences
#prefer no curly braces if allowed
csharp_prefer_braces = false:suggestion
#Style - expression bodied member options
#prefer block bodies for constructors
csharp_style_expression_bodied_constructors = false:suggestion
#prefer block bodies for methods
csharp_style_expression_bodied_methods = false:suggestion
#prefer expression-bodied members for properties
csharp_style_expression_bodied_properties = true:suggestion
#Style - expression level options
#prefer out variables to be declared inline in the argument list of a method call when possible
csharp_style_inlined_variable_declaration = true:suggestion
#prefer tuple names to ItemX properties
dotnet_style_explicit_tuple_names = true:suggestion
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_member_access = true:suggestion
#Style - Expression-level preferences
#prefer default over default(T)
csharp_prefer_simple_default_expression = true:suggestion
#prefer objects to be initialized using object initializers when possible
dotnet_style_object_initializer = true:suggestion
#prefer inferred tuple element names
dotnet_style_prefer_inferred_tuple_names = true:suggestion
#Style - implicit and explicit types
#prefer var over explicit type in all cases, unless overridden by another code style rule
csharp_style_var_elsewhere = true:suggestion
#prefer var is used to declare variables with built-in system types such as int
csharp_style_var_for_built_in_types = true:suggestion
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
csharp_style_var_when_type_is_apparent = true:suggestion
#Style - language keyword and framework type options
#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
#Style - Miscellaneous preferences
#prefer anonymous functions over local functions
csharp_style_pattern_local_over_anonymous_function = false:suggestion
#Style - Modifier preferences
#when this rule is set to a list of modifiers, prefer the specified ordering.
csharp_preferred_modifier_order = public,private,internal,protected,static,virtual,readonly,async,override,abstract,new:suggestion
#Style - Pattern matching
#prefer pattern matching instead of is expression with type casts
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
#Style - qualification options
#prefer fields not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_field = false:suggestion
#prefer methods not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_method = false:suggestion
#prefer properties not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_property = false:suggestion
# Add copyright file header
file_header_template = 品传科技\n开发:李鹏鹏\n------------------------------------------------------------------------

63
netcore/src/.gitattributes vendored Normal file
View File

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

363
netcore/src/.gitignore vendored Normal file
View File

@ -0,0 +1,363 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd

View File

@ -0,0 +1,5 @@
@ECHO OFF
for /f "tokens=*" %%a in ('dir obj /b /ad /s ^|sort') do rd "%%a" /s/q
for /f "tokens=*" %%a in ('dir bin /b /ad /s ^|sort') do rd "%%a" /s/q
echo print obj和bin清理完成
pause

View File

@ -0,0 +1,228 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="2.0.24" />
<PackageVersion Include="aliyun-net-sdk-sts" Version="3.1.2" />
<PackageVersion Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
<PackageVersion Include="AsyncKeyedLock" Version="6.3.4" />
<PackageVersion Include="Autofac" Version="8.0.0" />
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
<PackageVersion Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
<PackageVersion Include="AutoMapper" Version="13.0.1" />
<PackageVersion Include="Asp.Versioning.Mvc" Version="8.1.0" />
<PackageVersion Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageVersion Include="AWSSDK.S3" Version="3.7.300.2" />
<PackageVersion Include="AWSSDK.SecurityToken" Version="3.7.300.2" />
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.17.0" />
<PackageVersion Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageVersion Include="Blazorise" Version="1.5.2" />
<PackageVersion Include="Blazorise.Components" Version="1.5.2" />
<PackageVersion Include="Blazorise.DataGrid" Version="1.5.2" />
<PackageVersion Include="Blazorise.Snackbar" Version="1.5.2" />
<PackageVersion Include="Castle.Core" Version="5.1.1" />
<PackageVersion Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
<PackageVersion Include="CommonMark.NET" Version="0.15.1" />
<PackageVersion Include="Confluent.Kafka" Version="2.3.0" />
<PackageVersion Include="Dapper" Version="2.1.21" />
<PackageVersion Include="Dapr.AspNetCore" Version="1.12.0" />
<PackageVersion Include="Dapr.Client" Version="1.12.0" />
<PackageVersion Include="DeviceDetector.NET" Version="6.1.4" />
<PackageVersion Include="Devart.Data.Oracle.EFCore" Version="10.3.10.8" />
<PackageVersion Include="DistributedLock.Core" Version="1.0.5" />
<PackageVersion Include="DistributedLock.Redis" Version="1.0.2" />
<PackageVersion Include="DeepL.net" Version="1.8.0" />
<PackageVersion Include="EphemeralMongo.Core" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.linux-x64" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.osx-x64" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.win-x64" Version="1.1.3" />
<PackageVersion Include="FluentValidation" Version="11.8.0" />
<PackageVersion Include="Furion.Extras.Logging.Serilog" Version="4.9.5.17-beta.1" />
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.14" />
<PackageVersion Include="Hangfire.SqlServer" Version="1.8.14" />
<PackageVersion Include="HtmlSanitizer" Version="8.0.746" />
<PackageVersion Include="IdentityModel" Version="6.2.0" />
<PackageVersion Include="IdentityServer4" Version="4.1.2" />
<PackageVersion Include="IdentityServer4.AspNetIdentity" Version="4.1.2" />
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageVersion Include="LdapForNet" Version="2.7.15" />
<PackageVersion Include="LibGit2Sharp" Version="0.28.0" />
<PackageVersion Include="Magick.NET-Q16-AnyCPU" Version="13.4.0" />
<PackageVersion Include="MailKit" Version="4.7.1.1" />
<PackageVersion Include="Markdig.Signed" Version="0.37.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.25" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.4" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.5" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.5" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Composite" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.4" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="8.0.5" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="7.5.1" />
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="7.5.1" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.5.1" />
<PackageVersion Include="Minio" Version="6.0.2" />
<PackageVersion Include="MongoDB.Driver" Version="2.22.0" />
<PackageVersion Include="Moq" Version="4.20.70" />
<PackageVersion Include="NEST" Version="7.17.5" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Nito.AsyncEx.Context" Version="5.1.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
<PackageVersion Include="NuGet.Versioning" Version="6.7.0" />
<PackageVersion Include="NUglify" Version="1.21.0" />
<PackageVersion Include="Nullable" Version="1.3.1" />
<PackageVersion Include="Octokit" Version="9.0.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="5.5.0" />
<PackageVersion Include="OpenIddict.Core" Version="5.5.0" />
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="5.5.0" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="5.5.0" />
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="5.5.0" />
<PackageVersion Include="Oracle.EntityFrameworkCore" Version="8.23.40" />
<PackageVersion Include="Polly" Version="8.2.0" />
<PackageVersion Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<PackageVersion Include="Quartz" Version="3.7.0" />
<PackageVersion Include="Quartz.Extensions.DependencyInjection" Version="3.7.0" />
<PackageVersion Include="Quartz.Plugins.TimeZoneConverter" Version="3.7.0" />
<PackageVersion Include="Quartz.Serialization.Json" Version="3.7.0" />
<PackageVersion Include="RabbitMQ.Client" Version="6.6.0" />
<PackageVersion Include="Rebus" Version="8.4.2" />
<PackageVersion Include="Rebus.ServiceProvider" Version="10.1.2" />
<PackageVersion Include="Scriban" Version="5.9.0" />
<PackageVersion Include="Serilog" Version="3.1.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageVersion Include="Serilog.Enrichers.ClientInfo" Version="2.1.2" />
<PackageVersion Include="Serilog.Enrichers.Environment" Version="3.0.1" />
<PackageVersion Include="Serilog.Enrichers.Process" Version="3.0.0" />
<PackageVersion Include="Serilog.Enrichers.Sensitive" Version="1.7.3" />
<PackageVersion Include="Serilog.Enrichers.Thread" Version="4.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageVersion Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageVersion Include="Serilog.Sinks.Seq" Version="8.0.0" />
<PackageVersion Include="SerilogTracing" Version="1.1.0" />
<PackageVersion Include="SerilogTracing.Expressions" Version="1.1.0" />
<PackageVersion Include="SerilogTracing.Instrumentation.AspNetCore" Version="1.1.0" />
<PackageVersion Include="SerilogTracing.Instrumentation.SqlClient" Version="1.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Shouldly" Version="4.2.1" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.4" />
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="2.0.1" />
<PackageVersion Include="SkiaSharp" Version="2.88.6" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.6" />
<PackageVersion Include="SkiaSharp.NativeAssets.macOS" Version="2.88.6" />
<PackageVersion Include="Slugify.Core" Version="4.0.1" />
<PackageVersion Include="Spectre.Console" Version="0.47.0" />
<PackageVersion Include="SqlSugarCore" Version="5.1.4.169" />
<PackageVersion Include="StackExchange.Redis" Version="2.7.4" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
<PackageVersion Include="System.Linq.Dynamic.Core" Version="1.3.5" />
<PackageVersion Include="System.Linq.Queryable" Version="4.3.0" />
<PackageVersion Include="System.Runtime.Loader" Version="4.3.0" />
<PackageVersion Include="System.Security.Permissions" Version="8.0.0" />
<PackageVersion Include="System.Security.Principal.Windows" Version="5.0.0" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageVersion Include="System.Text.Encodings.Web" Version="8.0.0" />
<PackageVersion Include="System.Text.Json" Version="8.0.4" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1" />
<PackageVersion Include="TimeZoneConverter" Version="6.1.0" />
<PackageVersion Include="Unidecode.NET" Version="2.1.0" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="xunit.extensibility.execution" Version="2.9.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="ConfigureAwait.Fody" Version="3.3.2" />
<PackageVersion Include="Fody" Version="6.8.0" />
<PackageVersion Include="Senparc.CO2NET.AspNet" Version="1.5.0" />
<PackageVersion Include="Senparc.Weixin.Cache.Redis" Version="2.19.4" />
<PackageVersion Include="Senparc.Weixin.TenPay" Version="1.16.4" />
<PackageVersion Include="Senparc.Weixin.TenPayV3" Version="1.6.6" />
<PackageVersion Include="Senparc.Weixin.WxOpen" Version="3.21.2" />
<PackageVersion Include="Senparc.Weixin.AspNet" Version="1.4.7.1" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<PackageVersion Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageVersion Include="Furion" Version="4.9.5.16" />
<PackageVersion Include="Furion.Xunit" Version="4.9.5.16" />
<PackageVersion Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.5.16" />
<PackageVersion Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.5.16" />
<PackageVersion Include="Furion.Extras.DatabaseAccessor.SqlSugar" Version="4.9.5.16" />
<PackageVersion Include="Hinse.Cache" Version="1.2.0" />
<PackageVersion Include="Hinse.CapEventbus.MySqlAndRabbitMQ" Version="1.2.1" />
<PackageVersion Include="Hinse.Health" Version="1.3.4" />
<PackageVersion Include="Hinse.Util" Version="3.3.0" />
<PackageVersion Include="IPTools.China" Version="1.6.0" />
<PackageVersion Include="JetBrains.Annotations" Version="2024.2.0" />
<PackageVersion Include="Magicodes.IE.Excel" Version="2.7.5.1" />
<PackageVersion Include="MiniExcel" Version="1.34.0" />
<PackageVersion Include="NString" Version="2.1.1" />
<PackageVersion Include="Yitter.IdGenerator" Version="1.0.14" />
<PackageVersion Include="Z.EntityFramework.Extensions.Classic" Version="8.103.6.2" />
<PackageVersion Include="Z.EntityFramework.Classic" Version="7.2.22" />
<PackageVersion Include="Z.EntityFramework.Plus.EFCore" Version="8.103.1" />
<PackageVersion Include="Zack.EFCore.Batch.MySQL.Pomelo_NET7" Version="7.1.8" />
<PackageVersion Include="Scrutor" Version="4.2.2" />
<PackageVersion Include="EFCore.BulkExtensions" Version="8.1.2" />
<PackageVersion Include="DotNetCore.CAP" Version="8.2.0" />
<PackageVersion Include="DotNetCore.CAP.Dashboard" Version="8.2.0" />
<PackageVersion Include="DotNetCore.CAP.MySql" Version="8.2.0" />
<PackageVersion Include="DotNetCore.CAP.RabbitMQ" Version="8.2.0" />
<PackageVersion Include="DotNetCore.CAP.InMemoryStorage" Version="8.2.0" />
<PackageVersion Include="Savorboard.CAP.InMemoryMessageQueue" Version="8.2.1" />
<PackageVersion Include="Mapster.Async" Version="2.0.1" />
<PackageVersion Include="Mapster.DependencyInjection" Version="1.0.1" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Shouldly" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Furion.Xunit" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JT.Shop.Application\JT.Shop.Application.csproj" />
<ProjectReference Include="..\JT.Shop.Authorization\JT.Shop.Authorization.csproj" />
<ProjectReference Include="..\JT.Shop.EntityFramework.Core\JT.Shop.EntityFramework.Core.csproj" />
<ProjectReference Include="..\JT.Shop.QueryService.SqlSugar\JT.Shop.QueryService.SqlSugar.csproj" />
<PackageReference Include="DotNetCore.CAP.InMemoryStorage" />
<PackageReference Include="Savorboard.CAP.InMemoryMessageQueue" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,24 @@
using JT.Shop.Application.Service.Account;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Shouldly;
using JT.Shop.Domain.Entity.Business;
namespace JT.Shop.Application.UnitTests.Service.Account
{
public class AuthAccountIdentitiesQueryServiceTests(IServiceProvider serviceProvider) : TestBase(serviceProvider)
{
[Fact]
public async Task When_Get_Should_Be_Ok()
{
AuthAccountIdentitiesQueryService service = GetRequiredService<AuthAccountIdentitiesQueryService>();
var output = await service.Get(18336461348165);
output.Rows.ShouldNotBeEmpty();
//output.Shops.First().SystemAuthorization.ShouldNotBeNull();
//output.Shops.First().SystemAuthorization.Mode.ShouldBe(SystemAuthorizationMode.Normal);
}
}
}

View File

@ -0,0 +1,104 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.Business.Member;
using JT.Shop.Application.Service.ShopHead.Shop;
using JT.Shop.Core;
using JT.Shop.Domain;
using JT.Shop.Domain.Dtos;
using JT.Shop.Domain.StatisticsReport;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JT.Shop.Application.UnitTests.Service.Business.Member
{
public class MemberServiceTest : TestBase
{
[Fact]
public async Task PartList()
{
await MockCurrentShopUserInfoScope(async () =>
{
var output = await GetRequiredService<MemberService>().PartListAsync(new ShopHeadQueryMemberLoseWeightPartsInput() { ServeTimeRange = new DateRangeFilterInput() { Start = DateTime.Parse("2024-12-31"), End = DateTime.Parse("2025-01-07") } },
GetRequiredService<ILoseWeightPartsQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task AFKAllListAsync()
{
await MockCurrentShopUserInfoScope(async () =>
{
var output = await GetRequiredService<MemberService>().AFKAllListAsync(new BusinessMemberListWithLeaveWarningInput() { Time = DateTime.Parse("2025-01-07") });
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task ZhangChengWarningAsync()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<MemberService>().ZhangChengWarningAsync(new BusinessMemberListWithZhangChengWarningInput() { Day = 1 });
await GetRequiredService<MemberService>().ZhangChengWarningAsync(new BusinessMemberListWithZhangChengWarningInput() { Day = 2 });
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task AgainZhangChengWarningAsync()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<MemberService>().AgainZhangChengWarningAsync(new BusinessMemberListWithAgainZhangChengWarningInput() { StartVal = 1 });
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task SubscribeWarningAsync()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<MemberService>().SubscribeWarningAsync(new BusinessMemberListWithSubscribeInput() { });
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task SummarizeWarningAsync()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<MemberService>().SummarizeWarningAsync(new BusinessMemberListWithSummarizeWarningInput() { });
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task GetAllChildListWith3Plush1Lost()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<MemberService>().GetAllChildListWith3Plush1Lost(new BusinessMemberListWith3Plus1LostInput() { Time = DateTime.Parse("2025-01-07") });
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task TodayListAsync()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<MemberService>().TodayListAsync(new BusinessMemberTodayListInput() { });
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
}
}

View File

@ -0,0 +1,20 @@
// 品传科技
// 开发:李鹏鹏
// ------------------------------------------------------------------------
using JT.Shop.Domain;
using System;
using System.Threading.Tasks;
namespace JT.Shop.Application.UnitTests.Service.Shop;
public class DayCleanDomainServiceTest(DayCleanDomainService service) : TestBase
{
[Fact]
public async Task Test()
{
await service
.ExecuteAsync(new DateTime(2025, 1, 1), default);
}
}

View File

@ -0,0 +1,32 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.Mch.Conf;
using JT.Shop.Application.Service.Shop.Colleague;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JT.Shop.Application.UnitTests.Service.Shop
{
public class ShopRoleListQueryServiceTest(ShopRoleListQueryService service) : TestBase
{
[Fact]
public async Task Test()
{
await service.GetAccountList(new ShopRoleListQueryService.ShopRoleAccountListInput(){RoleId = 19043717587781 }, 18903188293189);
}
}
public class ShopSkinThemeQueryServiceTest(ShopSkinThemeQueryService service) : TestBase
{
[Fact]
public async Task Test()
{
await service.QueryByShopId( 18903188293189);
}
}
}

View File

@ -0,0 +1,118 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.ShopApi.Member;
using JT.Shop.Application.Service.ShopHead.Shop;
using JT.Shop.Core;
using JT.Shop.Domain;
using JT.Shop.Domain.Dtos;
using JT.Shop.Domain.Shared;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace JT.Shop.Application.UnitTests.Service.ShopApi.Member
{
public class MemberServiceTest(MemberService service) : TestBase
{
/* [Fact]
public async Task Add()
{
var num = new Random().Next();
await MockCurrentShopUserInfoScope(async () =>
{
await service.ApplyAsync(new MemberAddInput()
{
Name = $"名字{num}",
Phone = $"150{num}",
Career = RegUserCareerEnum.ComMag,
});
}, new CurrentShopUserInfoS2SDto { BusinessId = 19221331138885, ShopId = 19222606505285, Name = "单元测试" });
}*/
[Fact]
public async Task AllListAsync()
{
var num = new Random().Next();
await MockCurrentShopUserInfoScope(async () =>
{
await service.AllListAsync(new MemberAllListInput()
{
SortField = "increaseweight",
SortOrder = "asc",
PageNo = 1,
PageSize = 10,
SType = 0,
ServeEndValue = 0,
PType = 0,
DType = 0
});
}, new CurrentShopUserInfoS2SDto { BusinessId = 19221331138885, ShopId = 20097712614725, Name = "单元测试" });
}
[Fact]
public async Task RankListAsync()
{
var num = new Random().Next();
await MockCurrentShopUserInfoScope(async () =>
{
var output = await service.RankListAsync(new RankListC2SDto()
{
DateRange = ShopReportRankOfLoseWeightQueryServiceDateRange.Today
});
}, new CurrentShopUserInfoS2SDto { BusinessId = 1, ShopId = 19145601575493 });
}
[Fact]
public async Task GetAllChildList_When_Params_All_NULL()
{
var list = await GetRequiredService<IPcShopRegUserQueryService>().GetAllChildList(16547534871493, null, 18738520908613, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, /*null,*/ null, null, null, null, null, null, null, null, null, new PageInputV2Base { });
}
[Theory]
[InlineData(0, 1, RegUserProperType.CurrentMonthNewUser, RegUserGroupProp.User31, "shopentercnt")]
[InlineData(1, 2, RegUserProperType.NoSuccess, RegUserGroupProp.JZQZRDD, "clainweight")]
[InlineData(2, 3, RegUserProperType.Success, RegUserGroupProp.SHQZRDD, "increaseweight")]
[InlineData(2, 3, RegUserProperType.User31, RegUserGroupProp.JZQZRWD, "dealtime")]
[InlineData(0, 1, RegUserProperType.CurrentMonthNewUser, RegUserGroupProp.ZRDD, "")]
[InlineData(1, 2, RegUserProperType.NoSuccess, RegUserGroupProp.YGZ, "")]
[InlineData(2, 3, RegUserProperType.Success, RegUserGroupProp.YDJ, "")]
[InlineData(2, 3, RegUserProperType.User31, RegUserGroupProp.BYSR, "")]
public async Task GetAllChildList(int? SType, int? NoEntryDay, RegUserProperType? PType, RegUserGroupProp? GType,string SortName)
{
await GetRequiredService<IPcShopRegUserQueryService>().GetAllChildList(1, null, null, "null", "null", "null", RegUserCareerEnum.ComMag, SType, RegUserRegiType.ZD, RegUserStatusEnum.Enable, new DateRangeFilterInput() { Start = new DateTime(2024, 1, 1), End = new DateTime(2024, 2, 1) }, new DateRangeFilterInput() { Start = new DateTime(2024, 1, 1), End = new DateTime(2024, 2, 1) }, new DateRangeFilterInput() { Start = new DateTime(2024, 1, 1), End = new DateTime(2024, 2, 1) }, new DateRangeFilterInput() { Start = new DateTime(2024, 1, 1), End = new DateTime(2024, 2, 1) }, new DateRangeFilterInput() { Start = new DateTime(2024, 1, 1), End = new DateTime(2024, 2, 1) }, new DateRangeFilterInput() { Start = new DateTime(2024, 1, 1), End = new DateTime(2024, 2, 1) },
[RegUserTagEnum.JJQ, RegUserTagEnum.GGQ], [RegUserEnterTimeType.AfterNoon, RegUserEnterTimeType.Morning], NoEntryDay, PType, PType, /*WType,*/ GType, [0, 1, 2, 3, 4, 5, 6], [new NumberRangeFilterInput<int> { Min = null, Max = 1 }, new NumberRangeFilterInput<int> { Min = 10, Max = 100 }], [new NumberRangeFilterInput<decimal> { Min = 0, Max = 1 }, new NumberRangeFilterInput<decimal> { Min = 10, Max = 100 }], [new NumberRangeFilterInput<decimal> { Min = 0, Max = 1 }, new NumberRangeFilterInput<decimal> { Min = 10, Max = 100 }], null, ["1", "2"], [new NumberRangeFilterInput<int> { Min = 0, Max = 1 }, new NumberRangeFilterInput<int> { Min = 10, Max = 100 }], new PageInputV2Base {SortName = SortName });
}
[Fact]
public async Task GetAllChildTodayList_When_Params_All_NULL()
{
var list = await GetRequiredService<IPcShopRegUserQueryService>().GetAllChildTodayList(16547534871493, null, 18738520908613, null, null, null, null, null, null, null, null, null, null, null, null, null, new PageInputV2Base { });
}
[Theory]
[InlineData(1, RegUserProperType.CurrentMonthNewUser, RegUserGroupProp.User31, RegUserWeightProp.Increase, "shopentercnt")]
[InlineData(2, RegUserProperType.NoSuccess, RegUserGroupProp.JZQZRDD, RegUserWeightProp.Equ, "clainweight")]
[InlineData(3, RegUserProperType.Success, RegUserGroupProp.SHQZRDD, RegUserWeightProp.Reduce, "increaseweight")]
[InlineData(3, RegUserProperType.User31, RegUserGroupProp.JZQZRWD, RegUserWeightProp.Increase, "dealtime")]
[InlineData(1, RegUserProperType.CurrentMonthNewUser, RegUserGroupProp.ZRDD, RegUserWeightProp.Increase, "")]
[InlineData(2, RegUserProperType.NoSuccess, RegUserGroupProp.YGZ, RegUserWeightProp.Increase, "")]
[InlineData(3, RegUserProperType.Success, RegUserGroupProp.YDJ, RegUserWeightProp.Increase, "")]
[InlineData(3, RegUserProperType.User31, RegUserGroupProp.BYSR, RegUserWeightProp.Increase, "")]
public async Task GetAllChildTodayList(int? NoEntryDay, RegUserProperType? PType, RegUserGroupProp? GType, RegUserWeightProp weightProp, string SortName)
{
await GetRequiredService<IPcShopRegUserQueryService>().GetAllChildTodayList(1, null, null, "null", "null", "null", [RegUserSXProp.BuyAndNoUsed, RegUserSXProp.BuyAndUsed, RegUserSXProp.NotBuy], [RegUserEnterStatus.AFK, RegUserEnterStatus.Ban], new DateRangeFilterInput() { Start = new DateTime(2024, 1, 1), End = new DateTime(2024, 2, 1) }, new DateRangeFilterInput() { Start = new DateTime(2024, 1, 1), End = new DateTime(2024, 2, 1) }, [RegUserTagEnum.GGQ, RegUserTagEnum.SJQ], [RegUserEnterTimeType.AfterNoon, RegUserEnterTimeType.Morning], NoEntryDay, PType, weightProp, GType, new PageInputV2Base { SortName = SortName });
}
}
}

View File

@ -0,0 +1,105 @@
using JT.Shop.Application.Service.ShopApi.Report;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
using Shouldly;
using JT.Shop.Domain.Dtos;
using JT.Shop.Domain;
using JT.Shop.Application.Service.ShopApi.Report.Dto;
namespace JT.Shop.Application.UnitTests.Service.ShopApi.Report;
public class ReportServiceTests : TestBase
{
private readonly ReportService reportService;
public ReportServiceTests(ReportService reportService)
{
this.reportService = reportService;
}
[Fact]
public async Task When_ClerkServeList_Shoule_Be_Ok()
{
var list = await reportService.ClerkServeList(new Application.Service.ShopApi.Report.Dto.ClerkServeListC2SDto { PageNo = 1, PageSize = 10, StartTime = DateTime.Parse("2024/07/17"), EndTime = DateTime.Parse("2024/07/24"), ServeId = 17653240352453 },GetRequiredService<IShopAccountServeSummaryQueryService>());
//list.TotalPage.ShouldBeGreaterThan(0);
//list.PageSize.ShouldBe(10);
//list.PageNo.ShouldBe(1);
//list.TotalPage.ShouldBeGreaterThan(0);
//list.TotalRows.ShouldBeGreaterThan(0);
//list.Rows.ShouldNotBeEmpty();
//foreach (var row in list.Rows)
//{
// row.List.ShouldNotBeNull();
// row.List.ShouldNotBeEmpty();
//}
}
[Fact]
public async Task When_ClerkList_Shoule_Be_Ok()
{
await MockCurrentShopUserInfoScope(async () =>
{
var list = await reportService.ClerkList(new Application.Service.ShopApi.Report.Dto.ClerkListC2SDto { PageNo = 1, PageSize = 10, StartTime = DateTime.Parse("2024/12/30"), EndTime = DateTime.Parse("2025/01/06") },GetRequiredService<IShopAccountServeSummaryQueryService>());
//list.TotalPage.ShouldBeGreaterThan(0);
//list.PageSize.ShouldBe(10);
//list.PageNo.ShouldBe(1);
//list.TotalPage.ShouldBeGreaterThan(0);
//list.TotalRows.ShouldBeGreaterThan(0);
//list.Rows.ShouldNotBeEmpty();
//foreach (var row in list.Rows)
//{
// row.List.ShouldNotBeNull();
// row.List.ShouldNotBeEmpty();
// row.List.ShouldNotContain(x => x.Name == "减重");
//}
}, new CurrentShopUserInfoS2SDto { UserId = 17652841927877, ShopId = 19145601575493 });
}
[Fact]
public async Task When_FlowListAsync_Shoule_Be_Ok()
{
await MockCurrentShopUserInfoScope(async () =>
{
var list = await reportService.FlowListAsync(new FlowListC2SDto { PageNo = 1, PageSize = 10, Time = DateTime.Parse("2024/07/25") },GetRequiredService<IShopEveryDayWaterQueryService>(),GetRequiredService<IPcShopServiceResultQueryService>(),GetRequiredService<IPcShopAccountQueryService>(),GetRequiredService<IPcShopServiceQueryService>());
}, new CurrentShopUserInfoS2SDto { UserId = 17652841927877, ShopId = 17652841927877 });
}
[Fact]
public async Task When_PartListAsync_Shoule_Be_Ok()
{
await MockCurrentShopUserInfoScope(async () =>
{
var list = await reportService.PartListAsync(new PartListC2SDto { PageNo = 1, PageSize = 10, ServeStartTime = DateTime.Parse("2024/07/25"), ServeEndTime = DateTime.Parse("2024/07/25") },GetRequiredService<ILoseWeightPartsQueryService>());
}, new CurrentShopUserInfoS2SDto { UserId = 17652841927877, ShopId = 17652841927877 });
}
[Fact]
public async Task When_DayListAsync_Shoule_Be_Ok()
{
await MockCurrentShopUserInfoScope(async () =>
{
var list = await reportService.DayListAsync(new DayListC2SDto { PageNo = 1, PageSize = 10, StartTime = DateTime.Parse("2024/07/25"), EndTime = DateTime.Parse("2024/07/25") }, GetRequiredService<IShopEveryDayLoseWeightSummaryQueryService>());
}, new CurrentShopUserInfoS2SDto { UserId = 17652841927877, ShopId = 17652841927877 });
}
}

View File

@ -0,0 +1,38 @@
using Furion;
using System;
using System.Threading.Tasks;
using Furion.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http.Features;
using System.Security.Claims;
using JT.Shop.Domain.Shared;
using JT.Shop.Domain.Dtos;
namespace JT.Shop.Application.UnitTests.Service.ShopApi;
public class TestBase
{
public async Task MockCurrentShopUserInfoScope(Func<Task> handler, CurrentShopUserInfoS2SDto current)
{
await Scoped.CreateAsync(async (_, scope) =>
{
ClaimsIdentity identity = new("Authentication", ClaimTypes.Name, ClaimTypes.Role);
identity.AddClaim(new Claim(ClaimConst.CLAINM_ACCOUNT, current.UserId.ToString()));
identity.AddClaim(new Claim(ClaimConst.CLAINM_SHOP_ID, current.ShopId.ToString()));
identity.AddClaim(new Claim(ClaimConst.CLAINM_NAME, $"{current.Name}"));
identity.AddClaim(new Claim(ClaimConst.CLAINM_SHOP_HEAD_ID, current.BusinessId.ToString()));
ClaimsPrincipal principal = new();
principal.AddIdentity(identity);
App.GetRequiredService<TestHttpUserPrincipal>().SetUser(principal);
await handler();
});
}
protected T GetRequiredService<T>() where T : class
{
return App.GetRequiredService<T>();
}
}

View File

@ -0,0 +1,78 @@
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using JT.Shop.Application.Service.ShopHead.Finance;
using JT.Shop.Domain.Entity.DianShu;
using Microsoft.EntityFrameworkCore;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JT.Shop.Application.UnitTests.Service.ShopHead
{
public class DianShuAppServiceTest(IDbContextPool pool, DianShuSetPwdDomainService dianShuSetPwdDomainService, IRepository<PcDianShuOfHead> pcdianshuOfheadRepository) : TestBase
{
[Fact]
public async Task Test()
{
await dianShuSetPwdDomainService.SetPwd("654321", 1);
await pool.SavePoolNowAsync();
var entity = await pcdianshuOfheadRepository.FindOrDefaultAsync((long)1);
await GetRequiredService<DianShuVerifySafetyPasswordService>().Verify(entity, "654321");
//entity.VerifySafetyPassword("654321");
}
[Fact]
public async Task GetChildHeadInfo()
{
var entity = await GetRequiredService<ShopHeadDianShuQueryService>().GetChildHeadInfo(18889346190277, 1);
entity.Qty.ShouldBe(15);
entity.Id.ShouldBe(18889346190277);
}
[Fact]
public async Task GetChildShopInfo()
{
var entity = await GetRequiredService<ShopHeadDianShuQueryService>().GetChildShopInfo(18903604435141, 1);
entity.Id.ShouldBe(18903604435141);
}
[Fact]
public async Task GetInfo()
{
var entity = await GetRequiredService<ShopHeadDianShuQueryService>().GetInfo(18889346190277);
entity.Qty.ShouldBe(15);
entity.Id.ShouldBe(18889346190277);
}
[Fact]
public async Task GetWaterList()
{
var output = await GetRequiredService<ShopHeadDianShuQueryService>().GetWaterList(new ShopHeadDianShuQueryService.ShopHeadDianShuWaterListInput(), 1);
output.TotalRows.ShouldBeGreaterThan(0);
}
[Fact]
public async Task GetConsumeList()
{
var output = await GetRequiredService<ShopHeadDianShuQueryService>().GetConsumeList(new ShopHeadDianShuQueryService.ShopHeadDianShuConsumeListInput(), 1);
}
}
}

View File

@ -0,0 +1,30 @@
// 品传科技
// 开发:李鹏鹏
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.ShopHead;
using JT.Shop.Application.Service.ShopHead.ChildHead;
using JT.Shop.Domain.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JT.Shop.Application.UnitTests.Service.ShopHead
{
public class HeadSelfControllerTest:TestBase
{
[Fact]
public async Task MonthData()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<HeadSelfController>()
.SimpleInfo(1, GetRequiredService<ShopHeadListQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
}
}

View File

@ -0,0 +1,35 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.ShopHead.Shop;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JT.Shop.Application.UnitTests.Service.ShopHead
{
public class HeadShopListQueryServiceTest : TestBase
{
[Fact]
public async Task GetList()
{
var output = await GetRequiredService<HeadShopListQueryService>()
.GetList(new HeadShopListQueryService.HeadShopListInput(), 1);
output.TotalRows.ShouldBeGreaterThan(0);
}
[Fact]
public async Task GetAllChildList()
{
var output = await GetRequiredService<HeadShopListQueryService>()
.GetAllChildList(new HeadShopListQueryService.HeadShopAllChildListInput(), 1);
output.TotalRows.ShouldBeGreaterThan(0);
}
}
}

View File

@ -0,0 +1,183 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using Furion.DatabaseAccessor;
using JT.Shop.Application.Service.ShopHead.Shop;
using JT.Shop.Core;
using JT.Shop.Domain;
using JT.Shop.Domain.Dtos;
using JT.Shop.Domain.Entity.GeneralAccount;
using JT.Shop.Domain.Entity.ShopHead;
using JT.Shop.Domain.StatisticsReport;
using Microsoft.EntityFrameworkCore;
using System;
using System.Threading.Tasks;
namespace JT.Shop.Application.UnitTests.Service.ShopHead.Shop
{
public class ShopReportControllerTest : TestBase
{
[Fact]
public async Task MonthData()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<ShopsReportController>().MonthData(new ShopReportMonthDataQueryServiceInput() { Year = 2024, Month = 1 },
GetRequiredService<IShopReportMonthDataQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task TodayData()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<ShopsReportController>().TodayData(new ShopReportTodayDataQueryServiceInput() { },
GetRequiredService<IShopReportTodayDataQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task BatchData1()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<ShopsReportController>().BatchData1(
GetRequiredService<IShopReportTodayDataQueryService>(), GetRequiredService<IShopReportMonthDataQueryService>(), GetRequiredService<IShopReportShopDataQueryService>(), GetRequiredService<IPcShopHeadQueryService>(), GetRequiredService<IPcShopHeadAccountQueryService>(),GetRequiredService<GeneralAccountWxLoginBindDomainService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task ShopData()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<ShopsReportController>().ShopData(
GetRequiredService<IShopReportShopDataQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task MemberAnalysis()
{
await MockCurrentShopUserInfoScope(async () =>
{
var output = await GetRequiredService<ShopsReportController>().MemberAnalysis(new ShopReportMemberAnalysisQueryServiceInput { },
GetRequiredService<IShopReportMemberAnalysisQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task RankOfLoseWeight()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<ShopsReportController>().RankOfLoseWeight(new ShopReportRankOfLoseWeightQueryServiceInput { Date = new DateTime(2024, 1, 1) },
GetRequiredService<IShopReportRankOfLoseWeightQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task RankOfShopLoseWeight()
{
await MockCurrentShopUserInfoScope(async () =>
{
{
var output = await GetRequiredService<ShopsReportController>().RankOfShopLoseWeight(new ShopReportRankOfShopLoseWeightQueryServiceInput { DateRange = ShopReportRankOfShopLoseWeightQueryServiceDateRange.Today },
GetRequiredService<IShopReportRankOfShopLoseWeightQueryService>());
}
{
var output = await GetRequiredService<ShopsReportController>().RankOfShopLoseWeight(new ShopReportRankOfShopLoseWeightQueryServiceInput { DateRange = ShopReportRankOfShopLoseWeightQueryServiceDateRange.Month },
GetRequiredService<IShopReportRankOfShopLoseWeightQueryService>());
}
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task RankOfShopNewAddMember()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<ShopsReportController>().RankOfShopNewAddMember(new ShopReportRankOfShopNewAddMemberQueryServiceInput { DateRange = ShopReportRankOfShopNewAddMemberQueryServiceDateRange.Today },
GetRequiredService<IShopReportRankOfShopNewAddMemberQueryService>());
await GetRequiredService<ShopsReportController>().RankOfShopNewAddMember(new ShopReportRankOfShopNewAddMemberQueryServiceInput { DateRange = ShopReportRankOfShopNewAddMemberQueryServiceDateRange.Month },
GetRequiredService<IShopReportRankOfShopNewAddMemberQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task RankOfShopServicePositionSum()
{
await MockCurrentShopUserInfoScope(async () =>
{
await GetRequiredService<ShopsReportController>().RankOfShopServicePositionSum(new ShopReportRankOfShopServicePositionSumQueryServiceInput { DateRange = ShopReportRankOfShopServicePositionSumQueryServiceDateRange.Today },
GetRequiredService<IShopReportRankOfShopServicePositionSumQueryService>());
await GetRequiredService<ShopsReportController>().RankOfShopServicePositionSum(new ShopReportRankOfShopServicePositionSumQueryServiceInput { DateRange = ShopReportRankOfShopServicePositionSumQueryServiceDateRange.Month },
GetRequiredService<IShopReportRankOfShopServicePositionSumQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task ShopAccountServeSummary()
{
await MockCurrentShopUserInfoScope(async () =>
{
var output = await GetRequiredService<ShopsReportController>().ShopAccountServeSummary(new ShopHeadQueryShopAccountServeSummaryInput { CreateTimeRange = new DateRangeFilterInput(DateTime.Parse("2025/1/1"), DateTime.Parse("2025/1/5")) },
GetRequiredService<IShopAccountServeSummaryQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task ShopAccountServeDetail()
{
await MockCurrentShopUserInfoScope(async () =>
{
var output = await GetRequiredService<ShopsReportController>().ShopAccountServeDetail(new ShopHeadQueryShopAccountServeDetailInput
{
CreateTimeRange = new DateRangeFilterInput(DateTime.Parse("2025/01/04"), DateTime.Parse("2025/01/04")),
ServeId = 19397538102085,
UserId = 19145601575749
},
GetRequiredService<IShopAccountServeSummaryQueryService>());
}, new CurrentShopUserInfoS2SDto { BusinessId = 1 });
}
[Fact]
public async Task PCShopMonthReportCreateDomainService()
{
var shops = await GetRequiredService<IRepository<PC_Shop>>().DetachedEntities.ToListAsync();
var start = new DateTime(2024, 10, 1);
foreach (var shop in shops)
{
var index = -1;
while (index++ < 5)
{
await GetRequiredService<PCShopMonthReportCreateDomainService>()
.Create(shop.Id, start.AddMonths(index), shop.BusinessId);
}
}
}
}
}

View File

@ -0,0 +1,42 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.ShopHead.ChildHead;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JT.Shop.Application.UnitTests.Service.ShopHead
{
public class ShopHeadListQueryServiceTest : TestBase
{
[Fact]
public async Task GetList()
{
var output = await GetRequiredService<ShopHeadListQueryService>()
.GetList(new ShopHeadListQueryService.ShopHeadListInput(), 1);
output.TotalRows.ShouldBeGreaterThan(0);
}
[Fact]
public async Task GetAllChildList()
{
var output = await GetRequiredService<ShopHeadListQueryService>()
.GetAllChildList(new ShopHeadListQueryService.ShopHeadAllChildListInput(), 1);
output.TotalRows.ShouldBeGreaterThan(0);
}
[Fact]
public async Task GetDetail()
{
var output = await GetRequiredService<ShopHeadListQueryService>()
.GetDetail(19411154610245);
}
}
}

View File

@ -0,0 +1,31 @@
using JT.Shop.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JT.Shop.Application.Service.System.Business;
using Mapster;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using Shouldly;
using static JT.Shop.Application.Service.System.Business.SystemBusinessVersionOutputQueryService;
namespace JT.Shop.Application.UnitTests.Service.System.Business
{
public class SystemBusinessVersionOutputQueryServiceTest : TestBase
{
protected SystemBusinessVersionOutputQueryService queryService =>
GetRequiredService<SystemBusinessVersionOutputQueryService>();
[Fact]
public async Task GetList()
{
var output = await queryService.GetList(new SystemBusinessVersionListInput() { SortName = "1" });
output.SortNameErr.ShouldBeTrue();
}
[Fact]
public async Task GetDetail()
{
await queryService.GetDetail(1);
}
}
}

View File

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JT.Shop.Application.Service.System.DianShu;
using JT.Shop.Domain.Entity.DianShu;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using static JT.Shop.Application.Service.System.DianShu.DianShuRechargeTargetListOutputQueryService;
namespace JT.Shop.Application.UnitTests.Service.System.DianShu
{
public class DianShuRechargeOrderListOutputQueryServiceTest(IServiceProvider serviceProvider) : TestBase(serviceProvider)
{
[Fact]
public async Task Test()
{
var list = await serviceProvider.GetRequiredService<IPcDianShuQueryService>()
.GetByIdWithEntity(new HashSet<long>() { 1 });
list.ShouldNotBeEmpty();
list.Count().ShouldBe(1);
}
[Fact]
public async Task Test2()
{
var output = await GetRequiredService().GetOrderList(new DianShuRechargeOrderListOutputQueryService.DianShuRechargeListInput() { });
output.Rows.ShouldNotBeEmpty();
}
private DianShuRechargeOrderListOutputQueryService GetRequiredService()
{
return GetRequiredService<DianShuRechargeOrderListOutputQueryService>();
}
}
public class DianShuRechargeTargetListOutputQueryServiceTest(IServiceProvider serviceProvider) : TestBase(serviceProvider)
{
[Fact]
public async Task When_GetTargetList()
{
{
var output = await GetRequiredService<DianShuRechargeTargetListOutputQueryService>().GetTargetList(new DianShuRechargeTargetListInput() { });
output.Rows.ShouldNotBeEmpty();
}
{
var output = await GetRequiredService<DianShuRechargeTargetListOutputQueryService>().GetTargetList(new DianShuRechargeTargetListInput() { Search = "1"});
output.Rows.ShouldNotBeEmpty();
}
{
var output = await GetRequiredService<DianShuRechargeTargetListOutputQueryService>().GetTargetList(new DianShuRechargeTargetListInput() { Type =
[DianShuType.Head]
});
output.Rows.ShouldNotBeEmpty();
}
}
[Fact]
public async Task When_GetList()
{
var output = await GetRequiredService<DianShuRechargeTargetListOutputQueryService>().GetList(new DianShuRechargeTargetListInput() { });
output.Rows.ShouldNotBeEmpty();
}
[Fact]
public async Task When_GetList2()
{
var output = await GetRequiredService<DianShuRechargeTargetListOutputQueryService>().GetList(new DianShuRechargeTargetListInput() { Type = new HashSet<DianShuType>() { DianShuType.Shop, DianShuType.Head } });
output.Rows.ShouldNotBeEmpty();
}
[Fact]
public async Task When_GetList3()
{
var output = await GetRequiredService<DianShuRechargeTargetListOutputQueryService>().GetList(new DianShuRechargeTargetListInput() { Type = new HashSet<DianShuType>() { DianShuType.Shop, DianShuType.Head }, SortName = "h.Id" });
output.Rows.ShouldNotBeEmpty();
}
}
}

View File

@ -0,0 +1,45 @@
using Furion.DependencyInjection;
using JT.Shop.Domain.Dtos;
using JT.Shop.Domain.Shared;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Furion;
namespace JT.Shop.Application.UnitTests;
public class TestBase
{
public TestBase()
{
}
public TestBase(IServiceProvider serviceProvider)
{
}
public async Task MockCurrentShopUserInfoScope(Func<Task> handler, CurrentShopUserInfoS2SDto current)
{
await Scoped.CreateAsync(async (_, scope) =>
{
ClaimsIdentity identity = new("Authentication", ClaimTypes.Name, ClaimTypes.Role);
identity.AddClaim(new Claim(ClaimConst.CLAINM_ACCOUNT, current.UserId.ToString()));
identity.AddClaim(new Claim(ClaimConst.CLAINM_SHOP_ID, current.ShopId.ToString()));
identity.AddClaim(new Claim(ClaimConst.CLAINM_NAME, $"{current.Name}"));
identity.AddClaim(new Claim(ClaimConst.CLAINM_SHOP_HEAD_ID, current.BusinessId.ToString()));
//identity.AddClaim(new Claim(ClaimConst.CLAINM_OPENID, $"{current.OpenId}"));
ClaimsPrincipal principal = new();
principal.AddIdentity(identity);
scope.ServiceProvider.GetRequiredService<TestHttpUserPrincipal>().SetUser(principal);
await handler();
});
}
public T GetRequiredService<T>() where T : class
{
return App.GetRequiredService<T>();
}
}

View File

@ -0,0 +1,148 @@
using Furion;
using Furion.Xunit;
using Hinse.Health;
using JT.Shop.Authorization;
using JT.Shop.Core;
using JT.Shop.Domain;
using JT.Shop.Domain.Dtos;
using JT.Shop.EntityFramework.Core;
using JT.Shop.QueryService;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Savorboard.CAP.InMemoryMessageQueue;
using System;
using System.Reflection;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Autofac;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Modularity;
using Xunit.Abstractions;
using Yitter.IdGenerator;
[assembly: TestFramework("JT.Shop.Application.UnitTests.TestProgram", "JT.Shop.Application.UnitTests")]
namespace JT.Shop.Application.UnitTests;
public class TestProgram : TestStartup
{
public TestProgram(IMessageSink messageSink) : base(messageSink)
{
Serve.RunNative(GenericRunOptions.DefaultSilence.ConfigureBuilder((hostbuilder) =>
{
hostbuilder.UseAutofac();
hostbuilder.ConfigureServices(services =>
{
var application = services.AddApplication<ApplicationTestModule>(SetAbpApplicationCreationOptions);
var RootServiceProvider = CreateServiceProvider(services);
var TestServiceScope = RootServiceProvider.CreateScope();
application.Initialize(TestServiceScope.ServiceProvider);
services.AddCap(x =>
{
x.UseInMemoryStorage();
x.UseInMemoryMessageQueue();
});
services.AddSqlsugarSetup(App.Configuration);
//services.AddSingleton<IHttpUserPrincipal, TestHttpUserPrincipal>();
//services.AddSingleton<TestHttpUserPrincipal>();
services.AddTransient<ISmsService, MockSmsService>();
services.AddTransient<IPasswordErrorLimitService, MockPasswordErrorLimitService>();
});
return hostbuilder;
}));
}
protected virtual void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
}
protected virtual IServiceProvider CreateServiceProvider(IServiceCollection services)
{
return services.BuildServiceProviderFromFactory();
}
}
[Volo.Abp.Modularity.DependsOn(
typeof(AbpDataModule), typeof(AbpAutofacModule), typeof(ShopApplicationModule), typeof(ShopEntityFrameworkCoreModule), typeof(ShopAuthorizationModule),typeof(ShopQueryServiceSqlSugarModule)
//typeof(AbpSecurityModule),
//typeof(AbpSettingsModule),
//typeof(AbpEventBusAbstractionsModule),
//typeof(AbpMultiTenancyAbstractionsModule)
)]
public class ApplicationTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
base.ConfigureServices(context);
context.Services.AddObjectMapper(
Assembly.GetAssembly(typeof(ShopApplicationModule)),
Assembly.GetAssembly(typeof(ShopQueryServiceSqlSugarModule))
);
}
}
public class MockPasswordErrorLimitService : IPasswordErrorLimitService
{
public Task Add(string account, string category, int minutes)
{
return Task.CompletedTask;
}
public Task Check(string account, string category, int maxTimes, string errmsg)
{
return Task.CompletedTask;
}
public Task RemoveCheck(string account, string category)
{
return Task.CompletedTask;
}
}
public class MockSmsService : ISmsService
{
public bool CheckCodeAsync(string code, string phone, string intent, bool IsClear = true)
{
return true;
}
public void ClearVrCodeAsync(string phone, string intent)
{
}
public Task<string> SendAsync(string phone, string intent)
{
return Task.FromResult(string.Empty);
}
}
public class TestHttpUserPrincipal : IHttpUserPrincipal, ISingletonDependency
{
private ClaimsPrincipal _user;
public void SetUser(ClaimsPrincipal user)
{
_user = user;
}
public ClaimsPrincipal User =>_user;
}
public class TestCurrentSession : ICurrentSession, ISingletonDependency
{
public string SessionId { get; }
}

View File

@ -0,0 +1,24 @@
using System;
using Xunit.Abstractions;
namespace JT.Shop.Application.UnitTests
{
public class UnitTest1
{
private readonly ITestOutputHelper Output;
public UnitTest1(ITestOutputHelper output)
{
Output = output;
}
[Fact]
public void Test1()
{
var date = new DateTime(2025, 7, 5, 12, 0, 0);
Output.WriteLine(date.AddDays(60).ToString("yyyy/MM/dd HH:mm"));
Output.WriteLine(DateTime.Parse("2025/7/20 12:00").AddDays(30).ToString("yyyy/MM/dd HH:mm"));
Output.WriteLine(DateTime.Parse("2025/7/5 12:00").AddDays(20).ToString("yyyy/MM/dd HH:mm"));
}
}
}

View File

@ -0,0 +1,140 @@
{
"$schema": "https://gitee.com/dotnetchina/Furion/raw/net6/schemas/v3/furion-schema.json",
//
"ConnectionStrings": {
//"DefaultConnection": "Data Source=123.249.79.37;Database=jt_shop_v2_test;User ID=jt_shop_v2_test;Password=hPLAMfteswmyd63X;pooling=true;port=3306;sslmode=none;CharSet=utf8;AllowLoadLocalInfile=true;"
"DefaultConnection": "Data Source=127.0.0.1;Database=jt_shop_v2_1;User ID=admin;Password=000000;pooling=true;port=3306;sslmode=none;CharSet=utf8;AllowLoadLocalInfile=true;"
},
//rabbitmq
"RabbitmqSetting": {
//rabbitmq
"Enabled": "true",
"GroupName": "JT.Shop.queue",
"HostName": "localhost",
"Port": 5672,
"UserName": "liuzl",
"Password": "liuzl",
"DBConnection": "Data Source=127.0.0.1;Database=jt_shop_v2_1;User ID=admin;Password=000000;pooling=true;port=3306;sslmode=none;CharSet=utf8;AllowLoadLocalInfile=true;"
},
//swagger
"SpecificationDocumentSettings": {
"DocumentTitle": "接口平台",
"DocExpansionState": "List",
"RoutePrefix": "api",
"HideServers": true,
"LoginInfo": {
"Enabled": true,
"CheckUrl": "/Home/CheckUrl",
"SubmitUrl": "/Home/SubmitUrl",
"UserName": "admin",
"Password": "admin"
}
},
//swagger
"AppSettings": {
"InjectSpecificationDocument": true
},
//
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning",
"System.Net.Http.HttpClient": "Warning",
"DotNetCore.CAP": "Warning"
},
"File": {
"Enabled": false, //
"FileName": "logs/{0:yyyyMMdd}_{1}.log", //
"Append": true, //
// "MinimumLevel": "Information", //
"FileSizeLimitBytes": 10485760, // 10M=10*1024*1024
"MaxRollingFiles": 30 // 30
},
"Database": {
"Enabled": true, //
"MinimumLevel": "Information"
},
"Monitor": {
"GlobalEnabled": false, //
"IncludeOfMethods": [], // GlobalEnabled=false
"ExcludeOfMethods": [], // GlobalEnabled=true
"BahLogLevel": "Information", // Oops.Bah Oops.Bah
"WithReturnValue": true, // true
"ReturnValueThreshold": 500, // 0
"JsonBehavior": "None", // JsonNone(OnlyJsonAll)
"JsonIndented": false, // Json
"UseUtcTimestamp": false // UTCLOCAL
}
},
//
"Upload": {
"Path": "Upload", //
"MaxSize": 20480, // KB1024*20
"ContentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "video/mp4" ],
"EnableMd5": false // MDF5-
},
//
"DynamicApiControllerSettings": {
"KeepName": true,
"KeepVerb": false,
"LowercaseRoute": true,
"DefaultRoutePrefix": "api",
"UrlParameterization": true
},
//
"FriendlyExceptionSettings": {
//
"DefaultErrorMessage": "系统异常,请联系管理员",
"HideErrorCode": true //
},
//JWT
"JWTSettings": {
"ValidateIssuerSigningKey": true, // bool true
"IssuerSigningKey": "E99B4E28D590C0527076074E93D5E941", // string 16: null,JT.Shop
"ValidateIssuer": true, // bool true
"ValidIssuer": "JT.Shop", // string
"ValidateAudience": true, // bool true
"ValidAudience": "JT.ShopAdmin", // string
"ValidateLifetime": true, // bool truetrue
"ExpiredTime": 120, // long 20
"ClockSkew": 5 // long 5
},
//
"CorsAccessorSettings": {
"WithExposedHeaders": [
"access-token",
"x-access-token",
"Content-Disposition",
"environment"
]
},
//
"Cache": {
"CacheType": "Memory", // MemoryRedis
"RedisConnectionString": "server=127.0.0.1:6379;password=;db=2;", // Redis
"InstanceName": "PCKJ:EfCoreSingleAdmin:" //redis
},
//ID
"SnowId": {
"WorkerId": 1, //
"WorkerIdBitLength": 1, // 6 [1, 19]
"SeqBitLength": 6 // 6 [3, 21]4
},
//
"CustomSetting": {
//
"Version": "0.0.1", //
"CopyRight": "郑州巨天",
"PlatformName": "门店管理平台"
},
//
"ApiUrlSetting": {
"Api": "http://imd.pcxbc.com", //api
"Img": "http://imd.pcxbc.com", //
"File": "http://imd.pcxbc.com", //
"H5": "http://mdh5.pcxbc.com", //h5
"UserH5": "http://mduser.pcxbc.com", //h5
"UserResultH5": "http://mduser.pcxbc.com/#/pages/weight/weight" //h5
}
}

View File

@ -0,0 +1,40 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using System.Security.Claims;
namespace JT.Shop.Application
{
/// <summary>
/// 过期过滤器
/// </summary>
public class ExpireFilterAttribute : Attribute, IAsyncActionFilter
{
/// <summary>
/// 结果筛选器
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
//获取过期时间,可以存到token中,也可以直接从数据库中获取
var expiretime = context.HttpContext.User?.FindFirstValue("expiretime").ToDate();
var userid = context.HttpContext.User?.FindFirstValue(ClaimConst.CLAINM_ACCOUNT).ToLong();
//如果过期时间小于当前时间则禁止访问
if (expiretime < DateTime.Now)
{
context.Result = new ForbidResult();
return;
}
//数据库查询
await Scoped.CreateAsync(async (_, scope) =>
{
var services = scope.ServiceProvider;
var userRep = services.GetService<IRepository<SysUser>>();
var user = await userRep.DetachedEntities.Where(x => x.Id == userid).FirstOrDefaultAsync();
//判断是否过期
});
await next();
}
}
}

View File

@ -0,0 +1,18 @@
global using Furion;
global using Furion.DatabaseAccessor;
global using Furion.DependencyInjection;
global using Furion.DynamicApiController;
global using Furion.FriendlyException;
global using Hinse.Util;
global using JT.Shop.Application.Service;
global using JT.Shop.Core;
global using JT.Shop.Domain;
global using JT.Shop.Domain.Dtos;
global using JT.Shop.Domain.Shared;
//global using JT.Shop.EntityFramework.Core;
global using Mapster;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.EntityFrameworkCore;
global using Newtonsoft.Json;
global using System.ComponentModel.DataAnnotations;
global using Yitter.IdGenerator;

View File

@ -0,0 +1,69 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Service\Business\Retailer\**" />
<Compile Remove="Service\Mch\Account\Dto\**" />
<Compile Remove="Service\ShopHead\Agent\**" />
<Compile Remove="Service\System\Captcha\**" />
<Compile Remove="Service\System\CodeGen\**" />
<Compile Remove="Service\System\LowCode\**" />
<Compile Remove="Service\System\StepBody\**" />
<Compile Remove="Service\System\Timer\**" />
<Compile Remove="Service\System\Workflow\**" />
<EmbeddedResource Remove="Service\Business\Retailer\**" />
<EmbeddedResource Remove="Service\Mch\Account\Dto\**" />
<EmbeddedResource Remove="Service\ShopHead\Agent\**" />
<EmbeddedResource Remove="Service\System\Captcha\**" />
<EmbeddedResource Remove="Service\System\CodeGen\**" />
<EmbeddedResource Remove="Service\System\LowCode\**" />
<EmbeddedResource Remove="Service\System\StepBody\**" />
<EmbeddedResource Remove="Service\System\Timer\**" />
<EmbeddedResource Remove="Service\System\Workflow\**" />
<None Remove="Service\Business\Retailer\**" />
<None Remove="Service\Mch\Account\Dto\**" />
<None Remove="Service\ShopHead\Agent\**" />
<None Remove="Service\System\Captcha\**" />
<None Remove="Service\System\CodeGen\**" />
<None Remove="Service\System\LowCode\**" />
<None Remove="Service\System\StepBody\**" />
<None Remove="Service\System\Timer\**" />
<None Remove="Service\System\Workflow\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Service\Account\DianShuController.cs" />
<Compile Remove="Service\Account\DianShuRechargeController.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JT.Shop.Domain\JT.Shop.Domain.csproj" />
<ProjectReference Include="..\JT.Shop.WeiXin\JT.Shop.WeiXin.csproj" />
<ProjectReference Include="..\Volo.Abp.Authorization\Volo.Abp.Authorization.csproj" />
<ProjectReference Include="..\Volo.Abp.FeatureManagement.Application.Contracts\Volo.Abp.FeatureManagement.Application.Contracts.csproj" />
<ProjectReference Include="..\Volo.Abp.FeatureManagement.Domain\Volo.Abp.FeatureManagement.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Extensions\" />
<Folder Include="PermissionDefinitions\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,940 @@
/****************************************************************
* liuzl
* PCXBC
* 2022/10/9 15:26:03
*
*
* PC-2022
* :
*
*****************************************************************/
using JT.Shop.Application.Service.Business.BodyType;
using JT.Shop.Application.Service.Business.Clerk;
using JT.Shop.Application.Service.Business.Member;
using JT.Shop.Application.Service.Business.Org;
using JT.Shop.Application.Service.Business.Product;
using JT.Shop.Application.Service.Business.Serve;
using JT.Shop.Application.Service.Mch.Clerk;
using JT.Shop.Application.Service.Mch.Conf;
using JT.Shop.Application.Service.Mch.Member;
using JT.Shop.Application.Service.Mch.Product;
using JT.Shop.Application.Service.Mch.Serve;
using JT.Shop.Application.Service.ShopApi.Member.Dto;
using JT.Shop.Application.Service.ShopApi.Report.Dto;
using JT.Shop.Application.Service.ShopApi.Shop;
using JT.Shop.Application.Service.ShopApi.User;
using JT.Shop.Application.Service.ShopHead.Shop;
using JT.Shop.Application.Service.UserApi.Result;
using JT.Shop.Domain.Entity.Business;
using JT.Shop.Domain.Entity.DianShu;
using JT.Shop.Domain.Entity.GeneralAccount;
using JT.Shop.Domain.Entity.ShopHead;
using JT.Shop.Domain.StatisticsReport;
using static JT.Shop.Application.Service.Mch.Conf.ShopConfigController;
using static JT.Shop.Application.Service.Shop.Colleague.ShopAccountListQueryService;
using static JT.Shop.Application.Service.ShopHead.ChildHead.ShopHeadListQueryService;
using static JT.Shop.Application.Service.ShopHead.Colleague.AccountListQueryService;
using static JT.Shop.Application.Service.ShopHead.Shop.HeadShopListQueryService;
using static JT.Shop.Domain.Entity.ShopHead.IPcShopHeadQueryService;
using static JT.Shop.Domain.IPcShopServiceResultQueryService;
using static JT.Shop.Domain.IShopAccountServeSummaryQueryService;
namespace JT.Shop.Application.Mapper
{
/// <summary>
/// 自定义映射
/// </summary>
public class CustomMapper : IRegister
{
/// <summary>
/// 映射配置
/// </summary>
/// <param name="config"></param>
public void Register(TypeAdapterConfig config)
{
//公众号添加
config.ForType<WXSubmitC2SDto, PC_BusinessWX>()
.Map(dest => dest.Name, src => src.Name.ToStr())
.Map(dest => dest.AppId, src => src.AppId.ToStr())
.Map(dest => dest.AppSecret, src => src.AppSecret.ToStr())
.Map(dest => dest.Desc, src => src.Desc.ToStr())
;
//门店资料
config.ForType<PC_ShopAccount, ShopUserInfoS2CDto>()
.Map(dest => dest.Avatar, src => src.Avatar.HeadImg(src.Gender))
;
//门店机构树
config.ForType<PC_UserOrg, OrgTreeNode>()
.Map(dest => dest.ParentId, src => src.Pid)
.Map(dest => dest.Title, src => src.Name)
.Map(dest => dest.Value, src => src.Id)
.Map(dest => dest.Weight, src => src.Sort);
;
//添加门店机构
config.ForType<UserAddOrgC2SDto, PC_UserOrg>()
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
.Map(dest => dest.Status, src => CommonStatus.Enable)
;
//会员历史记录列表
config.ForType<PC_Result, ResultListS2CDto>()
.Map(dest => dest.createtime, src => src.RecordTime.GetFormatTime())
;
//成员趋势信息
config.ForType<PC_Result, ResultTrendS2CDto>()
.Map(dest => dest.time, src => src.RecordTime.GetFormatTime())
.Map(dest => dest.weight, src => src.Weight.KG2Jin())
.Map(dest => dest.RecordTime, src => src.RecordTime.Date)
;
config.ForType<ShopReportTodayDataQueryDto, ShopReportTodayDataQueryOutput>()
.Map(dest => dest.IncreaseUserWeight, src => src.IncreaseUserWeight.KG2Jin())
.Map(dest => dest.ReductUserWeight, src => src.ReductUserWeight.KG2Jin())
;
config.ForType<ShopReportMonthDataQueryDto, ShopReportMonthDataQueryOutput>()
.Map(dest => dest.ShopUserWeight, src => src.ShopUserWeight.KG2Jin())
.Map(dest => dest.ShopUserWeightAvg, src => src.ShopUserWeightAvg.KG2Jin())
;
//成员服务记录
config.ForType<PC_ShopServiceResult, RegUserServeListS2CDto>()
.Map(dest => dest.Time, src => src.CreatedTime.Value.Date)
;
//成员产品使用记录
config.ForType<PC_ShopRegUserProductResult, ShopRegUserProductListS2CDto>()
.Map(dest => dest.Time, src => src.CreatedTime.Value.Date)
;
//门店资料
config.ForType<PC_ShopAccount, LoginOutput>()
.Map(dest => dest.Account, src => src.Phone.PhoneSensitive())
.Map(dest => dest.Avatar, src => src.Avatar.HeadImg(src.Gender))
.Map(dest => dest.NickName, src => src.Name)
.Map(dest => dest.Name, src => src.Name)
.Map(dest => dest.Sex, src => src.Gender)
.Map(dest => dest.Email, src => string.Empty)
.Map(dest => dest.Phone, src => src.Phone.PhoneSensitive())
.Map(dest => dest.Tel, src => string.Empty)
.Map(dest => dest.AdminType, src => 3)
;
//门店服务信息提交
config.ForType<MchSubmitServeInput, PC_ShopService>()
//.Map(dest => dest.Code, src => string.Empty)
//.Map(dest => dest.Status, src => GoodsStatus.WAIT)
//.Map(dest => dest.CreatedTime, src => DateTime.Now)
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
;
//门店服务信息提交
config.ForType<MchSubmitServeInput, PC_BusinessShopService>()
.Map(dest => dest.Code, src => string.Empty)
.Map(dest => dest.Status, src => GoodsStatus.WAIT)
.Map(dest => dest.CreatedTime, src => DateTime.Now)
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
;
//门店店员列表
config.ForType<PC_ShopAccount, MchClerkListOutput>()
.Map(dest => dest.AvatarUrl, src => src.Avatar.HeadImg(src.Gender))
.Map(dest => dest.BirthDay, src => src.BirthDay.GetFormatTime1())
;
//门店店员列表
config.ForType<PcShopAccountDto, BusinessClerkListItemOutput>()
.Map(dest => dest.AvatarUrl, src => src.Avatar.HeadImg(src.Sex))
.Map(dest => dest.BirthDay, src => src.BirthDay.GetFormatTime1())
.Map(dest => dest.Mobile, src => src.Mobile.PhoneSensitive())
;
//门店店员列表
config.ForType<PcShopAccountDto, ShopAccountListOutputItem>()
.Map(dest => dest.AvatarUrl, src => src.Avatar.HeadImg(src.Sex))
.Map(dest => dest.BirthDay, src => src.BirthDay.GetFormatTime1())
.Map(dest => dest.Mobile, src => src.Mobile.PhoneSensitive())
//.Map(dest => dest.Phone, src => src.Phone.PhoneSensitive())
;
config.ForType<PcShopHeadAccountDto, LoginAccountInfoBaseOutput>()
.Map(dest => dest.Avatar, src => string.Empty.HeadImg(src.Sex))
.Map(dest => dest.Mobile, src => src.Mobile.PhoneSensitive())
.Map(dest => dest.WxBind, src => MapContext.Current.Parameters["wxbind"])
//.Map(dest => dest.Phone, src => src.Phone.PhoneSensitive())
;
//门店职位修改
config.ForType<MchSubmitPosInput, PC_ShopPos>()
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
.Map(dest => dest.Status, src => CommonStatus.Enable)
.Map(dest => dest.CreatedTime, src => DateTime.Now)
.Map(dest => dest.Id, src => src.Id.IsEmpty() ? YitIdHelper.NextId() : src.Id)
;
//门店会员列表
config.ForType<PC_ShopRegUser, MchMemberListOutput>()
.Map(dest => dest.AvatarUrl, src => src.Avatar.HeadImg(src.Gender))
.Map(dest => dest.BirthDay, src => src.BirthDay.GetFormatTime1())
.Map(dest => dest.Phone, src => src.Phone.PhoneSensitive())
;
//门店会员列表
config.ForType<PC_ShopRegUser, BusinessMemberListOutputItem>()
.Map(dest => dest.AvatarUrl, src => src.Avatar.HeadImg(src.Gender))
.Map(dest => dest.BirthDay, src => src.BirthDay.GetFormatTime1())
.Map(dest => dest.Phone, src => src.Phone.PhoneSensitive())
;
//产品信息提交
config.ForType<BusinessSubmitProductInput, PC_ShopProduct>()
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
;
//产品信息提交
config.ForType<MchSubmitProductInput, PC_BusinessShopProduct>()
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
;
//昨日涨秤会员列表
config.ForType<PC_ShopRegUserDayReport, YesterdayZCListOutput>()
.Map(dest => dest.ChainWeight, src => src.ChainWeight.KG2Jin())
;
//门店配置
config.ForType<PC_ShopSetting, ConfInfoS2CDto>()
.Map(dest => dest.LogoUrl, src => src.Logo.ImgFile())
;
config.ForType<ShopSkinThemeQueryService.SkinTheme, ConfInfoS2CDto>()
.Map(dest => dest.LogoUrl, src => src.Logo.ImgFile())
;
//门店配置
config.ForType<PC_ShopSetting, ShopConfInfoS2CDto>()
.Map(dest => dest.Logo, src => src.Logo.ImgFile(), src => !string.IsNullOrWhiteSpace(src.Logo))
.Map(dest => dest.VLogo, src => src.Logo, src => !string.IsNullOrWhiteSpace(src.Logo))
.Map(dest => dest.Color, src => src.Color, src => !string.IsNullOrWhiteSpace(src.Color))
.Map(dest => dest.FontColor, src => src.FontColor, src => !string.IsNullOrWhiteSpace(src.FontColor))
;
config.ForType<ShopSkinThemeQueryService.SkinTheme, ShopConfInfoS2CDto>()
.Map(dest => dest.Logo, src => src.Logo.ImgFile())
.Map(dest => dest.VLogo, src => src.Logo)
.Map(dest => dest.Color, src => src.Color)
.Map(dest => dest.FontColor, src => src.FontColor)
;
config.ForType<PC_Shop, ShopConfigOutput>()
.Map(dest => dest.AvatarUrl, src => src.Avatar.ImgFile())
;
//身体部位类型信息提交
config.ForType<SubmitBodyTypeInput, PC_ShopBodyType>()
.Map(dest => dest.Description, src => src.Description.ToStrNoEmpty())
.Map(dest => dest.Image, src => src.Image.ToStrNoEmpty())
.Map(dest => dest.Status, src => CommonStatus.Disable)
;
//身体部位信息提交
config.ForType<SubmitBodyInput, PC_ShopBody>()
.Map(dest => dest.Description, src => src.Description.ToStrNoEmpty())
.Map(dest => dest.Image, src => src.Image.ToStrNoEmpty())
.Map(dest => dest.Status, src => CommonStatus.Disable)
;
//门店资料
config.ForType<PcGeneralAccount, LoginOutput>()
.Map(dest => dest.Account, src => src.Mobile.PhoneSensitive())
.Map(dest => dest.Avatar, src => string.Empty.HeadImg(Gender.MALE))
//.Map(dest => dest.NickName, src => src.Name)
//.Map(dest => dest.Name, src => src.Name)
//.Map(dest => dest.Sex, src => src.Gender)
.Map(dest => dest.Email, src => string.Empty)
.Map(dest => dest.Phone, src => src.Mobile.PhoneSensitive())
.Map(dest => dest.Tel, src => string.Empty)
.Map(dest => dest.AdminType, src => 3)
;
config.ForType<SystemAuthorization, SystemAuthorizationOutput>()
.Map(dest => dest.ExpireStatus, src => src.ExpireStatus())
;
config.ForType<PcShopHeadAccountDto, AccountListOutputItem>()
.Map(dest => dest.Mobile, src => src.Mobile.PhoneSensitive())
;
config.ForType<PcShopHeadAccountDto, AllChildAccountListOutputItem>()
.Map(dest => dest.Mobile, src => src.Mobile.PhoneSensitive())
;
config.ForType<PC_Shop, AppBaseInfoOutput>()
.Map(dest => dest.Code, src => src.ShopCode)
.Map(dest => dest.HeadId, src => src.BusinessId)
;
config.NewConfig<ShopReportRankOfLoseWeightQueryDto, ShopReportRankOfLoseWeightQueryOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var regUserRep = MapContext.Current.GetService<IRepository<PC_ShopRegUser>>();
var userids = poco.Rows.Select(x => x.RegUserId).ToHashSet();
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var users = (await regUserRep.DetachedEntities.Where(x => userids.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
foreach (var row in dto.Rows)
{
if (users.TryGetValue(row.RegUserId, out var user))
{
row.RegUserName = user.Name;
row.Avatar = user.Avatar.HeadImg(user.Gender);
row.Gender = user.Gender;
}
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
}
}
});
config.NewConfig<ShopReportRankOfShopLoseWeightQueryDto, ShopReportRankOfShopLoseWeightQueryOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
foreach (var row in dto.Rows)
{
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
}
}
});
config.NewConfig<ShopReportRankOfShopNewAddMemberQueryDto, ShopReportRankOfShopNewAddMemberQueryOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
foreach (var row in dto.Rows)
{
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
}
}
});
config.NewConfig<ShopReportRankOfShopServicePositionSumQueryDto, ShopReportRankOfShopServicePositionSumQueryOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var shopRep = MapContext.Current.GetService<IRepository<PC_ShopBody>>();
var shopids = poco.Rows.Select(x => x.BodyId).ToHashSet();
var shops = (await shopRep.DetachedEntities.Where(x => shopids.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
foreach (var row in dto.Rows)
{
if (shops.TryGetValue(row.BodyId, out var shop))
{
row.BodyName = shop.Name;
}
}
});
config.NewConfig<ShopHeadListDto, ShopHeadListOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var ids = poco.Rows.Select(x => x.Id).ToHashSet();
var versionService = MapContext.Current.GetService<ISystemBusinessVersionQueryService>();
var versionIds = poco.Rows.Select(x => x.SystemAuthorization.ConfigId).ToHashSet();
var versions = await versionService.GetDetail(versionIds);
var dianshuConsumeQueryServiceService = MapContext.Current.GetService<IPcDianshuConsumeQueryService>();
var dianshuConsumes = await dianshuConsumeQueryServiceService.QuerySumOfDianshu(ids);
var shopReportQueryServiceService = MapContext.Current.GetService<IShopReportShopDataQueryService>();
var shopCounts = await shopReportQueryServiceService.QueryShopCount(ids);
foreach (var row in dto.Rows)
{
if (versions.TryGetValue(row.SystemAuthorization.ConfigId, out var version))
{
row.SystemAuthorization.BusinessVersion = version.Adapt<BusinessVersionOutput>();
}
if (dianshuConsumes.TryGetValue(row.Id, out var dianshuConsume))
{
row.ConsumeDianShu = dianshuConsume;
}
if (shopCounts.TryGetValue(row.Id, out var shopCount))
{
row.ShopCount = shopCount;
}
}
});
config.NewConfig<IPcHeadShopQueryService.HeadShopListDto, HeadShopListOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var ids = poco.Rows.Select(x => x.Id).ToHashSet();
var versionService = MapContext.Current.GetService<ISystemBusinessVersionQueryService>();
var versionIds = poco.Rows.Select(x => x.SystemAuthorization.ConfigId).ToHashSet();
var versions = await versionService.GetDetail(versionIds);
var dianshuConsumeQueryServiceService = MapContext.Current.GetService<IPcDeviceQueryService>();
var dianshuConsumes = await dianshuConsumeQueryServiceService.QueryDeviceCount(ids);
var shopReportQueryServiceService = MapContext.Current.GetService<IPcShopRegUserQueryService>();
var shopCounts = await shopReportQueryServiceService.QueryMemberCount(ids);
foreach (var row in dto.Rows)
{
if (versions.TryGetValue(row.SystemAuthorization.ConfigId, out var version))
{
row.SystemAuthorization.BusinessVersion = version.Adapt<BusinessVersionOutput>();
}
if (dianshuConsumes.TryGetValue(row.Id, out var dianshuConsume))
{
row.DeviceCount = dianshuConsume;
}
if (shopCounts.TryGetValue(row.Id, out var shopCount))
{
row.MemberCount = shopCount;
}
}
});
config.NewConfig<PcShopRegUserAllChildListItemDto, BusinessMemberListOutputItem>()
.Map(dest => dest.LastWeight, src => src.LastWeight.KG2Jin())
.Map(dest => dest.FirstWeight, src => src.FirstWeight.KG2Jin())
.Map(dest => dest.StandWeight, src => src.StandWeight.KG2Jin())
.Map(dest => dest.TodayWeight, src => src.LastEntryTime.HasValue && src.LastEntryTime.Value.Date == DateTime.Now.Date ? src.LastWeight.KG2Jin() : 0)
.Map(dest => dest.IncreaseWeight, src => src.IncreaseWeight.KG2Jin())
.Map(dest => dest.UnIncreaseWeight, src => src.UnIncreaseWeight.KG2JinNoZero())
.Map(dest => dest.DealTime, src => src.DealTime.GetFormatTime(false))
.Map(dest => dest.LastEntryTime, src => src.LastEntryTime.ToYearDateTimeFromOffset())
.Map(dest => dest.ChainWeight, src => src.ChainWeight > 0 ? $"+{src.ChainWeight.KG2Jin()}" : $"{src.ChainWeight.KG2Jin()}")
.Map(dest => dest.ExpectTime, src => src.LastEntryTime.GetHourTime())
;
config.NewConfig<PcShopRegUserAllChildListDto, BusinessMemberListOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var ids = poco.Rows.Select(x => x.Id).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
var allsubscribe = await MapContext.Current.GetService<IRepository<PC_ShopRegUserSubscribe>>().DetachedEntities.Where(x => ids.Contains(x.RegUserId) && x.Status == RegUserSubscribeEnum.Subscribe).Select(x => new PC_ShopRegUserSubscribe
{
RegUserId = x.RegUserId
}).ToListAsync();
var thisMonday = DateTime.Now.GetMondayDate();
var allrank = await MapContext.Current.GetService<IRepository<PC_ShopRegUserRank>>().DetachedEntities.Where(x => ids.Contains(x.RegUserId) && x.Date == thisMonday && x.RankType == ShopRegUserRankType.Week).Select(x => new PC_ShopRegUserRank
{
RegUserId = x.RegUserId
}).ToListAsync();
foreach (var row in dto.Rows)
{
row.IsFollower = allsubscribe.Any(x => x.RegUserId == row.Id);
row.IsRank = allrank.Any(x => x.RegUserId == row.Id);
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
}
});
config.NewConfig<LoseWeightPartsQueryServiceItemDto, WeightListS2CDto>()
.Map(dest => dest.RealReduceWeight, src => src.RealReduceWeight.KG2Jin())
.Map(dest => dest.TotalReduceWeight, src => src.TotalReduceWeight.KG2Jin())
.Map(dest => dest.FirstWeight, src => src.FirstWeight.KG2Jin())
.Map(dest => dest.StandWeight, src => src.StandWeight.KG2Jin())
.Map(dest => dest.NoWeight, src => src.UnIncreaseWeight.KG2Jin())
.Map(dest => dest.ShouldWeight, src => (src.FirstWeight - src.StandWeight).KG2Jin())
.Map(dest => dest.EnterCnt, src => src.ShopEnterCnt)
.Map(dest => dest.DealTime, src => src.DealTime.GetFormatTime())
.Map(dest => dest.EnterTime, src => src.EnterTime.GetFormatTime())
;
config.NewConfig<LoseWeightPartsQueryServiceDto, ShopHeadQueryMemberLoseWeightPartsOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
//IShopRegUserEnterReportQueryService
var ids = poco.Rows.Select(x => x.RegUserId).ToHashSet();
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var regUserRep = MapContext.Current.GetService<IRepository<PC_ShopRegUser>>();
var users = (await regUserRep.DetachedEntities.Where(x => ids.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
var prevParts = (await MapContext.Current.GetService<ILoseWeightPartsQueryService>().QueryPrevPart(ids, MapContext.Current.Parameters["PrevServeTime"] as DateRangeFilterInput));
var sxOrders = await MapContext.Current.GetService<IShopRegUserSXOrderQueryService>()
.QueryRegUserLastCycleOrder(ids, OrderStatusEnum.Run);
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
foreach (var row in dto.Rows)
{
if (users.TryGetValue(row.RegUserId, out var user))
{
row.Name = user.Name;
row.Avatar = user.Avatar.HeadImg(user.Gender);
row.Phone = user.Phone.PhoneSensitive();
}
if (sxOrders.TryGetValue(row.RegUserId, out var sxOrder))
{
row.CycleValue = sxOrder.CycleValue;
}
if (prevParts.TryGetValue(row.RegUserId, out var prevPart))
{
row.LastData = new LastWeightListS2CDto
{
EnterCnt = prevPart.ShopEnterCnt,
LastWeight = prevPart.LastWeight.KG2Jin(),
RealReduceWeight = prevPart.RealReduceWeight.KG2Jin(),
TotalReduceWeight = prevPart.TotalReduceWeight.KG2Jin()
};
}
else row.LastData = new LastWeightListS2CDto();
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
}
});
config.NewConfig<ShopEveryDayWaterQueryServiceDto, ShopHeadQueryShopEveryDayWatersOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
//IShopRegUserEnterReportQueryService
var ids = poco.Rows.Select(x => x.RegUserId).ToHashSet();
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var regUserRep = MapContext.Current.GetService<IRepository<PC_ShopRegUser>>();
// var users = (await regUserRep.DetachedEntities.Where(x => ids.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
var sxOrders = await MapContext.Current.GetService<IShopRegUserSXOrderQueryService>()
.QueryRegUserLastCycleOrder(ids, OrderStatusEnum.Run);
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
foreach (var row in dto.Rows)
{
/* if (users.TryGetValue(row.RegUserId, out var user))
{
row.Name = user.Name;
row.Avatar = user.Avatar.HeadImg(user.Gender);
row.Phone = user.Phone.PhoneSensitive();
}*/
row.RTypeDescription = CommonService.GetDescription(row.RType);
if (row.LastWeight == 0 || row.TodayWeight == 0)
{
row.ValueType = "首次称重";
}
else
{
row.ValueType = row.Value > 0 ? "涨秤" : (row.Value < 0 ? "掉秤" : "平秤");
}
//row.Value = Math.Abs(row.Value);
if (sxOrders.TryGetValue(row.RegUserId, out var sxOrder))
{
row.ServeStartTime = sxOrder.StartTime.GetFormatTime();
}
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
}
dto.Value = dto.Value.KG2Jin();
dto.TotalIncrease = dto.TotalIncrease.KG2Jin();
dto.TotalReduce = dto.TotalReduce.KG2Jin();
});
config.NewConfig<PcShopServiceResultAllChildListDto, BusinessServeResultListOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
//IShopRegUserEnterReportQueryService
var ids = poco.Rows.Select(x => x.RegUserId).ToHashSet();
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var shopAccountUserIds = poco.Rows.Select(x => x.UserId).ToHashSet();
var serveIds = poco.Rows.Select(x => x.ServeId).ToHashSet();
var regUserRep = MapContext.Current.GetService<IRepository<PC_ShopRegUser>>();
var users = (await regUserRep.DetachedEntities.Where(x => ids.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
var shopAccounts = await MapContext.Current.GetService<IPcShopAccountQueryService>().Get(shopAccountUserIds);
var serves = await MapContext.Current.GetService<IPcShopServiceQueryService>()
.Get(serveIds);
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
var products = await MapContext.Current.GetService<IPcShopProductQueryService>().Get(poco.Rows.Select(x => x.ProductId).ToHashSet());
foreach (var row in dto.Rows)
{
if (users.TryGetValue(row.RegUserId, out var user))
{
row.RegUserName = user.Name;
//row.Avatar = user.Avatar.HeadImg(user.Gender);
//row.Phone = user.Phone.PhoneSensitive();
}
if (shopAccounts.TryGetValue(row.UserId, out var shopAccount))
{
row.UserName = shopAccount.Name;
//row.Avatar = shopAccount.Avatar.HeadImg(shopAccount.Sex);
}
if (serves.TryGetValue(row.ServeId, out var serve))
{
row.ServeName = serve.Name;
}
if (products.TryGetValue(row.ProductId, out var product))
{
row.ProductName = product.Name;
}
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
}
});
config.NewConfig<IShopEveryDayLoseWeightSummaryQueryService.ShopEveryDayLoseWeightSummaryQueryDto, ShopEveryDayLoseWeightSummaryQueryOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
//IShopRegUserEnterReportQueryService
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
foreach (var row in dto.Rows)
{
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
}
});
config.NewConfig<Domain.IShopAccountServeSummaryQueryService.ShopShopAccountServeSummaryQueryDto, ShopShopAccountServeSummaryQueryOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
//IShopRegUserEnterReportQueryService
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
var shopAccountUserIds = poco.Rows.Select(x => x.UserId).ToHashSet();
var shopAccounts = await MapContext.Current.GetService<IPcShopAccountQueryService>().Get(shopAccountUserIds);
foreach (var row in dto.Rows)
{
if (shopAccounts.TryGetValue(row.UserId, out var shopAccount))
{
row.Name = shopAccount.Name;
row.Avatar = shopAccount.Avatar.HeadImg(shopAccount.Sex);
//row.Phone = user.Phone.PhoneSensitive();
}
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
//减重服务次数=总次数-【精护部位服务(非减重服务)次数】
row.ServeCnt = row.ServeCnt - row.SXBodypartsNum;
}
});
config.NewConfig<ShopShopAccountServeDetailQueryDto, ShopShopAccountServeDetailQueryOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
//IShopRegUserEnterReportQueryService
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var serveIds = poco.Rows.Select(x => x.ServeId).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
var shopAccountUserIds = poco.Rows.Select(x => x.UserId).ToHashSet();
var shopAccounts = await MapContext.Current.GetService<IPcShopAccountQueryService>().Get(shopAccountUserIds);
var serves = await MapContext.Current.GetService<IPcShopServiceQueryService>()
.Get(serveIds);
var regUserIds = poco.Rows.Select(x => x.List.Select(y => y.RegUserId)).SelectMany(x => x).ToHashSet();
var users = await MapContext.Current.GetService<IPcShopRegUserQueryService>().Get(regUserIds);
var regProductIds = poco.Rows.Select(x => x.List.Select(y => y.ProductId)).SelectMany(x => x).ToHashSet();
var shopProducts = (await MapContext.Current.GetService<IRepository<PC_ShopProduct>>().DetachedEntities.Where(x => regProductIds.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
foreach (var row in dto.Rows)
{
if (shopAccounts.TryGetValue(row.UserId, out var shopAccount))
{
row.Name = shopAccount.Name;
row.Avatar = shopAccount.Avatar.HeadImg(shopAccount.Sex);
//row.Phone = user.Phone.PhoneSensitive();
}
if (serves.TryGetValue(row.ServeId, out var serve))
{
row.ServeName = serve.Name;
row.ComputeTimes = serve.ComputeTimes;
}
foreach (var item in row.List)
{
if (users.TryGetValue(item.RegUserId, out var user))
{
item.Name = user.Name;
item.Avatar = user.Avatar.HeadImg(user.Gender);
item.Phone = user.Phone.PhoneSensitive();
}
if (shopProducts.TryGetValue(item.ProductId, out var product))
{
item.ProductName = product.Name;
}
}
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
}
});
config.NewConfig<IPcRegUserWarningQueryService.PcShopRegUserLeaveAllChildListDto, BusinessMemberListWithLeaveWarningOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var memberids = poco.Rows.Select(x => x.RegUserId).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
var regUserRep = MapContext.Current.GetService<IRepository<PC_ShopRegUser>>();
var users = (await regUserRep.DetachedEntities.Where(x => memberids.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
foreach (var row in dto.Rows)
{
row.Day = row.EndTime.GetDays(row.StartTime, true);
if (users.TryGetValue(row.RegUserId, out var user))
{
row.Name = user.Name;
row.Avatar = user.Avatar.HeadImg(user.Gender);
//row.Gender = user.Gender;
}
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
}
});
config.NewConfig<IPcRegUserWarningQueryService.ZhangChengWarningQueryServiceDto, BusinessMemberListWithZhangChengWarningOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var memberids = poco.Rows.Select(x => x.RegUserId).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
var regUserRep = MapContext.Current.GetService<IRepository<PC_ShopRegUser>>();
var users = (await regUserRep.DetachedEntities.Where(x => memberids.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
var userDatas = (await MapContext.Current.GetService<IRepository<PC_ShopRegUserData>>().DetachedEntities.Where(x => memberids.Contains(x.RegUserId)).ToListAsync()).ToDictionary(x => x.RegUserId, x => x);
foreach (var row in dto.Rows)
{
row.ChainWeight = row.ChainWeight.KG2Jin();
if (userDatas.TryGetValue(row.RegUserId, out var userData))
{
row.RType = userData.RType;
}
if (users.TryGetValue(row.RegUserId, out var user))
{
row.Name = user.Name;
row.Avatar = user.Avatar.HeadImg(user.Gender);
//row.Gender = user.Gender;
}
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
}
});
config.NewConfig<IPcRegUserWarningQueryService.AgainZhangChengWarningQueryServiceDto, BusinessMemberListWithAgainZhangChengWarningOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var memberids = poco.Rows.Select(x => x.RegUserId).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
var regUserRep = MapContext.Current.GetService<IRepository<PC_ShopRegUser>>();
var users = (await regUserRep.DetachedEntities.Where(x => memberids.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
dto.Rows?.ForEach((row, index) =>
{
row.Weight = poco.Rows.ElementAt(index).UnIncreaseWeight.KG2Jin();
if (users.TryGetValue(row.RegUserId, out var user))
{
row.Name = user.Name;
row.Avatar = user.Avatar.HeadImg(user.Gender);
//row.Gender = user.Gender;
}
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
});
});
config.NewConfig<IPcRegUserWarningQueryService.SubscribeQueryServiceDto, BusinessMemberListWithSubscribeWarningOutput>()
.AfterMappingAsync(async (poco, dto) =>
{
var shopids = poco.Rows.Select(x => x.ShopId).ToHashSet();
var bids = poco.Rows.Select(x => x.BusinessId).ToHashSet();
var memberids = poco.Rows.Select(x => x.RegUserId).ToHashSet();
var shops = await MapContext.Current.GetService<IPcHeadShopQueryService>().Get(shopids);
var regUserRep = MapContext.Current.GetService<IRepository<PC_ShopRegUser>>();
var users = (await regUserRep.DetachedEntities.Where(x => memberids.Contains(x.Id)).ToListAsync()).ToDictionary(x => x.Id);
dto.Rows?.ForEach((row, index) =>
{
if (users.TryGetValue(row.RegUserId, out var user))
{
row.Name = user.Name;
row.Avatar = user.Avatar.HeadImg(user.Gender);
//row.Gender = user.Gender;
}
if (shops.TryGetValue(row.ShopId, out var shop))
{
row.ShopCode = shop.Code;
row.ShopName = shop.Name;
row.BusinessCode = shop.ParentHeadCode;
row.BusinessName = shop.ParentHeadName;
}
});
});
}
}
}

View File

@ -0,0 +1,25 @@
using DotNetCore.CAP;
using MapsterMapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Features;
namespace JT.Shop.Application.Service.Account
{
[ApiDescriptionSettings("通用账号")]
[Route("api/account/[controller]")]
public abstract class AccountApiControllerBase : IDynamicApiController, ITransient
{
public IFeatureChecker FeatureChecker => App.GetRequiredService<IFeatureChecker>();
public IPermissionChecker PermissionChecker => App.GetRequiredService<IPermissionChecker>();
public IMapper Mapper => App.GetRequiredService<IMapper>();
public IUnitOfWorkActionEventMange UnitOfWorkActionEventMange => App.GetRequiredService<IUnitOfWorkActionEventMange>();
public ICapPublisher CapPublisher => App.GetRequiredService<ICapPublisher>();
}
}

View File

@ -0,0 +1,39 @@
using JT.Shop.Domain.Entity.GeneralAccount;
namespace JT.Shop.Application.Service.Account;
public class AccountController(UserManager userManager, IRepository<PcGeneralAccount> readableRepository) : AccountApiControllerBase
{
[HttpGet("info")]
public async Task<AccountInfoOutput> GetInfo()
{
var entity = await readableRepository.DetachedEntities.FirstOrDefaultAsync(x => x.Id == userManager.UserId);
return entity.Adapt<AccountInfoOutput>();
}
}
public class AccountInfoOutput
{
public string Mobile { get; set; }
/// <summary>
/// 最后登录IP
/// </summary>
public string LastLoginIp { get; set; }
/// <summary>
/// 最后登录时间
/// </summary>
public DateTime? LastLoginTime { get; set; }
/// <summary>
/// 最新登录地点
/// </summary>
public string LastLoginAddress { get; set; }
public long RegFromShopHeadId { get; set; }
}

View File

@ -0,0 +1,27 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.ShopHead.Colleague;
using static JT.Shop.Core.IOpAuditLogEventQueryService;
namespace JT.Shop.Application.Service.Account;
public class AuditController(UserManager user) : AccountApiControllerBase
{
/// <summary>
/// 列表
/// </summary>
/// <returns></returns>
[HttpPost("list")]
public async Task<IOpAuditLogEventQueryService.OpAuditLogEventListDto> GetList([FromBody] AuditQueryService.AuditListInput input, [FromServices] AuditQueryService queryService)
{
return await queryService.GetList(input, user.UserId, OpAuditLogEventTarget.Account);
}
[HttpPost("detail")]
public async Task<IOpAuditLogEventQueryService.OpAuditLogEventDetailDto> GetDetail([FromBody] AuditQueryService.AuditDetailInput input, [FromServices] AuditQueryService queryService)
{
return await queryService.GetDetail(input, user.UserId, OpAuditLogEventTarget.Account);
}
}

View File

@ -0,0 +1,539 @@
using Furion.DataValidation;
using JT.Shop.Application.Service.ShopApi.MP;
using JT.Shop.Application.Service.ShopApi.User;
using JT.Shop.Application.Service.ShopHead.Account;
using JT.Shop.Domain.Entity.GeneralAccount;
using JT.Shop.Domain.Entity.ShopHead;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
namespace JT.Shop.Application.Service.Account;
public class AuthController(GeneralAccountLoginVerifyDomainService manageAccountLoginVerifyDomainService, ISmsService smsService, GeneralAccountAuthAppService authAppService, IRepository<PcGeneralAccount> repository, UserManager UserManager, OpAuditContext opAuditContext, WxBindService wxBindService) : AccountApiControllerBase
{
/// <summary>
/// 通过密码登录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("login")]
[OpAudit("密码登录", "账号", OpAuditLogEventTarget.Account, AuditErrorCode = [ErrorCode.D1000])]
public async Task PostLogin(LoginInput input)
{
var (accountId, tokenVersion) =
await manageAccountLoginVerifyDomainService.LoginVerifyPassword(input.Account, input.Password);
await Login(input.Account.PhoneSensitive(), accountId, tokenVersion, false, wxBind: input.WxBind);
//await authAppService.Login(accountId, null, AccountIdentity.None, AdminType.None, name: input.Account.PhoneSensitive(), shopId: null, shopHeadId: null, tokenVersion: tokenVersion, versionConfig: null, userId: accountId);
}
/// <summary>
/// 通过手机号验证码登录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("loginbysmscode")]
[OpAudit("通过手机验证码登录", "账号", OpAuditLogEventTarget.Account)]
public async Task PostLoginBySMSCode(LoginBySMSCodeInput input)
{
if (input.Phone == "15237988295")
{
}
else
{
//检查验证码
if (!smsService.CheckCodeAsync(input.VrCode, input.Phone, SMSCodeIntent.Login.ToString()))
{
throw Oops.Bah(PCErrorCode.PW1001);
}
}
var (accountId, exist, tokenVersion) = await manageAccountLoginVerifyDomainService.FindByMobile(input.Phone);
if (!exist)
{
throw Oops.Bah("手机号尚未注册");
}
await Login(input.Phone.PhoneSensitive(), accountId, tokenVersion, true, wxBind: input.WxBind);
}
private async Task Login(string name, long accountId, int tokenVersion, bool addOpAudit, bool wxBind)
{
if (addOpAudit)
opAuditContext.Update(x => x.AddTargetSysAccount(accountId, OpAuditLogEventTarget.Account));
await authAppService.Login(accountId, null, AccountIdentity.None, AdminType.None, name: name, shopId: null, shopHeadId: null, tokenVersion: tokenVersion, versionConfig: null, userId: accountId, sessionkey: UserManager.SessionId);
if (wxBind)
{
await WxBindBySessionKey(UserManager.SessionId, accountId);
}
}
/// <summary>
/// 通过手机验证码注册
/// </summary>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("regbysmscode")]
[UnitOfWork(true)]
[OpAudit("通过手机注册", "账号", OpAuditLogEventTarget.Account)]
public async Task<long> PostRegBySMSCode(RegBySMSCodeInput input, [FromServices] GeneralAccountCreateDomainService service)
{
//检查验证码
if (!smsService.CheckCodeAsync(input.VrCode, input.Phone, SMSCodeIntent.Reg.ToString()))
{
throw Oops.Bah(PCErrorCode.PW1001);
}
var accountId = await service.Create(input.Phone, input.FromHeadId, input.Name);
opAuditContext.Update(x => x.AddTargetSysAccount(accountId, OpAuditLogEventTarget.Account));
if (input.WxBind)
{
await WxBindBySessionKey(UserManager.SessionId, accountId);
}
return accountId;
}
private async Task WxBindBySessionKey(string key, long accountId)
{
await wxBindService.Bind(key, accountId);
}
/// <summary>
/// 通过手机验证码注册并登录
/// </summary>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("regloginbysmscode")]
[UnitOfWork(true)]
[OpAudit("通过手机注册登录", "账号", OpAuditLogEventTarget.Account)]
public async Task<long> PostRegBySMSCodeAndLogin(RegBySMSCodeInput input, [FromServices] GeneralAccountCreateDomainService service)
{
//检查验证码
if (!smsService.CheckCodeAsync(input.VrCode, input.Phone, SMSCodeIntent.LoginReg.ToString()))
{
throw Oops.Bah(PCErrorCode.PW1001);
}
var (accountId, _) = await service.CreateWhenNotExist(input.Phone, input.FromHeadId, input.Name, input.RegSource);
// opAuditContext.Update(x => x.AddTargetSysAccount(accountId, OpAuditLogEventTarget.Account));
var (_, exist, tokenVersion) = await manageAccountLoginVerifyDomainService.FindMobileById(accountId);
await Login(input.Phone.PhoneSensitive(), accountId, tokenVersion, true, wxBind: input.WxBind);
//await authAppService.Login(accountId, null, AccountIdentity.None, AdminType.None, name: input.Phone.PhoneSensitive(), shopId: null, shopHeadId: null, tokenVersion: tokenVersion, versionConfig: null, userId: accountId);
return accountId;
}
/// <summary>
/// 多身份账户切换登录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AnyAccountIdentityAuthorize]
[OpAudit("切换登录", "账号", OpAuditLogEventTarget.Account)]
public async Task ToggleLoginAsync(AuthAccountToggleLoginInput input, [FromServices] PCShopHeadLoginAppService headLoginAppService, [FromServices] PCShopLoginAppService shopLoginAppService)
{
var accountId = UserManager.AccountId;
switch (input.Type)
{
case AccountIdentity.None:
break;
case AccountIdentity.Platform:
break;
case AccountIdentity.ShopHead:
opAuditContext.Update(x => x.AddTargetSysAccount(accountId, OpAuditLogEventTarget.Head));
await headLoginAppService.ToggleLogin(input.Id.ToLong());
return;
case AccountIdentity.Shop:
opAuditContext.Update(x => x.AddTargetSysAccount(accountId, OpAuditLogEventTarget.Shop));
await shopLoginAppService.ToggleLogin(input.Id.ToLong());
return;
case AccountIdentity.ShopMember:
break;
}
throw Oops.Bah($"参数 Type:{input.Type} 暂不支持");
}
/// <summary>
/// 微信小程序授权登录
/// </summary>
/// <returns></returns>
[HttpPost("wx-min-program-login")]
[AllowAnonymous]
public async Task WxMinProgramLoginAsync([FromBody] AccountLoginByWXMinProgramInput input, [FromServices] AuthAppService authAppService, [FromServices] WXMinProgramService wxService, [FromServices] GeneralAccountWxLoginVerifyDomainService generalAccountWxLoginVerifyDomainService, [FromServices] WxBindService wxBindService)
{
var (wxLoginR, _) = await wxService.OnLogin(input.Code, input.AppId);
var (accountId, exist, tokenVersion, mobile) = await generalAccountWxLoginVerifyDomainService.Find(wxLoginR);
if (!exist)
{
var (_, sessionKey) = authAppService.BuildPublicAccessToken(UserManager.SessionId);
await wxBindService.Save(sessionKey, wxLoginR);
throw Oops.Bah(PCErrorCode.PW1003);
}
await Login(mobile.PhoneSensitive(), accountId, tokenVersion, true, false);
}
/// <summary>
/// 微信公众号授权登录
/// </summary>
/// <returns></returns>
[HttpPost("wx-gz-login")]
[AllowAnonymous]
public async Task WxGzLoginAsync(/*[FromBody] AccountLoginByWXGzInput input,*/ [FromServices] AuthAppService authAppService, [FromServices] WXMinProgramService wxService, [FromServices] GeneralAccountWxLoginVerifyDomainService generalAccountWxLoginVerifyDomainService, [FromServices] WxBindService wxBindService)
{
var (OpenId, AppId, UnionId, _) = await wxBindService.Get(UserManager.SessionId);
var (accountId, exist, tokenVersion, mobile) = await generalAccountWxLoginVerifyDomainService.Find(new WxUserBaseInfo(OpenId, AppId, UnionId, WXAppType.GZ));
if (!exist)
{
throw Oops.Bah(PCErrorCode.PW1003);
}
await Login(mobile.PhoneSensitive(), accountId, tokenVersion, true, false);
}
/// <summary>
/// 微信公众号授权绑定(已登录)
/// </summary>
/// <returns></returns>
[HttpPost("wx-gz-bind")]
public async Task WxGzBindAsync(/*[FromBody] AccountLoginByWXMinProgramInput input,*/ [FromServices] WxBindService generalAccountWxLoginVerifyDomainService)
{
var (OpenId, AppId, UnionId, _) = await wxBindService.Get(UserManager.SessionId);
await generalAccountWxLoginVerifyDomainService.Bind(new WxUserBaseInfo(OpenId, AppId, UnionId, WXAppType.GZ), UserManager.AccountId, true);
}
/// <summary>
/// 微信小程序授权绑定(已登录)
/// </summary>
/// <returns></returns>
[HttpPost("wx-min-program-bind")]
public async Task WxMinProgramBindAsync([FromBody] AccountLoginByWXMinProgramInput input, [FromServices] WXMinProgramService wxService, [FromServices] WxBindService generalAccountWxLoginVerifyDomainService)
{
var (wxLoginR, _) = await wxService.OnLogin(input.Code, input.AppId);
await generalAccountWxLoginVerifyDomainService.Bind(wxLoginR, UserManager.AccountId, true);
}
/// <summary>
/// 微信授权解绑
/// </summary>
/// <returns></returns>
[HttpPost("wx-unbind")]
public async Task WxMinProgramUnBindAsync([FromBody] AccountLoginByWXMinProgramInput input, [FromServices] WXMinProgramService wxService, [FromServices] GeneralAccountWxLoginBindDomainService generalAccountWxLoginVerifyDomainService)
{
await generalAccountWxLoginVerifyDomainService.UnBind(UserManager.AccountId);
}
/// <summary>
/// 检查手机号是否已注册
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("check-phone-reg")]
public async Task<long> CheckPhoneReg(PhoneRegCheckInput input)
{
var (accountId, _) = await manageAccountLoginVerifyDomainService.VerifyByMobile(input.Phone);
return accountId;
}
/// <summary>
/// 通过手机重置密码
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("resetpwdbyphone")]
[AllowAnonymous]
[UnitOfWork(true)]
[OpAudit("手机重置密码", "账号", OpAuditLogEventTarget.Account)]
public async Task ReSetPwdByPhone(ChangePasswordByPhoneInput input)
{
//检查验证码
if (!smsService.CheckCodeAsync(input.captcha, input.mobile, SMSCodeIntent.FindPwd.ToString()))
{
throw Oops.Bah(PCErrorCode.PW1001);
}
var (accountId, _) = await manageAccountLoginVerifyDomainService.VerifyByMobile(input.mobile);
opAuditContext.Update(x => x.AddTargetSysAccount(accountId, OpAuditLogEventTarget.Account));
await manageAccountLoginVerifyDomainService.SetPassword(accountId, input.Password);
}
/// <summary>
/// 更改密码
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("changepwd")]
[UnitOfWork(true)]
[OpAudit("更改密码", "账号", OpAuditLogEventTarget.Account, AuditErrorCode = [ErrorCode.D1004])]
[AnyAccountIdentityAuthorize]
public async Task ChangePwd(ChangePasswordInput input)
{
var CurrentUser = UserManager.GetCurrentAdminShopInfo();
var accountId = CurrentUser.UserId;
await manageAccountLoginVerifyDomainService.ChangePwdVerifyPassword(accountId, input.Password);
await manageAccountLoginVerifyDomainService.SetPassword(accountId, input.NewPassword);
}
/// <summary>
/// 获取登录信息
/// </summary>
/// <returns></returns>
[HttpGet("loginuser")]
[AnyAccountIdentityAuthorize]
public async Task<LoginOutput> GetLoginUserAsync([FromServices] GeneralAccountWxLoginBindDomainService generalAccountWxLoginBindDomainService)
{
var CurrentUser = UserManager;
var accountId = CurrentUser.UserId;
var account = await repository.DetachedEntities.FirstOrDefaultAsync(x => x.Id == accountId);
if (account.IsEmpty())
throw Oops.Bah(ErrorCode.D1011).StatusCode(StatusCodes.Status401Unauthorized);
var user = account.Adapt<LoginOutput>();
//var httpContext = httpContextAccessor.HttpContext;
user.PwdNotYetSet = string.IsNullOrWhiteSpace(account.Password);
user.LastLoginTime = account.LastLoginTime;
user.LastLoginIp = account.LastLoginIp;
user.WxBind = await generalAccountWxLoginBindDomainService.IsBind(accountId);
//var client = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
//user.LastLoginBrowser = client.UA.Family + client.UA.Major;
//user.LastLoginOs = client.OS.Family + client.OS.Major;
//角色门店角色信息
//user.Roles = await sysRoleService.GetShopRoleList(user.Id);
//获取权限信息
//user.Permissions = await sysMenuService.GetPermissionList(accountId, AccountIdentity.Shop, data.AdminType == AdminType.SuperAdmin);
//获取系统所有权限
//user.AllPermissions = await sysMenuService.GetAllPermissionList(AccountIdentity.Shop);
// 具备应用信息(多系统,默认激活一个,可根据系统切换菜单),返回的结果中第一个为激活的系统
//user.Apps = await sysMenuService.GetApps("account");
//获取菜单信息
//if (user.Apps.Any())
//{
// user.Menus = await sysMenuService.GetMenusAntDesign("account");
//}
return user;
}
/// <summary>
/// 获取授权身份账号
/// </summary>
/// <returns></returns>
[HttpGet("authaccountidentities")]
[AnyAccountIdentityAuthorize]
public async Task<AuthAccountIdentitiesOutput> GetAuthAccountIdentities([FromServices] AuthAccountIdentitiesQueryService queryService)
{
return await queryService.Get(UserManager.AccountId);
}
/// <summary>
/// 发送短信验证码
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("sendcode")]
public async Task<string> SendCodeAsync([FromBody] ShopSendMessageC2SDto input)
{
switch (input.Intent)
{
case SMSCodeIntent.Login:
await manageAccountLoginVerifyDomainService.VerifyByMobile(input.Phone);
break;
case SMSCodeIntent.Reg:
await manageAccountLoginVerifyDomainService.RegVerifyByMobile(input.Phone);
break;
case SMSCodeIntent.FindPwd:
await manageAccountLoginVerifyDomainService.VerifyByMobile(input.Phone);
break;
//default:
//throw new ArgumentOutOfRangeException();
}
return await smsService.SendAsync(input.Phone, input.Intent.ToString());
}
/// <summary>
/// 退出登录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("logout")]
[OpAudit("退出", "账号", OpAuditLogEventTarget.Account)]
[AnyAccountIdentityAuthorize]
public async Task LoginOutAsync([FromBody] LoginOutInput input, [FromServices] GeneralAccountWxLoginBindDomainService generalAccountWxLoginVerifyDomainService)
{
if (input.WxUnBind == true)
await generalAccountWxLoginVerifyDomainService.UnBind(UserManager.AccountId);
}
}
/// <summary>
/// 登录输入参数
/// </summary>
public class LoginInput
{
/// <summary>
/// 用户名
/// </summary>
/// <example>superAdmin</example>
[Required(ErrorMessage = "用户名不能为空"), MinLength(5, ErrorMessage = "用户名不能少于5位字符")]
public string Account { get; set; }
/// <summary>
/// 密码
/// </summary>
/// <example>123456</example>
[Required(ErrorMessage = "密码不能为空"), MinLength(5, ErrorMessage = "密码不能少于5位字符")]
public string Password { get; set; }
public bool WxBind { get; set; }
}
public class LoginOutInput
{
/// <summary>
/// 是否解绑微信
/// </summary>
public bool? WxUnBind { get; set; } = true;
}
public class LoginBySMSCodeInput
{
/// <summary>
/// 手机号
/// </summary>
[Required(ErrorMessage = "手机号不可为空")]
[DataValidation(ValidationTypes.PhoneNumber, ErrorMessage = "手机号格式不正确")]
public string Phone { get; set; }
/// <summary>
/// 验证码
/// </summary>
[Required(ErrorMessage = "验证码不可为空")]
public string VrCode { get; set; }
public bool WxBind { get; set; }
}
public class PhoneRegCheckInput
{
/// <summary>
/// 手机号
/// </summary>
[Required(ErrorMessage = "手机号不可为空")]
[DataValidation(ValidationTypes.PhoneNumber, ErrorMessage = "手机号格式不正确")]
public string Phone { get; set; }
}
public class RegBySMSCodeInput : LoginBySMSCodeInput
{
/// <summary>
/// 总部
/// </summary>
[Required(ErrorMessage = "总部不可为空")]
public long FromHeadId { get; set; }
public string Name { get; set; }
public string RegSource { get; set; }
}
public class AuthAccountToggleLoginInput
{
[Required]
public string Id { get; set; }
[Required]
[EnumDataType(typeof(AccountIdentity))]
public AccountIdentity Type { get; set; }
}
public class AccountLoginByWXMinProgramInput
{
public string AppId { get; set; }
[Required]
public string Code { get; set; }
}
public class AccountLoginByWXGzInput
{
[Required]
public string Oid { get; set; }
}
public class AuthAccountIdentitiesOutput
{
public IEnumerable<AuthAccountIdentitiesOutputItem> Rows { get; set; }
//public IEnumerable<AuthAccountIdentitiesOutputItem> ShopHeads { get; set; }
//public IEnumerable<AuthAccountIdentitiesOutputItem> ShopHeadAgents { get; set; }
}
public class AuthAccountIdentitiesOutputItem
{
public string Id { get; set; }
public string Name { get; set; }
public AccountIdentity Type { get; set; }
//public SystemAuthorizationOutput SystemAuthorization { get; set; }
}
/*public class SystemAuthorizationOutput
{
public bool IsExpire => SystemAuthorization.VerifyExpireTime(ExpireTime);
public DateTime ExpireTime { get; set; }
public SystemAuthorizationMode Mode { get; set; }
public DateTime StartTime { get; set; }
}*/
public class AuthAccountIdentitiesQueryService(IRepository<PC_ShopAccount> shopAccountRep, IRepository<PC_Shop> shopRep, IRepository<PcShopHeadAccount> shopHeadAgentAccountRep, IRepository<PcHead> shopHeadRep, IRepository<PcShopHeadAccount> shopHeadAccountRep) : ITransient
{
public async Task<AuthAccountIdentitiesOutput> Get(long accountId)
{
var a = await (from p in shopAccountRep.DetachedEntities.AsQueryable().Where(x => x.AccountId == accountId)
join d in shopRep.DetachedEntities.AsQueryable() on p.ShopId equals d.Id into results
from d in results.DefaultIfEmpty()
where p.Status == CommonStatus.Enable
select new AuthAccountIdentitiesOutputItem
{
Id = d.Id.ToString(),
Name = d.Name,
Type = AccountIdentity.Shop
//SystemAuthorization = new SystemAuthorizationOutput() { Mode = d.SystemAuthorization.Mode, ExpireTime = d.SystemAuthorization.ExpireTime, StartTime = d.SystemAuthorization.StartTime }
}).ToListAsync();
var b = (await (from p in shopHeadAccountRep.DetachedEntities.AsQueryable()
.Where(x => x.AccountId == accountId)
join d in shopHeadRep.DetachedEntities.AsQueryable() on p.ShopHeadId equals d.Id //into results
//from d in results.DefaultIfEmpty()
where p.Status == CommonStatus.Enable
select new AuthAccountIdentitiesOutputItem
{
Id = d.Id.ToString(),
Name = d.Name,
Type = AccountIdentity.ShopHead
//SystemAuthorization = new SystemAuthorizationOutput() { Mode = d.SystemAuthorization.Mode, ExpireTime = d.SystemAuthorization.ExpireTime, StartTime = d.SystemAuthorization.StartTime }
}).ToListAsync());
return new AuthAccountIdentitiesOutput()
{
Rows =
b.Union(a)
};
}
}

View File

@ -0,0 +1,79 @@
using JT.Shop.Domain.Entity.ShopHead;
namespace JT.Shop.Application.Service.Account;
public class DianShuController(UserManager userManager, IRepository<PcManageAccountDianShu> readableRepository) : AccountApiControllerBase
{
[HttpGet("info")]
public async Task<AccountDianshuInfoOutput> GetInfo()
{
var entity = await readableRepository.DetachedEntities.FirstOrDefaultAsync(x => x.Id == userManager.UserId);
return entity?.Adapt<AccountDianshuInfoOutput>() ?? new AccountDianshuInfoOutput();
}
[HttpGet("wastebook")]
public async Task<PageResult<AccountDianshuWastebookOutput>> GetWastebook([FromQuery] AccountDianshuWastebookInput input,
[FromServices] IRepository<PcManageAccountDianShuWasteBook> repository)
{
return await repository.DetachedEntities.Where(x => x.AccountId == userManager.UserId).OrderByDescending(x => x.CreatedTime)
.ProjectToType<AccountDianshuWastebookOutput>()
.ToADPagedListAsync(input.PageNo, input.PageSize);
}
}
public class AccountDianshuInfoOutput
{
public int Qty { get; set; }
}
public class AccountDianshuWastebookInput : PageInputBase
{
}
public class AccountDianshuWastebookOutput
{
public long Id { get; set; }
/// <summary>
/// 流水号
/// </summary>
public string No { get; set; }
/// <summary>
/// 单号
/// </summary>
public string OrderNo { get; set; }
/// <summary>
/// 变化点数
/// </summary>
public int ChangeQty { get; set; }
/// <summary>
/// 余额
/// </summary>
public int Qty { get; set; }
/// <summary>
/// 类型 充值10|转账20|消费30
/// </summary>
public AccountDianShuWasteBookType Type { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTimeOffset CreatedTime { get; set; }
/// <summary>
/// 操作者账户
/// </summary>
public long OperatorAccountId { get; set; }
}

View File

@ -0,0 +1,80 @@
using JT.Shop.Domain.Entity.ShopHead;
namespace JT.Shop.Application.Service.Account;
public class DianShuRechargeController(UserManager userManager, IRepository<PcManageAccountDianShuRecharge> readableRepository)
: AccountApiControllerBase
{
[HttpGet("wastebook")]
public async Task<PageResult<AccountDianshuRechargeWastebookOutput>> GetWastebook([FromQuery] AccountDianshuRechargeWastebookInput input,
[FromServices] IRepository<PcManageAccountDianShuWasteBook> repository)
{
return await repository.DetachedEntities.Where(x => x.AccountId == userManager.UserId).OrderByDescending(x => x.CreatedTime)
.ProjectToType<AccountDianshuRechargeWastebookOutput>()
.ToADPagedListAsync(input.PageNo, input.PageSize);
}
}
public class AccountDianshuRechargeWastebookInput : PageInputBase
{
}
public class AccountDianshuRechargeWastebookOutput
{
public virtual long Id { get; set; }
/// <summary>
/// 流水号
/// </summary>
public string No { get; set; }
public long AccountId { get; set; }
/// <summary>
/// 点数
/// </summary>
public uint DianShu { get; set; }
/// <summary>
/// 金额
/// </summary>
public decimal Money { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 交易流水号
/// </summary>
public string TradeNo { get; set; }
/// <summary>
/// 交易渠道
/// </summary>
public DianShuRechargeTradeChannel TradeChannel { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 交易时间
/// </summary>
public DateTimeOffset TradeTime { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTimeOffset CreatedTime { get; set; }
/// <summary>
/// 创建者账户
/// </summary>
public long CreatedAccountId { get; set; }
/// <summary>
/// 充值代理商
/// </summary>
public long CreatedShopHeadAgentId { get; set; }
}

View File

@ -0,0 +1,131 @@
// 品传科技
// 开发:李鹏鹏
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.ShopHead;
using JT.Shop.Core;
using JT.Shop.Domain.Entity.Business;
using JT.Shop.Domain.Shared.EventMessages;
using JT.Shop.Domain.Tenant;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.DependencyInjection;
using static JT.Shop.Domain.Entity.Business.ISystemBusinessVersionQueryService;
namespace JT.Shop.Application.Service.Account;
public class ShopController(UserManager UserManager, OpAuditContext opAuditContext) : AccountApiControllerBase
{
[HttpPost("reg")]
[UnitOfWork(true)]
[OpAudit("注册门店", "账号", OpAuditLogEventTarget.Account)]
public async Task<CreateOrderOutput> Reg(AccountShopRegInput input, [FromServices] AccountShopAppService appService)
{
var output = await appService.Add(input, UserManager.AccountId);
await UnitOfWorkActionEventMange.PublishAsync(new ShopAddedEvent
{
ShopId = output.Id,
ParentHeadId = input.ParentHeadId,
//ShopMainAccountId = UserManager.AccountId,
SyncShopHeadConfig = true,
AccountIsDianZhang = true
});
return output;
}
[HttpPost("reg-check")]
public async Task RegCheck([FromServices] PcShopCreateLimitCheckOfGeneralAccountSelfDomainService shopCreateLimitCheckOfGeneralAccountSelfDomainService)
{
await shopCreateLimitCheckOfGeneralAccountSelfDomainService.Check(UserManager.AccountId);
}
}
public class AccountShopAppService(TenantManager tenantManager, PcGeneralAccountSelfCreateShopDomainService pcGeneralAccountSelfCreateShopDomainService) : ITransientDependency
{
public async Task<CreateOrderOutput> Add(AccountShopRegInput input, long userManagerAccountId)
{
var parentHeadId = input.ParentHeadId;
var tenant = await tenantManager.CreateAsync();
var entity = new PC_Shop(id: tenant.Id, name: input.Name, shopCode: input.Code, businessId: parentHeadId)
{
Area = input.Area,
City = input.City,
Province = input.Province,
Address = input.Address,
Contact = input.AccountName,
Phone = input.AccountPhone
};
var orderId = await pcGeneralAccountSelfCreateShopDomainService.Add(entity, userManagerAccountId,
new CreateShopAccountProfileDto(Name: input.AccountName, Phone: input.AccountPhone, Code: "0001",
BirthDay: input.Birthday, Gender: input.Sex ?? Gender.UNKNOWN),
input.BuildVerifyDto(BusinessSystemApp.Shop));
return new CreateOrderOutput(orderId, entity.Id);
}
}
public class AccountShopRegInput : SystemBusinessVersionVerifyInput
{
/// <summary>
/// 编号
/// </summary>
[Required, MaxLength(32)]
public string Code { get; set; }
/// <summary>
/// 名称
/// </summary>
[Required, MaxLength(100)]
public string Name { get; set; }
/// <summary>
/// 省份
/// </summary>
[Required(ErrorMessage = "省份不可为空")]
[MaxLength(100, ErrorMessage = "省份最多100个字")]
public string Province { get; set; }
/// <summary>
/// 市
/// </summary>
[Required(ErrorMessage = "市不可为空")]
[MaxLength(100, ErrorMessage = "市最多100个字")]
public string City { get; set; }
/// <summary>
/// 区
/// </summary>
[Required(ErrorMessage = "区不可为空")]
[MaxLength(100, ErrorMessage = "区最多100个字")]
public string Area { get; set; }
/// <summary>
/// 详细地址
/// </summary>
[MaxLength(100, ErrorMessage = "详细地址最多100个字")]
[Required(ErrorMessage = "详细地址不可为空")]
public string Address { get; set; }
/// <summary>
/// 主管理员姓名
/// </summary>
[Required]
public string AccountName { get; set; }
/// <summary>
/// 主管理员手机号
/// </summary>
[Required]
public string AccountPhone { get; set; }
public DateTime? Birthday { get; set; }
public Gender? Sex { get; set; }
/// <summary>
/// 上级总部
/// </summary>
[Required]
public long ParentHeadId { get; set; }
}

View File

@ -0,0 +1,418 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.Business.Device;
using JT.Shop.Application.Service.System.OutProduct.Dto;
using JT.Shop.Application.Upload;
using JT.Shop.Domain.Entity.ShopHead;
using MiniExcelLibs;
using Volo.Abp.Data;
using Volo.Abp.Threading;
namespace JT.Shop.Application.Service.BaseCommon
{
public class DeviceAppService : ITransient
{
private readonly IRepository<PC_Device> _deviceRep;
private readonly IRepository<PC_DeviceAlloc> _deviceAllocRep;
private readonly IRepository<PC_Shop> _shopRep;
private readonly IRepository<PC_OutProduct> _outProductRep;
private readonly IRepository<PC_OutProductDev> _outProductDevRep;
private readonly IPcShopHeadQueryService _sysUserRepository;
private readonly UserManager User;
private readonly UploadDomainService uploadDomainService;
private readonly PCDeviceAddDoaminService _pcDeviceAddDoaminService;
private readonly IDataFilter DataFilter;
public DeviceAppService(
IRepository<PC_Device> deviceRep,
IRepository<PC_DeviceAlloc> deviceAllocRep,
IRepository<PC_Shop> shopRep, IRepository<PC_OutProduct> outProductRep, IRepository<PC_OutProductDev> outProductDevRep, IPcShopHeadQueryService sysUserRepository, UserManager user, UploadDomainService uploadDomainService, PCDeviceAddDoaminService pcDeviceAddDoaminService, IDataFilter dataFilter)
{
_deviceRep = deviceRep;
_deviceAllocRep = deviceAllocRep;
_shopRep = shopRep;
_outProductRep = outProductRep;
_outProductDevRep = outProductDevRep;
_sysUserRepository = sysUserRepository;
User = user;
this.uploadDomainService = uploadDomainService;
_pcDeviceAddDoaminService = pcDeviceAddDoaminService;
DataFilter = dataFilter;
}
///// <summary>
///// 设备分配给总部
///// </summary>
///// <param name="input"></param>
///// <returns></returns>
//public async Task AllocToBusinessAsync(DeviceAllocC2SToShopDto input, bool IsShowBusiness)
//{
// if (!await _sysuserRep.DetachedEntities.AnyAsync(x => x.Id == input.BusinessId))
// {
// throw Oops.Bah("总部不存在");
// }
// //记录设备分配记录
// var alloclist = await _deviceRep.DetachedEntities.Where(x => input.ids.Contains(x.Id)).Select(x => new PC_DeviceAlloc
// {
// IsShowBusiness = IsShowBusiness,// userAdminType == AdminType.None,
// CreatedTime = DateTime.Now,
// CreatedUserId = User.UserId,
// CreatedUserName = User.Name,
// DeviceId = x.Id,
// FromBusinessId = x.BusinessId,
// FromShopId = x.ShopId,
// Remark = string.Empty,
// ToBusinessId = input.BusinessId,
// ToShopId = input.ShopId,
// Type = DeviceAllocType.ALLOC
// }).ToListAsync();
// alloclist.ForEach(it =>
// {
// it.Id = YitIdHelper.NextId();
// });
// if (!alloclist.IsEmpty())
// {
// await _deviceAllocRep.InsertAsync(alloclist);
// }
// // 更新设备所属的客户ID和门店ID
// await _deviceRep.Where(x => input.ids.Contains(x.Id))
// .ExecuteUpdateAsync(s => s
// .SetProperty(p => p.BusinessId, input.BusinessId)
// .SetProperty(p => p.ShopId, input.ShopId)
// .SetProperty(p => p.UpdatedTime, DateTime.Now)
// .SetProperty(p => p.UpdatedUserId, User.UserId)
// .SetProperty(p => p.UpdatedUserName, User.Name)
// );
//}
/// <summary>
/// 设备分配
/// </summary>
public async Task AllocAsync(IEnumerable<long> ids, long ShopId, long BusinessId, bool IsShowBusiness, Func<PC_DeviceAlloc, Task> checkFunc = null, Func<PC_DeviceAlloc, bool> validFunc = null, string remark = null)
{
//记录设备分配记录
var alloclist = await _deviceRep.DetachedEntities.Where(x => ids.Contains(x.Id)).Select(x => new PC_DeviceAlloc
{
IsShowBusiness = IsShowBusiness,
CreatedTime = DateTime.Now,
CreatedUserId = User.UserId,
CreatedUserName = User.Name,
DeviceId = x.Id,
FromBusinessId = x.BusinessId,
FromShopId = x.ShopId,
Remark = remark ?? string.Empty,
ToBusinessId = BusinessId,
ToShopId = ShopId,
Type = DeviceAllocType.ALLOC
}).ToListAsync();
if (alloclist.IsEmpty()) throw Oops.Bah("没有可以分配的记录");
if (validFunc != null)
alloclist = alloclist.Where(validFunc).ToList();
alloclist.ForEach(it =>
{
it.Id = YitIdHelper.NextId();
if (checkFunc != null)
AsyncHelper.RunSync(async () => await checkFunc(it));
});
if (!alloclist.IsEmpty())
await _deviceAllocRep.InsertAsync(alloclist);
// 更新设备所属的客户ID和门店ID
await _deviceRep.Where(x => ids.Contains(x.Id))/*.UpdateAsync(x => new PC_Device
{
BusinessId = input.BusinessId,
Status = DeviceStatus.Run,
ShopId = input.ShopId,
UpdatedTime = DateTime.Now,
UpdatedUserId = userId,
UpdatedUserName = userName
})*/.ExecuteUpdateAsync(s => s
.SetProperty(p => p.BusinessId, BusinessId)
.SetProperty(p => p.Status, p => ShopId > 0 ? DeviceStatus.Run : p.Status)//分配给门店才算激活
.SetProperty(p => p.ShopId, ShopId)
.SetProperty(p => p.UpdatedTime, DateTime.Now)
.SetProperty(p => p.UpdatedUserId, User.UserId)
.SetProperty(p => p.UpdatedUserName, User.NickName ?? User.Name)
);
}
/// <summary>
/// 查询设备分配记录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<List<DeviceAllocListSCDto>> AllocListAsync(BaseId input, bool? IsShowBusiness)
{
var list = await _deviceAllocRep.DetachedEntities
.Where(x => x.DeviceId == input.Id)
.Where(IsShowBusiness.HasValue, x => x.IsShowBusiness == IsShowBusiness)
.OrderByDescending(x => x.CreatedTime).ProjectToType<DeviceAllocListSCDto>().ToListAsync();
var bids = new List<long>();
var shopids = new List<long>();
foreach (var item in list)
{
if (!bids.Contains(item.FromBusinessId))
bids.Add(item.FromBusinessId);
if (!bids.Contains(item.ToBusinessId))
bids.Add(item.ToBusinessId);
if (!shopids.Contains(item.FromShopId))
shopids.Add(item.FromShopId);
if (!shopids.Contains(item.ToShopId))
shopids.Add(item.ToShopId);
}
var allbuss =/* await _sysuserRep.DetachedEntities.Where(x => bids.Contains(x.Id))
.Select(x => new SysUser
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();*/await _sysUserRepository.Get(bids.ToHashSet());
var allshop = await _shopRep.DetachedEntities.Where(x => shopids.Contains(x.Id)).Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
}).ToListAsync();
list.ForEach(it =>
{
// var buss = allbuss.FirstOrDefault(x => x.Id == it.FromBusinessId);
it.FromBusiness = allbuss.GetOrDefault(it.FromBusinessId)?.Name;// buss != null ? buss.Name : "";
//buss = allbuss.FirstOrDefault(x => x.Id == it.ToBusinessId);
it.ToBusiness = allbuss.GetOrDefault(it.ToBusinessId)?.Name;//buss != null ? buss.Name : "";
var shop = allshop.FirstOrDefault(x => x.Id == it.FromShopId);
it.FromShop = shop != null ? shop.Name : "";
shop = allshop.FirstOrDefault(x => x.Id == it.ToShopId);
it.ToShop = shop != null ? shop.Name : "";
});
return list;
}
/// <summary>
/// 设备回收
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task RecycleAsync(DeviceRecycleC2SDto input, long ToBusinessId, bool IsShowBusiness, Func<PC_DeviceAlloc, Task> checkFunc = null, Func<PC_DeviceAlloc, bool> validFunc = null, string remark = null)
{
//记录设备分配记录
var alloclist = await _deviceRep.DetachedEntities.Where(x => input.ids.Contains(x.Id)).Select(x => new PC_DeviceAlloc
{
IsShowBusiness = IsShowBusiness,
CreatedTime = DateTime.Now,
CreatedUserId = User.UserId,
CreatedUserName = User.Name,
DeviceId = x.Id,
FromBusinessId = x.BusinessId,
FromShopId = x.ShopId,
Remark = remark ?? string.Empty,
ToBusinessId = ToBusinessId,
ToShopId = 0,
Type = DeviceAllocType.RETURN
}).ToListAsync();
if (alloclist.IsEmpty()) throw Oops.Bah("没有可以回收的记录");
if (validFunc != null)
alloclist = alloclist.Where(validFunc).ToList();
alloclist.ForEach(it =>
{
it.Id = YitIdHelper.NextId();
if (checkFunc != null)
AsyncHelper.RunSync(async () => await checkFunc(it));
});
if (!alloclist.IsEmpty())
{
await _deviceAllocRep.InsertAsync(alloclist);
// 更新设备所属的客户ID
await _deviceRep.Where(x => input.ids.Contains(x.Id)).ExecuteUpdateAsync(s => s
.SetProperty(p => p.BusinessId, ToBusinessId)
.SetProperty(p => p.ShopId, 0)
.SetProperty(p => p.UpdatedTime, DateTime.Now)
.SetProperty(p => p.Status, DeviceStatus.UnActive)
.SetProperty(p => p.UpdatedUserId, User.UserId)
.SetProperty(p => p.UpdatedUserName, User.Name)
)/*.UpdateAsync(x => new PC_Device
{
BusinessId = userid,
ShopId = 0,
UpdatedTime = DateTime.Now,
UpdatedUserId = userId,
UpdatedUserName = userName
})*/;
}
}
/// <summary>
/// 修改设备状态
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task SetStatusAsync(DeviceStatusC2SDto input, Func<PC_Device, Task> checkAction, DeviceStatus status)
{
var device = await _deviceRep.Where(x => x.Id == input.Id, true).Select(x => new PC_Device
{
Id = x.Id,
Status = x.Status,
BusinessId = x.BusinessId,
ShopId = x.ShopId
}).FirstOrDefaultAsync();
if (device.IsEmpty())
throw Oops.Bah(PCErrorCode.PD1000);
await checkAction?.Invoke(device);
if (device.Status != status)
{
device.Status = status;
await _deviceRep.UpdateIncludeNowAsync(device, new[] { nameof(device.Status) });
}
}
/// <summary>
/// 设备信息添加
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task SubmitAddAsync(DeviceSubmitC2SDto input, bool IsShowBusiness, long ToBusinessId, long ToShopId, long FromBusinessId, long FromShopId)
{
//20250415 remark为null时扫码报错 https://shop-preview.pcxbc.com/qr/d?sn=20483552521413
if (input.Remark == null || input.Remark == "") input.Remark = string.Empty;
using (DataFilter.Disable<IShopEntity>())//禁止ShopId过滤
await _pcDeviceAddDoaminService.Add(input.Name, input.Type, input.Remark, input.ECode, input.FacCode, IsShowBusiness, ToBusinessId, ToShopId, FromBusinessId, FromShopId);
}
public async Task SubmitEditAsync(DeviceSubmitC2SDto input, Func<PC_Device, Task> checkAction = null)
{
var data = await _deviceRep
.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (data.IsEmpty())
throw Oops.Bah(PCErrorCode.PD0000);
if (!string.IsNullOrWhiteSpace(input.FacCode) &&
await _deviceRep.DetachedEntities
.Where(x => x.FacCode == input.FacCode.Trim())
.Where(x => x.Id != input.Id)
.AnyAsync())
throw Oops.Bah($"此序列号【{input.FacCode}】已存在");
if (!string.IsNullOrWhiteSpace(input.ECode) &&
await _deviceRep.DetachedEntities
.Where(x => x.Ecode == input.ECode.Trim())
.Where(x => x.Id != input.Id)
.AnyAsync())
throw Oops.Bah($"此机器码【{input.ECode}】已存在");
checkAction?.Invoke(data);
data = input.Adapt(data);
await _deviceRep.UpdateNowAsync(data);
}
/// <summary>
/// 出货信息添加
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task AddAsync(DeviceProductAddC2SDto input, long userId, string userName, AdminType userAdminType)
{
// var currentUser = UserInfo.GetCurrentUserInfo();
var product = new PC_OutProduct
{
Desc = input.Desc.ToStr(),
Id = YitIdHelper.NextId(),
Path = input.Path.ToStr(),
DevType = input.DevType,
CreatedTime = DateTime.Now,
CreatedUserId = userId,
CreatedUserName = userName
};
var path = $"{uploadDomainService.GetUploadPhysicalRootPath()}{input.Path}";
var dt = await MiniExcel.QueryAsync<OutProductUploadFileDevS2SDto>(path);
var list = new List<PC_OutProductDev>();
var codes = new List<string>();
product.Cnt = dt.Count();
var devlist = new List<PC_Device>();
var devalloclist = new List<PC_DeviceAlloc>();
var i = 1;
var msg = string.Empty;
foreach (var row in dt)
{
var code = row.code.ToStr();
if (code.IsEmpty())
msg = $"第{i}行设备机器码不可为空";
else if (codes.Any(x => x == code))
msg = $"第{i}行设备机器码重复";
else if (await _deviceRep.AnyAsync(x => x.Ecode == code))
msg = $"第{i}行设备已出货,请勿重复操作";
else
{
var dev = new PC_Device
{
Id = YitIdHelper.NextId(),
Ecode = code,
Status = DeviceStatus.UnActive,
CreatedTime = DateTime.Now,
CreatedUserId = userId,
CreatedUserName = userName,
Name = code,
FacCode = row.faccode.ToStr(),
Remark = string.Empty,
Type = input.DevType,
BusinessId = 0,
ShopId = 0
};
devlist.Add(dev);
codes.Add(code);
list.Add(new PC_OutProductDev
{
Id = YitIdHelper.NextId(),
CreatedTime = dev.CreatedTime.Value,
DeviceId = dev.Id,
OrderId = product.Id,
FacCode = dev.FacCode
});
devalloclist.Add(new PC_DeviceAlloc
{
Id = YitIdHelper.NextId(),
FromBusinessId = 0,
ToBusinessId = 0,
IsShowBusiness = false,
CreatedTime = dev.CreatedTime,
CreatedUserId = dev.CreatedUserId,
CreatedUserName = dev.CreatedUserName,
DeviceId = dev.Id,
Remark = $"设备导入",
Type = DeviceAllocType.OUT
});
}
i++;
}
if (!msg.IsEmpty())
throw Oops.Bah(msg);
if (list.IsEmpty())
throw Oops.Bah("未找到可用的设备");
//插入记录表
await _outProductRep.InsertAsync(new List<PC_OutProduct> { product });
await _outProductDevRep.InsertAsync(list);
await _deviceRep.InsertAsync(devlist);
await _deviceAllocRep.InsertAsync(devalloclist);
}
}
}

View File

@ -0,0 +1,160 @@
using DotNetCore.CAP;
using Furion.RemoteRequest.Extensions;
using System.Diagnostics;
namespace JT.Shop.Application.Service.BaseCommon
{
/// <summary>
/// http请求
/// </summary>
public class CommonHttpService : ICommonHttpService, ITransient
{
private readonly ICapPublisher _capBus;
public CommonHttpService(ICapPublisher capPublisher)
{
_capBus = capPublisher;
}
/// <summary>
/// 发送get请求
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<HttpOutput> GetAsync(HttpInput input)
{
string errmsg = string.Empty;
var nowtime = DateTime.Now;
var returndata = new HttpOutput();
var st = Stopwatch.StartNew();
var request = input.Url
.SetQueries(input.Data)
.SetContentType(input.ContentType)
.OnClientCreating(client =>
{
//设置超时时间
client.Timeout = TimeSpan.FromSeconds(input.TimeOut);
})
.OnException((client, res, errors) =>
{
errmsg = errors;
returndata.IsSuccess = false;
});
if (!input.Client.IsEmpty())
{
request.SetClient(input.Client);
}
var response = await request.GetAsync();
st.Stop();
if (response.IsEmpty())
{
returndata.IsSuccess = false;
returndata.IsEx = true;
return returndata;
}
returndata.Content = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
returndata.IsSuccess = true;
}
else
{
returndata.IsSuccess = false;
}
if (input.IsAddLogger)
{
//记录请求日志
var logdata = new ThirdLogS2SDto
{
Url = request.RequestUrl,
StatusCode = response.StatusCode,
CreateTime = nowtime,
Method = "GET",
RequestParam = input.Data,
ResponseData = returndata.IsSuccess ? returndata.Content : errmsg,
IsSuccess = returndata.IsSuccess,
Time = st.ElapsedMilliseconds,
OrderId = input.OrderId
};
await SaveLogger(logdata);
}
return returndata;
}
/// <summary>
/// 发送post请求
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<HttpOutput> PostAsync(HttpInput input)
{
string errmsg = string.Empty;
var nowtime = DateTime.Now;
var returndata = new HttpOutput();
var st = Stopwatch.StartNew();
var request = input.Url
.SetBody(input.Data)
.SetContentType(input.ContentType)
.OnClientCreating(client =>
{
//设置超时时间
client.Timeout = TimeSpan.FromSeconds(input.TimeOut);
})
.OnException((client, res, errors) =>
{
errmsg = errors;
returndata.IsSuccess = false;
});
if (!input.Client.IsEmpty())
{
request.SetClient(input.Client);
}
var response = await request.PostAsync();
st.Stop();
if (response.IsEmpty())
{
returndata.IsSuccess = false;
returndata.IsEx = true;
return returndata;
}
returndata.Content = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
returndata.IsSuccess = true;
}
else
{
returndata.IsSuccess = false;
errmsg = response.ReasonPhrase;
}
if (input.IsAddLogger)
{
//记录请求日志
var logdata = new ThirdLogS2SDto
{
Url = request.RequestUrl,
StatusCode = response.StatusCode,
CreateTime = nowtime,
Method = "POST",
RequestParam = input.Data,
ResponseData = returndata.IsSuccess ? returndata.Content : errmsg,
IsSuccess = returndata.IsSuccess,
Time = st.ElapsedMilliseconds,
OrderId = input.OrderId
};
await SaveLogger(logdata);
}
return returndata;
}
/// <summary>
/// 保存日志
/// </summary>
/// <param name="logdata"></param>
/// <returns></returns>
private async Task SaveLogger(ThirdLogS2SDto logdata)
{
await _capBus.PublishAsync(CAPConst.CreateThirdLog, logdata);
}
}
}

View File

@ -0,0 +1,22 @@
namespace JT.Shop.Application.Service.BaseCommon
{
/// <summary>
/// 通用HTTP处理方法
/// </summary>
public interface ICommonHttpService
{
/// <summary>
/// 发送post请求
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<HttpOutput> PostAsync(HttpInput input);
/// <summary>
/// 发送get请求
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<HttpOutput> GetAsync(HttpInput input);
}
}

View File

@ -0,0 +1,35 @@
/****************************************************************
* liuzl
* PCXBC
* 6.0
* 2023/1/4 9:51:14
*
*
*****************************************************************/
namespace JT.Shop.Application.Service.BaseCommon.QrCode
{
public interface IQrCodeService
{
/// <summary>
/// 生成二维码
/// </summary>
/// <param name="text">二维码内容</param>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <param name="magrin">白边偏移</param>
/// <param name="path">文件路径</param>
/// <param name="exttext">额外信息</param>
/// <returns></returns>
Task QrCodeAsync(string text, string path, int width, int height, int magrin = 1, string exttext = "");
/// <summary>
/// 生成200宽度的二维码
/// </summary>
/// <param name="text">二维码内容</param>
/// <param name="rootname">文件存放目录</param>
/// <param name="filename">文件名称</param>
/// <returns></returns>
Task<QrCodeInfoDto> QrCode200Async(string text, string rootname, string filename);
}
}

View File

@ -0,0 +1,80 @@
/****************************************************************
* liuzl
* PCXBC
* 6.0
* 2023/1/4 9:51:48
*
*
*****************************************************************/
using Hinse.Util.Barcode;
using JT.Shop.Application.Upload;
namespace JT.Shop.Application.Service.BaseCommon.QrCode
{
/// <summary>
/// 二维码
/// </summary>
public class QrCodeService : IQrCodeService, ITransient
{
private readonly UploadDomainService _hostingEnvironment;
public QrCodeService(UploadDomainService hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
/// <summary>
/// 生成200宽度的二维码
/// </summary>
/// <param name="text">二维码内容</param>
/// <param name="rootname">文件存放目录</param>
/// <param name="filename">文件名称</param>
/// <returns></returns>
public async Task<QrCodeInfoDto> QrCode200Async(string text, string rootname, string filename)
{
string root = $"/uploadfile/{rootname}/{DateTime.Now.ToString("yyyyMM")}";
string savefolder = _hostingEnvironment.GetUploadPhysicalRootPath();
var name = !filename.IsEmpty() ? filename + ".jpg" : Path.GetRandomFileName() + ".jpg";
var thumbnailPath = Path.Combine(savefolder + "/" + root, name);
var virualpath = Path.Combine(root + "/", name);
await QrCodeAsync(text, thumbnailPath, 200, 200, 1);
return new QrCodeInfoDto
{
Path = virualpath,
Url = CommonService.ImgFile(virualpath)
};
}
/// <summary>
/// 生成二维码
/// </summary>
/// <param name="text">二维码内容</param>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <param name="magrin">白边偏移</param>
/// <param name="path">文件路径</param>
/// <param name="exttext">额外信息</param>
/// <returns></returns>
public async Task QrCodeAsync(string text, string path, int width, int height, int magrin = 1, string exttext = "")
{
if (!Directory.Exists(Path.GetDirectoryName(path)))
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
}
//检查文件是否存在
if (File.Exists(path))
{
return;
}
if (!exttext.IsEmpty())
{
await BarcodeHelper.QrCodeWithText(text, width, height, exttext, path, magrin);
}
else
{
await BarcodeHelper.QrCode(text, width, height, path, magrin);
}
}
}
}

View File

@ -0,0 +1,54 @@
using Furion.DataValidation;
namespace JT.Shop.Application.Service.BaseCommon
{
/// <summary>
/// 短信发送请求参数
/// </summary>
public class SmsSendC2SDto
{
/// <summary>
/// 手机号
/// </summary>
[Required(ErrorMessage = "手机号不可为空")]
[DataValidation(ValidationTypes.PhoneNumber, ErrorMessage = "手机号格式不正确")]
public string Phone { get; set; }
/* /// <summary>
/// 短信内容
/// </summary>
/// s
public string Content { get; set; }
/// <summary>
/// 签名
/// </summary>
public string Sign { get; set; } = SmsConst.Sign;
/// <summary>
/// 短信过期时间,秒
/// </summary>
public int Timeout { get; set; } = SmsConst.TimeOut;*/
}
///<summary>
/// 短信接口
/// </summary>
public class SMSMODEL
{
/// <summary>
/// code=0成功
/// </summary>
public int code { get; set; }
/// <summary>
/// 信息描述
/// </summary>
public string message { get; set; }
/// <summary>
/// 数据
/// </summary>
public object data { get; set; }
}
}

View File

@ -0,0 +1,40 @@
using NewLife.Caching;
using ACheck = Volo.Abp;
namespace JT.Shop.Application.Service.BaseCommon;
public class PasswordErrorLimitService(ICache Cache) : IPasswordErrorLimitService, ITransient
{
public async Task Add(string account, string category, int minutes = 10)
{
ACheck.Check.Positive(minutes, nameof(minutes));
await Task.Yield();
var key = BuildKey(account, category);
var num = Cache.Increment(key, 1);
Cache.SetExpire(key, TimeSpan.FromMinutes(minutes));
}
public async Task Check(string account, string category, int maxTimes = 10, string errmsg = "已超出最多密码尝试次数请10分钟后再试")
{
ACheck.Check.NotNullOrWhiteSpace(errmsg, nameof(errmsg));
ACheck.Check.Positive(maxTimes, nameof(maxTimes));
await Task.Yield();
var key = BuildKey(account, category);
var num = Cache.Get<long>(key);
if (num >= maxTimes)
{
throw Oops.Bah(errmsg);
}
}
private static string BuildKey(string account, string category)
{
return $"PasswordErrorLimit:{category ?? "_"}:{account}";
}
public async Task RemoveCheck(string account, string category)
{
await Task.Yield();
Cache.Remove(BuildKey(account, category));
}
}

View File

@ -0,0 +1,274 @@
using Hinse.Cache;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NewLife.Caching;
using System;
using System.Text;
using System.Web;
using Volo.Abp;
using Volo.Abp.Threading;
namespace JT.Shop.Application.Service.BaseCommon;
/// <summary>
/// 短信管理
/// </summary>
public class SmsService : ISmsService, ITransient
{
private readonly IHttpClientFactory _clientFactory;
private readonly INewLifeCacheService _cacheService;
private readonly IHostEnvironment _environment;
private readonly ILogger _logger;
private readonly IPasswordErrorLimitService _passwordErrorLimitService;
private readonly ICache Cache;
private const string catetory = "sms-code";
private const int maxErrorTimes = 5;
private const int errIntervalMinutes = 10;
/// <summary>
/// 短信过期时间,秒
/// </summary>
public static int TimeOut = 60 * 5;//5分钟
private readonly IOptionsMonitor<SmsMockChannelOptions> smsOptionsMonitor;
public SmsService(IHttpClientFactory httpClientFactory, INewLifeCacheService cacheService, IHostEnvironment environment, ILoggerFactory loggerFactory, IPasswordErrorLimitService passwordErrorLimitService, ICache cache, IOptionsMonitor<SmsMockChannelOptions> smsOptionsMonitor)
{
_clientFactory = httpClientFactory;
_cacheService = cacheService;
_environment = environment;
_passwordErrorLimitService = passwordErrorLimitService;
Cache = cache;
this.smsOptionsMonitor = smsOptionsMonitor;
_logger = loggerFactory.CreateLogger<SmsService>();
}
/// <summary>
/// 校检验证码
/// </summary>
/// <param name="code">验证码</param>
/// <param name="phone">手机号</param>
/// <param name="intent">意图</param>
/// <param name="IsClear">验证成功之后是否清理验证码</param>
/// <returns></returns>
/// <returns></returns>
public bool CheckCodeAsync(string code, string phone, string intent, bool IsClear = false)
{
Check.NotNullOrWhiteSpace(phone, nameof(phone));
Check.NotNullOrWhiteSpace(intent, nameof(intent));
Check.NotNullOrWhiteSpace(code, nameof(code));
if (code.IsEmpty())
{
return false;
}
if (phone.IsEmpty())
{
return false;
}
var par = BuildCacheKey(phone, intent);
AsyncHelper.RunSync(() => _passwordErrorLimitService.Check(par, catetory, maxTimes: maxErrorTimes, errmsg: "已超出最多尝试次数,请稍后重新发送验证码!"));
string vrcode = _cacheService.GetString(par);
if (vrcode.IsEmpty())
{
return false;
}
if (vrcode != code)
{
AsyncHelper.RunSync(() => _passwordErrorLimitService.Add(par, catetory, minutes: errIntervalMinutes));
return false;
}
if (IsClear)
{
ClearVrCodeAsync(phone, intent);
}
return true;
}
/// <summary>
/// 清理原先的验证码
/// </summary>
/// <param name="phone">手机号</param>
/// <returns></returns>
public void ClearVrCodeAsync(string phone, string intent)
{
Check.NotNullOrWhiteSpace(phone, nameof(phone));
Check.NotNullOrWhiteSpace(intent, nameof(intent));
var par = BuildCacheKey(phone, intent);
string vrcode = _cacheService.GetString(par);
if (!vrcode.IsEmpty())
{
_cacheService.Remove(par);
}
AsyncHelper.RunSync(() => _passwordErrorLimitService.RemoveCheck(par, catetory));
}
/// <summary>
/// 短信验证码发送
/// </summary>
/// <returns></returns>
public async Task<string> SendAsync(string phone, string intent)
{
Check.NotNullOrWhiteSpace(phone, nameof(phone));
Check.NotNullOrWhiteSpace(intent, nameof(intent));
var cacheKey = BuildCacheKey(phone, intent);
using (Cache.AcquireLock($"{cacheKey}-a-lock", 5000))//一个手机号限制仅一个请求锁定在最多5秒内发送且只有一次发送
{
{
var num = Cache.GetExpire(cacheKey);
if (num.TotalSeconds > TimeOut - 60)//一个手机号60秒内只能发送一次
{
throw Oops.Bah("请求频繁");
}
}
Random rd = new Random();
var yzm = rd.Next(100000, 999999);
var content = $"【{SmsConst.Sign}】您好,欢迎使用{SmsConst.Sign},您的手机验证码是:{yzm},验证码一分钟内有效,若非本人操作,请忽略!";
/* string vrcode = _cacheService.GetString(par);
if (!vrcode.IsEmpty())
{
throw Oops.Bah("请求频繁");
}*/
var mock = false;
#if DEBUG
if (_environment.IsDevelopment() || _environment.EnvironmentName.StartsWith("MOCK-")) mock = true;//调试模式且开发环境下不真实发送
#endif
if (mock) _logger.LogWarning("mock smscode");
else if (smsOptionsMonitor.CurrentValue.Enable && smsOptionsMonitor.CurrentValue.Include(phone))
{
_logger.LogWarning($"PostWeiXinGroup smscode:{phone}");
await PostWeiXinGroup(phone, content);
}
else await Post(phone, content);
_cacheService.SetString(cacheKey, yzm.ToString(), TimeOut);
AsyncHelper.RunSync(() => _passwordErrorLimitService.RemoveCheck(cacheKey, catetory));
return mock ? yzm.ToString() : null;
}
}
private async Task Post(string phone, string content)
{
if (_logger.IsEnabled(LogLevel.Information))
_logger.LogInformation($"send phone sms code:{phone}");
var data = new {
phone = phone,
Content = HttpUtility.UrlEncode(content)
};
var url = "http://sms.ybhdmob.com/Message/Send?token=ybhdmob";
var request = new HttpRequestMessage(HttpMethod.Post,
url);
string body = data.ToJson();
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
var results = result.ToObject<SMSMODEL>();
if (results is { code: 0 })
{
return;
}
else
{
_logger.LogError("send phone sms fail:{result}", result);
throw Oops.Bah(results?.message);
}
}
else
{
_logger.LogError("send phone sms fail:{response}", response);
throw Oops.Bah("短信发送失败");
}
}
private async Task PostWeiXinGroup(string phone, string content)
{
if (_logger.IsEnabled(LogLevel.Information))
_logger.LogInformation($"send phone sms code:{phone}");
var data = new {
msgtype = "text",
text = new { content = $"模拟短信通道发送 - {phone} {content}" }
};
var url = smsOptionsMonitor.CurrentValue.ApiUrl;
var request = new HttpRequestMessage(HttpMethod.Post,
url);
string body = data.ToJson();
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
var results = result.ToObject<PostWeiXinGroupResult>();
if (results is { errcode: "0" })
{
return;
}
else
{
_logger.LogError("send phone SmsMockChannel fail:{result}", result);
throw Oops.Bah($"模拟短信通道发送失败 {results?.errmsg}");
}
}
else
{
_logger.LogError("send phone SmsMockChannel fail:{response}", response);
throw Oops.Bah("模拟短信通道发送失败");
}
}
public class PostWeiXinGroupResult
{
public string errcode { get; set; }
public string errmsg { get; set; }
}
private static string BuildCacheKey(string mobile, string intent)
{
return $"{SmsConst.YZMPre}{mobile}";
}
}
public class SmsMockChannelOptions
{
public string ApiUrl { get; set; } =
"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=69324091-3f81-42c2-b8ec-08befd101332";
public HashSet<string> Mobile { get; set; }
public bool Enable { get; set; }
public const string SmsMockChannel = "SmsMockChannel";
public bool Include(string mobile)
{
return Mobile != null && Mobile.Contains(mobile);
}
}

View File

@ -0,0 +1,39 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using JT.Shop.Domain.Entity.Business;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JT.Shop.Application.Service.BaseCommon
{
[ApiDescriptionSettings("管理平台")]
[Route("/api/common")]
public class SharesAppService : IDynamicApiController
{
/// <summary>
/// 共享名称。如:店员职位、门店服务、门店产品
/// </summary>
/// <param name="input"></param>
/// <param name="pcShareNameQueryService"></param>
/// <returns></returns>
[HttpGet("share-name")]
[AnyAccountIdentityAuthorize]
public async Task<IEnumerable<PcShareNameDto>> Get([FromQuery] ShareNameSearchInput input, [FromServices] IPcShareNameQueryService pcShareNameQueryService)
{
return await pcShareNameQueryService.Query(input.Type, input.Name, input.Take);
}
}
public class ShareNameSearchInput
{
[Range(1, 500)] public int Take { get; set; } = 10;
public string Name { get; set; }
[Required]
public PcShareNameType Type { get; set; }
}
}

View File

@ -0,0 +1,21 @@
namespace JT.Shop.Application.Upload
{
/// <summary>
/// 文件上传
/// </summary>
public interface IUploadService
{
/// <summary>
/// 图片上传
/// </summary>
/// <param name="input"></param>
Task<UploadS2CDto> UploadImg(UploadC2SDto input);
/// <summary>
/// excel上传
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<UploadS2CDto> UploadExcel(UploadC2SDto input);
}
}

View File

@ -0,0 +1,40 @@
using JT.Shop.Application.Upload;
namespace JT.Shop.Application.Service.BaseCommon.Upload
{
/// <summary>
/// 上传管理
/// </summary>
[ApiDescriptionSettings("管理平台")]
[Route("/api/common")]
[AnyAccountIdentityAuthorize]
public class UploadAppService : IDynamicApiController
{
private readonly IUploadService _uploadService;
public UploadAppService(IUploadService uploadService)
{
_uploadService = uploadService;
}
/// <summary>
/// 图片上传
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<UploadS2CDto> UploadImg([FromForm] UploadC2SDto input)
{
return await _uploadService.UploadImg(input);
}
/// <summary>
/// excel上传
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<UploadS2CDto> UploadExcel([FromForm] UploadC2SDto input)
{
return await _uploadService.UploadExcel(input);
}
}
}

View File

@ -0,0 +1,232 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Volo.Abp.DependencyInjection;
using FormOptions = Microsoft.AspNetCore.Http.Features.FormOptions;
namespace JT.Shop.Application.Upload
{
/// <summary>
/// 文件上传
/// </summary>
public class UploadService : IUploadService, ITransient
{
private static readonly FormOptions _defaultFormOptions = new FormOptions();
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserManager UserInfo;
private readonly UploadDomainService uploadDomainService;
public UploadService(IHttpContextAccessor httpContextAccessor,
UserManager userInfo, UploadDomainService uploadDomainService)
{
_httpContextAccessor = httpContextAccessor;
UserInfo = userInfo;
this.uploadDomainService = uploadDomainService;
}
/// <summary>
/// 图片上传
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<UploadS2CDto> UploadImg(UploadC2SDto input)
{
var currentUser = UserInfo.GetCurrentUserInfo();
var Request = _httpContextAccessor.HttpContext.Request;
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
{
throw Oops.Bah("只支持multipart/form-data类型");
}
var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, Request.Body);
var section = await reader.ReadNextSectionAsync();
List<string> filelist = new List<string>();
while (section != null)
{
var hasContentDispositionHeader =
ContentDispositionHeaderValue.TryParse(
section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader)
{
if (!MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
{
}
else
{
string[] _permittedExtensions = { ".gif", ".jpg", ".jpeg", ".png", ".bmp" };
long _fileSizeLimit = 1048576 * 5;
string rootname = string.Empty;
if (input.uploadpath.IsEmpty())
{
rootname = $"/uploadfile/{input.root}/{DateTime.Now.ToString("yyyyMMdd")}";
}
else
{
rootname = $"/uploadfile/{input.root}/{input.uploadpath}";
}
string savefolder = uploadDomainService.GetUploadPhysicalRootPath();
if (!Path.Exists(savefolder))
{
throw new Exception($"上传根目录【{savefolder}】不存在");
}
string name = string.Empty;
if (input.filename.IsEmpty())
{
name = Path.GetRandomFileName() + ".jpg";
}
else
{
name = $"{input.filename}.jpg";
}
Dictionary<string, string> dict = new Dictionary<string, string>();
var streamedFileContent = await FileHelpers.ProcessStreamedFile(
section, contentDisposition, dict,
_permittedExtensions, _fileSizeLimit);
if (dict.ContainsKey("File"))
{
string msg = dict.GetValueOrDefault("File");
throw Oops.Bah(msg);
}
var thumbnailPath = Path.Combine(savefolder + "/" + rootname);
if (!Directory.Exists(Path.GetDirectoryName(thumbnailPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(thumbnailPath));
}
var filepath = Path.Combine(thumbnailPath + "/", name);
var virualpath = Path.Combine(rootname + "/", name);
var filename = contentDisposition.FileName.Value;
using (var targetStream = File.Create(filepath))
{
await targetStream.WriteAsync(streamedFileContent);
filelist.Add(virualpath);
}
return new UploadS2CDto
{
path = virualpath,
Url = virualpath.ImgFile()
};
}
}
section = await reader.ReadNextSectionAsync();
}
return null;
}
/// <summary>
/// excel上传
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<UploadS2CDto> UploadExcel(UploadC2SDto input)
{
var currentUser = UserInfo.GetCurrentUserInfo();
var Request = _httpContextAccessor.HttpContext.Request;
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
{
throw Oops.Bah("只支持multipart/form-data类型");
}
var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, Request.Body);
var section = await reader.ReadNextSectionAsync();
List<string> filelist = new List<string>();
while (section != null)
{
var hasContentDispositionHeader =
ContentDispositionHeaderValue.TryParse(
section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader)
{
if (!MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
{
}
else
{
string[] _permittedExtensions = { ".xsl", ".xlsx" };
long _fileSizeLimit = 1048576 * 5;
string rootname = string.Empty;
if (input.uploadpath.IsEmpty())
{
rootname = $"/uploadfile/{input.root}/{DateTime.Now.ToString("yyyyMMdd")}";
}
else
{
rootname = $"/{input.uploadpath}/{input.root}";
}
string savefolder = uploadDomainService.GetUploadPhysicalRootPath();
if (!Path.Exists(savefolder))
{
throw new Exception($"上传根目录【{savefolder}】不存在");
}
string name = string.Empty;
if (input.filename.IsEmpty())
{
name = Path.GetRandomFileName() + ".xlsx";
}
else
{
name = $"{input.filename}.xlsx";
}
Dictionary<string, string> dict = new Dictionary<string, string>();
var streamedFileContent = await FileHelpers.ProcessStreamedFile(
section, contentDisposition, dict,
_permittedExtensions, _fileSizeLimit);
if (dict.ContainsKey("File"))
{
string msg = dict.GetValueOrDefault("File");
throw Oops.Bah(msg);
}
var thumbnailPath = Path.Combine(savefolder + "/" + rootname, name);
if (!Directory.Exists(Path.GetDirectoryName(thumbnailPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(thumbnailPath));
}
var filepath = Path.Combine(thumbnailPath + "/", name);
var virualpath = Path.Combine(rootname + "/", name);
var filename = contentDisposition.FileName.Value;
using (var targetStream = File.Create(filepath))
{
await targetStream.WriteAsync(streamedFileContent);
filelist.Add(virualpath);
}
return new UploadS2CDto
{
path = virualpath,
Url = CommonService.File(virualpath)
};
}
}
section = await reader.ReadNextSectionAsync();
}
return null;
}
}
public class UploadOptions
{
public const string Upload = "Upload";
public string PhysicalPath { get; set; } = String.Empty;
}
public class UploadDomainService : ISingletonDependency
{
private readonly UploadOptions _uploadOptions;
private readonly IWebHostEnvironment _hostingEnvironment;
public UploadDomainService(IOptions<UploadOptions> uploadOptions, IWebHostEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
_uploadOptions = uploadOptions.Value;
}
public string GetUploadPhysicalRootPath()
{
return string.IsNullOrWhiteSpace(_uploadOptions.PhysicalPath)
? _hostingEnvironment.WebRootPath
: _uploadOptions.PhysicalPath;
}
}
}

View File

@ -0,0 +1,142 @@
using JT.Shop.Application.Service.Mch.Body;
using JT.Shop.Application.Service.ShopHead;
using JT.Shop.Domain.FeatureDefinitions.ShopHead;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Features;
using Volo.Abp.Localization;
namespace JT.Shop.Application.Service.Business.BodyType
{
/// <summary>
/// 身体部位管理
/// </summary>
[ApiDescriptionSettings("总部")]
[Route("/api/business/[controller]")]
public class BodyService : ITransient, IDynamicApiController
{
private readonly IRepository<PC_ShopBodyType> _bodyTypeRepository;
private readonly IRepository<PC_ShopBody> _bodyRepository;
private readonly IRepository<PC_BusinessBody> _businessBodyRepository;
private readonly UserManager _userManager;
public BodyService(
IRepository<PC_ShopBodyType> bodyTypeRepository,
IRepository<PC_ShopBody> bodyRepository,
UserManager userManager,
IRepository<PC_BusinessBody> businessBodyRepository
)
{
_bodyTypeRepository = bodyTypeRepository;
_bodyRepository = bodyRepository;
_userManager = userManager;
_businessBodyRepository = businessBodyRepository;
}
#region -
/// <summary>
/// 获取总部关联的身体部位列表
/// </summary>
/// <returns></returns>
[HttpPost("BusinessBodyList")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfBodyPermissionDefinitionProvider.ViewName)]
public async Task<List<ShopBodyTypeListOutput>> ListAsync()
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
//获取身体部位类型列表
var typelist = await _bodyTypeRepository.DetachedEntities.Where(x => x.Status == CommonStatus.Enable).OrderBy(x => x.SortCode).ToListAsync();
//获取身体部位列表
var bodylist = await _bodyRepository.DetachedEntities.Where(x => x.Status == CommonStatus.Enable).ToListAsync();
//获取总部关联的身体部位
var shopBodyRelList = await _businessBodyRepository.DetachedEntities.Where(x => x.BusinessId == CurrentUser.ShopHeadId).ToListAsync();
var returnlist = new List<ShopBodyTypeListOutput>();
typelist.ForEach(x =>
{
var bodylistoutput = new ShopBodyTypeListOutput
{
TypeId = x.Id,
TypeName = x.Name,
List = new List<ShopBodyListOutput>()
};
var blist = bodylist.Where(y => y.TypeId == x.Id).ToList();
blist.ForEach(y =>
{
var rel = shopBodyRelList.FirstOrDefault(z => z.BodyId == y.Id);
var bodyoutput = new ShopBodyListOutput
{
Id = y.Id,
Name = y.Name,
TypeId = y.TypeId,
IsChecked = !rel.IsEmpty()
};
bodylistoutput.List.Add(bodyoutput);
});
returnlist.Add(bodylistoutput);
});
return returnlist;
}
/// <summary>
/// 总部身体部位信息绑定
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("BusinessBodySubmit")]
[UnitOfWork(true)]
[OpAudit("编辑", "部位管理", OpAuditLogEventTarget.Head)]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfBodyPermissionDefinitionProvider.EditName)]
public async Task SubmitAsync(ShopBodySubmitInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
//先删除绑定的
await _businessBodyRepository.Where(x => x.BusinessId == CurrentUser.ShopHeadId).DeleteAsync();
if (input.ids.IsEmpty())
{
return;
}
//新增
var insertlist = new List<PC_BusinessBody>();
input.ids.ForEach(x =>
{
insertlist.Add(new PC_BusinessBody
{
Id = YitIdHelper.NextId(),
BodyId = x,
BusinessId = CurrentUser.ShopHeadId
});
});
await _businessBodyRepository.InsertAsync(insertlist);
}
#endregion -
}
public class ShopHeadOfBodyPermissionDefinitionProvider : PermissionDefinitionProvider
{
public const string GroupName = $"{ShopHeadPermissionDefinitionNames.Prefix}.bodymag";
public const string ViewName = $"{GroupName}.view";
public const string EditName = $"{GroupName}.edit";
public override void Define(IPermissionDefinitionContext context)
{
{
var groups = context.AddGroup($"{GroupName}", new FixedLocalizableString("部位配置"));
groups.AddPermission($"{ViewName}", new FixedLocalizableString("查看"));
groups.AddPermission($"{EditName}", new FixedLocalizableString("修改"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopHeadOfBodyFeatureDefinitionProvider.EditName);
}
}
}
}

View File

@ -0,0 +1,82 @@
namespace JT.Shop.Application.Service.Business.BodyType
{
/// <summary>
/// 提交身体部位类型
/// </summary>
public class SubmitBodyTypeInput : BaseNullId
{
/// <summary>
/// 类型名称
/// </summary>
[MaxLength(50, ErrorMessage = "类型名称最多50个字")]
[Required(ErrorMessage = "类型名称不可为空")]
public string Name { get; set; }
/// <summary>
/// 类型描述
/// </summary>
[MaxLength(200, ErrorMessage = "类型描述最多200个字")]
public string Description { get; set; }
/// <summary>
/// 类型图片
/// </summary>
[MaxLength(200, ErrorMessage = "类型图片最多200个字")]
[Required(ErrorMessage = "类型图片不可为空")]
public string Image { get; set; }
/// <summary>
/// 排序
/// </summary>
public int SortCode { get; set; }
}
/// <summary>
/// 提交身体部位
/// </summary>
public class SubmitBodyInput : BaseNullId, IValidatableObject
{
/// <summary>
/// 部位名称
/// </summary>
[MaxLength(50, ErrorMessage = "部位名称最多50个字")]
[Required(ErrorMessage = "部位名称不可为空")]
public string Name { get; set; }
/// <summary>
/// 部位描述
/// </summary>
[MaxLength(200, ErrorMessage = "部位描述最多200个字")]
public string Description { get; set; }
/// <summary>
/// 所属类型ID
/// </summary>
public long TypeId { get; set; }
/// <summary>
/// 部位图片
/// </summary>
[MaxLength(200, ErrorMessage = "部位图片最多200个字")]
//[Required(ErrorMessage = "部位图片不可为空")]
public string Image { get; set; }
/// <summary>
/// 排序
/// </summary>
public int SortCode { get; set; }
/// <summary>
///
/// </summary>
/// <param name="validationContext"></param>
/// <returns></returns>
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (TypeId <= 0)
{
yield return new ValidationResult("请选择部位类型", new[] { nameof(TypeId) });
}
}
}
}

View File

@ -0,0 +1,99 @@
namespace JT.Shop.Application.Service.Business.BodyType
{
/// <summary>
/// 身体部位列表
/// </summary>
public class BodyListOutput : BaseId
{
/// <summary>
/// 部位名称
/// </summary>
[Comment("部位名称")]
[MaxLength(50)]
[Required]
public string Name { get; set; }
/// <summary>
/// 所属类型ID
/// </summary>
[Comment("所属类型ID")]
public long TypeId { get; set; }
/// <summary>
/// 类型名称
/// </summary>
public string TypeName { get; set; }
/// <summary>
/// 部位描述
/// </summary>
[Comment("部位描述")]
[MaxLength(200)]
[Required]
public string Description { get; set; }
/// <summary>
/// 部位图片
/// </summary>
[Comment("部位图片")]
[MaxLength(200)]
[Required]
public string Image { get; set; }
/// <summary>
/// 排序
/// </summary>
[Comment("排序")]
public int SortCode { get; set; }
/// <summary>
/// 状态
/// </summary>
[Comment("状态")]
public CommonStatus Status { get; set; }
}
/// <summary>
/// 身体部位类型列表
/// </summary>
public class BodyTypeListOutput : BaseId
{
/// <summary>
/// 类型名称
/// </summary>
[Comment("类型名称")]
[MaxLength(50)]
[Required]
public string Name { get; set; }
/// <summary>
/// 类型描述
/// </summary>
[Comment("类型描述")]
[MaxLength(200)]
[Required]
public string Description { get; set; }
/// <summary>
/// 类型图片
/// </summary>
[Comment("类型图片")]
[MaxLength(200)]
[Required]
public string Image { get; set; }
public string ImageUrl => Image.ImgFile();
/// <summary>
/// 排序
/// </summary>
[Comment("排序")]
public int SortCode { get; set; }
/// <summary>
/// 状态
/// </summary>
[Comment("状态")]
public CommonStatus Status { get; set; }
}
}

View File

@ -0,0 +1,249 @@
using JT.Shop.Application.Service.Mch.Clerk;
using JT.Shop.Application.Service.Shop.Colleague;
using JT.Shop.Application.Service.ShopHead;
using JT.Shop.Core;
using JT.Shop.Domain.Entity.ShopHead;
using JT.Shop.Domain.FeatureDefinitions.ShopHead;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Features;
using Volo.Abp.Localization;
namespace JT.Shop.Application.Service.Business.Clerk
{
/// <summary>
/// 总部之店员管理
/// </summary>
[ApiDescriptionSettings("总部")]
[Route("/api/business/[controller]")]
public class ClerkService(
UserManager User,
PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService,
OpAuditContext opAuditContext,
IRepository<PC_ShopPos> shopposRep,
IRepository<PC_Shop> shopRep,
IPcShopAccountQueryService shopAccountQueryService,
IPcShopHeadQueryService shopheadQueryService)
: ITransient, IDynamicApiController
{
/// <summary>
/// 店员列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopColleagueAccountPermissionDefinitionProvider.ViewName)]
public async Task<BusinessClerkListOutput> ListAsync(BusinessClerkListInput input)
{
var CurrentUser = User.GetCurrentShopHeadInfo();
/* var list = await _shopAccountRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(!input.Name.IsEmpty(), x => x.Name.Contains(input.Name) || x.Phone.Contains(input.Name) *//*|| x.Account.Contains(input.Name)*//*)
.Where(input.Status != 0, x => x.Status == input.Status)
.OrderByDescending(x => x.CreatedTime)
.ProjectToType<BusinessClerkListOutput>()
.ToADPagedListAsync(input.PageNo, input.PageSize);*/
var list = (await shopAccountQueryService.GetAllChildList(CurrentUser.ShopHeadId, input.ChildParentHeadId, input.ShopId, input.Code, input.Name,
input.Phone, input.Status, input.PosShareNameId, input.CreateTimeRange, input)).Adapt<BusinessClerkListOutput>();
var allposids = list.Rows.Select(x => x.PosId).ToHashSet();
var poslist = await shopposRep.DetachedEntities.Where(x => allposids.Contains(x.Id)).ToListAsync();
var uids = list.Rows.Select(x => x.BusinessId).ToList();
var users = await shopheadQueryService.Get(uids.ToHashSet());
var sids = list.Rows.Select(x => x.ShopId).ToHashSet();
var shops = await shopRep.DetachedEntities.Where(x => sids.Contains(x.Id))
.Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
list.Rows.ToList().ForEach(it =>
{
var pos = poslist.FirstOrDefault(x => x.Id == it.PosId);
if (pos != null)
{
it.PosName = pos.Name;
}
if (users.TryGetValue(it.BusinessId, out var head))
{
it.BusinessName = head.Name;
it.BusinessCode = head.Code;
}
var shop = shops.Where(x => x.Id == it.ShopId).FirstOrDefault();
if (shop != null)
{
it.ShopName = shop.Name;
}
});
return list;
}
public class ShopHeadOfShopAccountAddInput : ShopAccountAppService.ShopAccountAddInput
{
public long ShopId { get; set; }
}
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopColleagueAccountPermissionDefinitionProvider.AddName)]
[HttpPost("add")]
[OpAudit("添加成员", "门店", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task<long> Add([FromBody] ShopHeadOfShopAccountAddInput input, [FromServices] ShopAccountAppService service)
{
var shop = (await shopRep.DetachedEntities.FirstOrDefaultAsync(x => x.Id == input.ShopId)) ?? throw Oops.Bah(PC_SHOP_ERROR_CODE.SHOP_NOTFOUND40004).WithData(input.ShopId);
await pcHeadLevelChildCheckDomainService.InChildShopCheck(shop.BusinessId, User.GetCurrentShopHeadInfo().ShopHeadId);
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(input.ShopId, OpAuditLogEventTarget.Shop));
return await service.Add(input, input.ShopId, shop.BusinessId);
}
public class ShopHeadOfShopAccountEditInput : ShopAccountAppService.ShopAccountEditInput
{
public long ShopId { get; set; }
}
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopColleagueAccountPermissionDefinitionProvider.EditName)]
[HttpPost("edit")]
[OpAudit("编辑成员", "门店", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task Edit([FromBody] ShopHeadOfShopAccountEditInput input, [FromServices] ShopAccountAppService service)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
User.GetCurrentShopHeadInfo().ShopHeadId);
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(input.ShopId, OpAuditLogEventTarget.Shop));
await service.Edit(input, input.ShopId);
}
public class ShopHeadOfShopAccountChangeGeneralAccountInput : ShopAccountAppService.ShopAccountChangeGeneralAccountInput
{
public long ShopId { get; set; }
}
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopColleagueAccountPermissionDefinitionProvider.EditName)]
[HttpPost("change-general-account")]
[OpAudit("更换通用绑定账号", "店员", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task ChangeGeneralAccount([FromBody] ShopHeadOfShopAccountChangeGeneralAccountInput input, [FromServices] ShopAccountAppService service)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
User.GetCurrentShopHeadInfo().ShopHeadId);
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(input.ShopId, OpAuditLogEventTarget.Shop));
await service.ChangeGeneralAccount(input, input.ShopId);
}
public class ShopHeadOfShopAccountDelInput : ShopAccountAppService.ShopAccountDelInput
{
}
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopColleagueAccountPermissionDefinitionProvider.DelName)]
[HttpPost("del")]
[OpAudit("删除成员", "门店", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task Del([FromBody] ShopHeadOfShopAccountDelInput inputs, [FromServices] ShopAccountAppService service)
{
foreach (var input in inputs.Items)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
User.GetCurrentShopHeadInfo().ShopHeadId);
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(input.ShopId, OpAuditLogEventTarget.Shop));
await service.Del(input.Id, input.ShopId, input.Type);
}
}
/* [ShopHeadSystemBusinessVersionAuthorize(ShopOfColleagueAccountPermissionDefinitionProvider.EditName)]
[HttpPost("change")]
[UnitOfWork(true)]
public async Task<long> ChangeSuper([FromBody] ShopAccountAppService.ShopAccountAddInput input, [FromServices] ShopAccountAppService service)
{
if (input.Type == AdminType.SuperAdmin) user.CheckSuperAdmin();
if (user.UserId == input.AccountId) throw Oops.Bah("更换的还是同一个账号").WithData(input.AccountId);
await service.Del(user.UserId, user.GetCurrentShopInfo().ShopId, input.Type);
return await service.Add(input, user.GetCurrentShopInfo().ShopId, input.Type);
}*/
/// <summary>
/// 启用
/// </summary>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopColleagueAccountPermissionDefinitionProvider.EnableName)]
[HttpPost("enable")]
[OpAudit("启用成员", "门店", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task Enable([FromBody] ShopHeadOfShopAccountDelInput inputs, [FromServices] ShopAccountAppService service)
{
foreach (var input in inputs.Items)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
User.GetCurrentShopHeadInfo().ShopHeadId);
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(input.ShopId, OpAuditLogEventTarget.Shop));
await service.Enable(input.Id, input.ShopId, input.Type);
}
}
/// <summary>
/// 禁用
/// </summary>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopColleagueAccountPermissionDefinitionProvider.DisableName)]
[OpAudit("禁用成员", "门店", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task Disable([FromBody] ShopHeadOfShopAccountDelInput inputs, [FromServices] ShopAccountAppService service)
{
foreach (var input in inputs.Items)
{
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(input.ShopId, OpAuditLogEventTarget.Shop));
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
User.GetCurrentShopHeadInfo().ShopHeadId);
await service.Disable(input.Id, input.ShopId, input.Type);
}
}
}
public class ShopHeadOfShopColleagueAccountPermissionDefinitionProvider : PermissionDefinitionProvider
{
public const string GroupName = $"{ShopHeadFeatureDefinitionNames.Prefix}.shop.colleague.account";
public const string ViewName = $"{GroupName}.view";
public const string AddName = $"{GroupName}.add";
public const string DelName = $"{GroupName}.del";
public const string EditName = $"{GroupName}.edit";
public const string EnableName = $"{GroupName}.enable";
public const string DisableName = $"{GroupName}.disable";
public override void Define(IPermissionDefinitionContext context)
{
{
var groups = context.AddGroup($"{GroupName}", new FixedLocalizableString("店员"));
groups.AddPermission($"{ViewName}", new FixedLocalizableString("查看店员"))
.RequireFeatures(ShopHeadOfShopColleagueAccountFeatureDefinitionProvider.ViewName);
groups.AddPermission($"{AddName}", new FixedLocalizableString("添加"));
groups.AddPermission($"{EditName}", new FixedLocalizableString("编辑"));
groups.AddPermission($"{DelName}", new FixedLocalizableString("删除"));
groups.AddPermission($"{EnableName}", new FixedLocalizableString("启用"));
groups.AddPermission($"{DisableName}", new FixedLocalizableString("禁用"));
}
}
}
}

View File

@ -0,0 +1,42 @@
namespace JT.Shop.Application.Service.Business.Clerk
{
/// <summary>
/// 店员列表
/// </summary>
public class BusinessClerkListInput : PageInputV2Base
{
/// <summary>
/// 创建时间范围
/// </summary>
public DateRangeFilterInput CreateTimeRange { get; set; }
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/// <summary>
/// 店员名称
/// </summary>
public string Code { get; set; }
/// <summary>
/// 店员名称
/// </summary>
public string Name { get; set; }
public string Phone { get; set; }
public HashSet<long> PosShareNameId { get; set; }
/// <summary>
///状态
/// </summary>
public CommonStatus? Status { get; set; }
}
/// <summary>
/// 职位列表
/// </summary>
public class BusinessPostListInput : PageInputBase
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
}
}

View File

@ -0,0 +1,104 @@
using JT.Shop.Core;
namespace JT.Shop.Application.Service.Business.Clerk
{
/// <summary>
/// 店员列表
/// </summary>
public class BusinessClerkListItemOutput : BaseIdAndUserInfo
{
public AdminType AdminType { get; set; }
/// <summary>
/// 账号
/// </summary>
public string Account { get; set; }
public long AccountId { get; set; }
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 头像URL
/// </summary>
public string AvatarUrl { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string Phone { get; set; }
public string Mobile { get; set; }
/// <summary>
/// 编号
/// </summary>
public string Code { get; set; }
/// <summary>
/// 性别
/// </summary>
public Gender Sex { get; set; }
/// <summary>
/// 出生年月
/// </summary>
public string BirthDay { get; set; }
/// <summary>
/// 状态
/// </summary>
public CommonStatus Status { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedTime { get; set; }
/// <summary>
/// 职位ID
/// </summary>
public long PosId { get; set; }
/// <summary>
/// 职位名称
/// </summary>
public string PosName { get; set; }
}
public class BusinessClerkListOutput: PageResultV2<BusinessClerkListItemOutput>
{
}
/// <summary>
/// 职位列表
/// </summary>
public class BusinessPostListOutput : BaseIdAndUserInfo
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
}

View File

@ -0,0 +1,666 @@
using JT.Shop.Application.Service.BaseCommon;
using JT.Shop.Application.Service.ShopApi.Device;
using JT.Shop.Application.Service.ShopHead;
using JT.Shop.Domain.Entity.Business;
using JT.Shop.Domain.Entity.ShopHead;
using JT.Shop.Domain.FeatureDefinitions.ShopHead;
using Microsoft.AspNetCore.Authorization;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.Threading;
namespace JT.Shop.Application.Service.Business.Device
{
/// <summary>
/// 设备管理
/// </summary>
[ApiDescriptionSettings("总部")]
[Route("/api/business/[controller]")]
public class DeviceService(DeviceAppService appService, UserManager UserInfo, IRepository<PC_DeviceAlloc> _deviceAllocRep, OpAuditContext opAuditContext, PcHeadLevelChildCheckDomainService headLevelChildCheckDomainService, IRepository<PC_Shop> _shopRep, IRepository<PcHead> headRepository, IPcDeviceQueryService pdPcDeviceQueryService, IPcShopHeadQueryService pcShopHeadQueryService, IRepository<PC_Device_Url> _pcDeviceUrl) : ITransient, IDynamicApiController
{
/// <summary>
/// 设备分配给总部
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork(true)]
[OpAudit("分配给下级总部", "设备", OpAuditLogEventTarget.Head)]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.AllocToHeadName)]
public async Task AllocToHeadAsync(DeviceAllocC2SToShopHeadDto input)
{
var CurrentUser = UserInfo.GetCurrentAdminShopInfo();
var entity = await headRepository.DetachedEntities.Where(x => x.Id == input.BusinessId).FirstOrDefaultAsync();
if (entity == null) throw Oops.Bah("下级总部不存在").WithData(input.BusinessId);
await headLevelChildCheckDomainService.InChildHeadCheck(input.BusinessId, CurrentUser.ShopHeadId);
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(input.BusinessId, OpAuditLogEventTarget.Head));
await appService.AllocAsync(input.ids, 0, input.BusinessId, true, remark: "分配给下级总部");
/*if (!await _sysuserRep.DetachedEntities.AnyAsync(x => x.Id == input.BusinessId))
{
throw Oops.Bah("总部不存在");
}
//记录设备分配记录
var alloclist = await _deviceRep.DetachedEntities.Where(x => input.ids.Contains(x.Id)).Select(x => new PC_DeviceAlloc
{
IsShowBusiness = CurrentUser.AccountType == AdminType.None,
CreatedTime = DateTime.Now,
CreatedUserId = CurrentUser.UserId,
CreatedUserName = CurrentUser.Name,
DeviceId = x.Id,
FromBusinessId = x.BusinessId,
FromShopId = x.ShopId,
Remark = string.Empty,
ToBusinessId = input.BusinessId,
ToShopId = input.ShopId,
Type = DeviceAllocType.ALLOC
}).ToListAsync();
alloclist.ForEach(it =>
{
it.Id = YitIdHelper.NextId();
});
if (!alloclist.IsEmpty())
{
await _deviceAllocRep.InsertAsync(alloclist);
}
// 更新设备所属的客户ID和门店ID
await _deviceRep.Where(x => input.ids.Contains(x.Id)).UpdateAsync(x => new PC_Device
{
BusinessId = input.BusinessId,
ShopId = input.ShopId,
UpdatedTime = DateTime.Now,
UpdatedUserId = CurrentUser.UserId,
UpdatedUserName = CurrentUser.Name
});*/
}
/// <summary>
/// 设备分配
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork(true)]
[OpAudit("分配给门店", "设备", OpAuditLogEventTarget.Head)]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.AllocToShopName)]
public async Task AllocToShopAsync(DeviceAllocC2SToShopDto input)
{
var CurrentUser = UserInfo.GetCurrentAdminShopInfo();
var entity = await _shopRep.DetachedEntities.Where(x => x.Id == input.ShopId).FirstOrDefaultAsync();
if (entity == null) throw Oops.Bah("门店不存在").WithData(input.ShopId);
await headLevelChildCheckDomainService.InChildShopCheck(entity.BusinessId, CurrentUser.ShopHeadId);
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(input.ShopId, OpAuditLogEventTarget.Shop));
await appService.AllocAsync(input.ids, input.ShopId, entity.BusinessId, true, remark: "分配给门店");
/*if (!await _shopRep.DetachedEntities.AnyAsync(x => x.Id == input.ShopId))
{
throw Oops.Bah("门店不存在");
}
if (!await _sysuserRep.DetachedEntities.AnyAsync(x => x.Id == input.BusinessId))
{
throw Oops.Bah("总部不存在");
}
//记录设备分配记录
var alloclist = await _deviceRep.DetachedEntities.Where(x => input.ids.Contains(x.Id)).Select(x => new PC_DeviceAlloc
{
IsShowBusiness = CurrentUser.AccountType == AdminType.None,
CreatedTime = DateTime.Now,
CreatedUserId = CurrentUser.UserId,
CreatedUserName = CurrentUser.Name,
DeviceId = x.Id,
FromBusinessId = x.BusinessId,
FromShopId = x.ShopId,
Remark = string.Empty,
ToBusinessId = input.BusinessId,
ToShopId = input.ShopId,
Type = DeviceAllocType.ALLOC
}).ToListAsync();
alloclist.ForEach(it =>
{
it.Id = YitIdHelper.NextId();
});
if (!alloclist.IsEmpty())
{
await _deviceAllocRep.InsertAsync(alloclist);
}
// 更新设备所属的客户ID和门店ID
await _deviceRep.Where(x => input.ids.Contains(x.Id)).UpdateAsync(x => new PC_Device
{
BusinessId = input.BusinessId,
Status = DeviceStatus.Run,
ShopId = input.ShopId,
UpdatedTime = DateTime.Now,
UpdatedUserId = CurrentUser.UserId,
UpdatedUserName = CurrentUser.Name
});*/
}
/// <summary>
/// 查询设备分配记录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.ViewName)]
public async Task<List<DeviceAllocListSCDto>> AllocListAsync(BaseId input)
{
var CurrentUser = UserInfo.GetCurrentAdminShopInfo();
return await appService.AllocListAsync(input, true);
/* var list = await _deviceAllocRep.DetachedEntities
.Where(x => x.DeviceId == input.Id)
.Where(CurrentUser.AccountType == AdminType.None, x => x.IsShowBusiness == true)
.OrderByDescending(x => x.CreatedTime).ProjectToType<DeviceAllocListSCDto>().ToListAsync();
List<long> bids = new List<long>();
List<long> shopids = new List<long>();
foreach (var item in list)
{
if (!bids.Contains(item.FromBusinessId))
{
bids.Add(item.FromBusinessId);
}
if (!bids.Contains(item.ToBusinessId))
{
bids.Add(item.ToBusinessId);
}
if (!shopids.Contains(item.FromShopId))
{
shopids.Add(item.FromShopId);
}
if (!shopids.Contains(item.ToShopId))
{
shopids.Add(item.ToShopId);
}
}
var allbuss = await _sysuserRep.DetachedEntities.Where(x => bids.Contains(x.Id))
.Select(x => new SysUser
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
var allshop = await _shopRep.DetachedEntities.Where(x => shopids.Contains(x.Id)).Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
}).ToListAsync();
list.ForEach(it =>
{
var buss = allbuss.FirstOrDefault(x => x.Id == it.FromBusinessId);
it.FromBusiness = buss != null ? buss.Name : "";
buss = allbuss.FirstOrDefault(x => x.Id == it.ToBusinessId);
it.ToBusiness = buss != null ? buss.Name : "";
var shop = allshop.FirstOrDefault(x => x.Id == it.FromShopId);
it.FromShop = shop != null ? shop.Name : "";
shop = allshop.FirstOrDefault(x => x.Id == it.ToShopId);
it.ToShop = shop != null ? shop.Name : "";
});
return list;*/
}
/// <summary>
/// 获取设备列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AllowAnonymous]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.ViewName)]
public async Task<DeviceListS2CDto> ListAsync(DeviceListC2SDto input, [FromServices] PCShopSettingProvider pcShopSettingProvider)
{
var CurrentUser = UserInfo.GetCurrentAdminShopInfo();
var list = /*await _deviceRep.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(CurrentUser.AccountType == AdminType.None, x => _deviceAllocRep.DetachedEntities.Where(e => e.ToBusinessId == CurrentUser.UserId && e.Type != DeviceAllocType.RETURN && e.DeviceId == x.Id).Any()
|| x.BusinessId == CurrentUser.ShopHeadId
)
.Where(!input.ECode.IsEmpty(), x => x.Ecode == input.ECode)
.Where(input.Status != 0, x => x.Status == input.Status)
.Where(input.DevType > 0, x => x.Type == input.DevType)
.OrderByDescending(x => x.CreatedTime)
.ProjectToType<DeviceListS2CDto>()
.ToADPagedListAsync(input.PageNo, input.PageSize)*/(await pdPcDeviceQueryService.GetAllChildList(CurrentUser.ShopHeadId, input.ChildParentHeadId, input.ShopId, input.Status, input.DevType, input.ECode, input.FacCode, input.Search, input)).Adapt<DeviceListS2CDto>();
//if (CurrentUser.AccountType != AdminType.None)
{
var alluserid = list.Rows.Select(x => x.BusinessId).ToHashSet();
var alluser = await pcShopHeadQueryService.Get(alluserid) /* await _sysuserRep.GetAllNoFilterAsync(x => alluserid.Contains(x.Id), x => new SysUser
{
Id = x.Id,
Name = x.Name
})*/;
var allshopid = list.Rows.Select(x => x.ShopId).ToList();
var allshop = await _shopRep.DetachedEntities.Where(x => allshopid.Contains(x.Id)).Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
}).ToListAsync();
list.Rows.ToList().ForEach(it =>
{
//var user = alluser.FirstOrDefault(x => x.Id == it.BusinessId);
if (alluser.TryGetValue(it.BusinessId, out var user))
{
it.BusinessName = user.Name;
it.BusinessCode = user.Code;
}
var shop = allshop.FirstOrDefault(x => x.Id == it.ShopId);
if (!shop.IsEmpty())
{
it.ShopName = shop.Name;
}
it.Url = (AsyncHelper.RunSync(() => pcShopSettingProvider.GetWXClientType(it.ShopId))).DeviceEntryUrl(it.Id);
});
}
/* else if (CurrentUser.AccountType == AdminType.None)
{
var alluserid = list.Rows.Select(x => x.BusinessId).ToList();
var alluser = await _sysuserRep.GetAllNoFilterAsync(x => alluserid.Contains(x.Id), x => new SysUser
{
Id = x.Id,
Name = x.Name
});
var allshopid = list.Rows.Select(x => x.ShopId).ToList();
var allshop = await _shopRep.DetachedEntities.Where(x => allshopid.Contains(x.Id)).Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
}).ToListAsync();
list.Rows.ToList().ForEach(it =>
{
var user = alluser.FirstOrDefault(x => x.Id == it.BusinessId);
if (!user.IsEmpty())
{
it.BusinessName = user.Name;
}
var shop = allshop.FirstOrDefault(x => x.Id == it.ShopId);
if (!shop.IsEmpty())
{
it.ShopName = shop.Name;
}
});
}*/
//设备二维码跳转小程序
try
{
var urlList = await _pcDeviceUrl.DetachedEntities.ToListAsync();
if (urlList.Any())
{
list.Rows.ToList().ForEach(it =>
{
var info = urlList.Where(s => s.DeviceId == it.Id).FirstOrDefault();
if (info != null)
{
it.Url = info.Url;
}
});
}
}
catch (Exception e)
{
}
return list;
}
/// <summary>
/// 设备从门店回收
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork(true)]
[OpAudit("从门店回收", "设备", OpAuditLogEventTarget.Head)]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.RecycleFromShopName)]
public async Task RecycleFromShopAsync(DeviceRecycleC2SDto input)
{
var CurrentUser = UserInfo.GetCurrentAdminShopInfo();
await appService.RecycleAsync(input, ToBusinessId: CurrentUser.BusinessId, IsShowBusiness: true,
async d =>
{
if (d.FromShopId == 0 /*&& d.FromBusinessId == CurrentUser.ShopHeadId*/)
{
throw Oops.Bah("重复回收").WithData(new { d.Id });
}
await headLevelChildCheckDomainService.InChildShopCheck(d.FromBusinessId, CurrentUser.ShopHeadId);
if (d.FromShopId > 0)//如果已分配给门店
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(d.FromShopId, OpAuditLogEventTarget.Shop));
//else if (d.FromBusinessId != CurrentUser.ShopHeadId)//如果已分配给其他总部
// opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(d.FromBusinessId, OpAuditLogEventTarget.Head));
}, remark: "总部回收");
/*var userid = CurrentUser.AccountType == AdminType.None ? CurrentUser.UserId : 0;
//记录设备分配记录
var alloclist = await _deviceRep.DetachedEntities.Where(x => input.ids.Contains(x.Id)).Select(x => new PC_DeviceAlloc
{
IsShowBusiness = CurrentUser.AccountType == AdminType.None ? true : false,
CreatedTime = DateTime.Now,
CreatedUserId = CurrentUser.UserId,
CreatedUserName = CurrentUser.Name,
DeviceId = x.Id,
FromBusinessId = x.BusinessId,
FromShopId = x.ShopId,
Remark = string.Empty,
ToBusinessId = userid,
ToShopId = 0,
Type = DeviceAllocType.RETURN
}).ToListAsync();
alloclist.ForEach(it =>
{
it.Id = YitIdHelper.NextId();
});
if (!alloclist.IsEmpty())
{
await _deviceAllocRep.InsertAsync(alloclist);
}
// 更新设备所属的客户ID
await _deviceRep.Where(x => input.ids.Contains(x.Id)).UpdateAsync(x => new PC_Device
{
BusinessId = userid,
ShopId = 0,
UpdatedTime = DateTime.Now,
UpdatedUserId = CurrentUser.UserId,
UpdatedUserName = CurrentUser.Name
});*/
}
/// <summary>
/// 设备从总部回收
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork(true)]
[OpAudit("从下级总部回收", "设备", OpAuditLogEventTarget.Head)]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.RecycleFromHeadName)]
public async Task RecycleFromHeadAsync(DeviceRecycleC2SDto input)
{
var CurrentUser = UserInfo.GetCurrentAdminShopInfo();
await appService.RecycleAsync(input, ToBusinessId: CurrentUser.BusinessId, IsShowBusiness: true,
async d =>
{
if (d.FromShopId > 0)
{
throw Oops.Bah("尚未从门店回收").WithData(new { d.Id, d.FromShopId });
}
if (d.FromBusinessId == CurrentUser.ShopHeadId)
{
throw Oops.Bah("重复回收").WithData(new { d.Id, d.FromBusinessId });
}
await headLevelChildCheckDomainService.InChildHeadCheck(d.FromBusinessId, CurrentUser.ShopHeadId);
/*if (d.FromShopId > 0)//如果已分配给门店
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(d.FromShopId, OpAuditLogEventTarget.Shop));
else*/
if (d.FromBusinessId != CurrentUser.ShopHeadId)//如果已分配给其他总部
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(d.FromBusinessId, OpAuditLogEventTarget.Head));
}, remark: "总部回收");
/*var userid = CurrentUser.AccountType == AdminType.None ? CurrentUser.UserId : 0;
//记录设备分配记录
var alloclist = await _deviceRep.DetachedEntities.Where(x => input.ids.Contains(x.Id)).Select(x => new PC_DeviceAlloc
{
IsShowBusiness = CurrentUser.AccountType == AdminType.None ? true : false,
CreatedTime = DateTime.Now,
CreatedUserId = CurrentUser.UserId,
CreatedUserName = CurrentUser.Name,
DeviceId = x.Id,
FromBusinessId = x.BusinessId,
FromShopId = x.ShopId,
Remark = string.Empty,
ToBusinessId = userid,
ToShopId = 0,
Type = DeviceAllocType.RETURN
}).ToListAsync();
alloclist.ForEach(it =>
{
it.Id = YitIdHelper.NextId();
});
if (!alloclist.IsEmpty())
{
await _deviceAllocRep.InsertAsync(alloclist);
}
// 更新设备所属的客户ID
await _deviceRep.Where(x => input.ids.Contains(x.Id)).UpdateAsync(x => new PC_Device
{
BusinessId = userid,
ShopId = 0,
UpdatedTime = DateTime.Now,
UpdatedUserId = CurrentUser.UserId,
UpdatedUserName = CurrentUser.Name
});*/
}
/// <summary>
/// 修改设备状态
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork(true)]
[OpAudit("启用", "设备", OpAuditLogEventTarget.Head)]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.EnableName)]
public async Task Enable(DeviceStatusC2SDto input)
{
var CurrentUser = UserInfo.GetCurrentAdminShopInfo();
await appService.SetStatusAsync(input, async d =>
{
if (d.ShopId > 0)
await headLevelChildCheckDomainService.InChildShopCheck(d.BusinessId, CurrentUser.ShopHeadId);
else
await headLevelChildCheckDomainService.InChildHeadCheck(d.BusinessId, CurrentUser.ShopHeadId);
opAuditContext.Update(x =>
{
if (d.ShopId > 0)//如果已分配给门店
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(d.ShopId, OpAuditLogEventTarget.Shop));
});
}, DeviceStatus.Run);
}
[UnitOfWork(true)]
[OpAudit("禁用", "设备", OpAuditLogEventTarget.Head)]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.DisableName)]
public async Task Disable(DeviceStatusC2SDto input)
{
var CurrentUser = UserInfo.GetCurrentAdminShopInfo();
await appService.SetStatusAsync(input, async d =>
{
if (d.ShopId > 0)
await headLevelChildCheckDomainService.InChildShopCheck(d.BusinessId, CurrentUser.ShopHeadId);
else
await headLevelChildCheckDomainService.InChildHeadCheck(d.BusinessId, CurrentUser.ShopHeadId);
opAuditContext.Update(x =>
{
if (d.ShopId > 0)//如果已分配给门店
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(d.ShopId, OpAuditLogEventTarget.Shop));
});
}, DeviceStatus.Stop);
}
[UnitOfWork(true)]
[OpAudit("手动添加", "设备", OpAuditLogEventTarget.Head)]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.AddName)]
public async Task SubmitAddAsync(DeviceSubmitC2SDto input, [FromServices] IRepository<PC_Device> _deviceRepository, [FromServices] IFeatureChecker _featureChecker)
{
var CurrentUser = UserInfo.GetCurrentShopHeadInfo();
{
var maxLimitCount = await _featureChecker.GetAsync<int>(ShopHeadOfDeviceFeatureDefinitionProvider.LIMIT_MAX);
if (await _deviceRepository
.DetachedEntities
.Where(x => x.BusinessId == CurrentUser.ShopHeadId)
.CountAsync() >= maxLimitCount)
{
throw Oops.Bah(PCErrorCode.LIMIT_MAX_COUNT10001, maxLimitCount);
}
}
await appService.SubmitAddAsync(input, true, ToBusinessId: CurrentUser.BusinessId, ToShopId: 0, FromBusinessId: CurrentUser.BusinessId, FromShopId: 0);
}
/// <summary>
/// 设备信息修改
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork(true)]
[OpAudit("手动修改", "设备", OpAuditLogEventTarget.Head)]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDevicePermissionDefinitionProvider.EditName)]
public async Task SubmitEditAsync(DeviceSubmitC2SDto input)
{
var CurrentUser = UserInfo.GetCurrentAdminShopInfo();
var headId = CurrentUser.BusinessId;
if (!await _deviceAllocRep
.DetachedEntities
.Where(x => /*x.ToShopId == shopId &&*/x.DeviceId == input.Id && x.FromBusinessId == headId && x.FromShopId == 0 && x.Type == DeviceAllocType.Add)
.AnyAsync())
{
throw Oops.Bah("不能修改非本总部手动添加的设备");
}
await appService.SubmitEditAsync(input, async d =>
{
await headLevelChildCheckDomainService.InChildShopCheck(d.BusinessId, CurrentUser.ShopHeadId);
if (d.ShopId > 0)//如果已分配给门店
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(d.ShopId, OpAuditLogEventTarget.Shop));
});
/* // 检查序列号是否重复
if (await _deviceRep.DetachedEntities
.Where(x => x.FacCode == input.FacCode)
.Where(!input.Id.IsEmpty(), x => x.Id != input.Id)
.AnyAsync())
{
throw Oops.Bah(PCErrorCode.PD1001);
}
var data = await _deviceRep.Where(x => x.Ecode == input.ECode)
.Where(!input.Id.IsEmpty(), x => x.Id != input.Id).FirstOrDefaultAsync();
// 检查机器码是否重复
if (!data.IsEmpty())
{
throw Oops.Bah($"此机器码已绑定序列号{data.FacCode}");
}
data = input.Adapt<PC_Device>();
if (input.Id.IsEmpty())
{
data.Id = YitIdHelper.NextId();
data.Status = DeviceStatus.Run;
data.BusinessId = 0;
data.ShopId = 0;
await _deviceRep.InsertNowAsync(data);
//增加分配记录
await _deviceAllocRep.InsertNowAsync(new PC_DeviceAlloc
{
Id = YitIdHelper.NextId(),
IsShowBusiness = false,
CreatedTime = DateTime.Now,
CreatedUserId = CurrentUser.UserId,
CreatedUserName = CurrentUser.Name,
DeviceId = data.Id,
FromBusinessId = 0,
FromShopId = 0,
Remark = "设备手动添加",
ToBusinessId = 0,
ToShopId = 0,
Type = DeviceAllocType.Add
});
}
else
{
await _deviceRep.UpdateIncludeNowAsync(data, new[] { nameof(data.Ecode), nameof(data.Type), nameof(data.Name), nameof(data.Remark), nameof(data.FacCode) });
}*/
}
/// <summary>
/// 下载设备门店二维码
/// </summary>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize]
public async Task<string> DownLoadImgAsync(BaseId input, [FromServices] DeviceQrImgDownloadService pcShopSettingProvider)
{
return await pcShopSettingProvider.DeviceQrImgDownload(input.Id);
}
}
public class ShopHeadOfDevicePermissionDefinitionProvider : PermissionDefinitionProvider
{
public const string GroupName = $"{ShopHeadPermissionDefinitionNames.Prefix}.device";
public const string ViewName = $"{GroupName}.view";
public const string AddName = $"{GroupName}.add";
public const string AllocToShopName = $"{GroupName}.alloc.shop";
public const string RecycleFromShopName = $"{GroupName}.recycle.shop";
public const string AllocToHeadName = $"{GroupName}.alloc.head";
public const string RecycleFromHeadName = $"{GroupName}.recycle.head";
public const string EditName = $"{GroupName}.edit";
public const string EnableName = $"{GroupName}.enable";
public const string DisableName = $"{GroupName}.disable";
public override void Define(IPermissionDefinitionContext context)
{
{
var groups = context.AddGroup($"{GroupName}", new FixedLocalizableString("设备管理"));
groups.AddPermission($"{ViewName}", new FixedLocalizableString("查看"))
.RequireFeatures(ShopHeadOfDeviceFeatureDefinitionProvider.ViewName);
groups.AddPermission($"{AddName}", new FixedLocalizableString("添加"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopHeadOfDeviceFeatureDefinitionProvider.AddName);
groups.AddPermission($"{EditName}", new FixedLocalizableString("编辑"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopHeadOfDeviceFeatureDefinitionProvider.AddName);
groups.AddPermission($"{AllocToShopName}", new FixedLocalizableString("分配给门店"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopHeadOfDeviceFeatureDefinitionProvider.AllocToShopName);
groups.AddPermission($"{RecycleFromShopName}", new FixedLocalizableString("从门店回收"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopHeadOfDeviceFeatureDefinitionProvider.RecycleFromShopName);
groups.AddPermission($"{AllocToHeadName}", new FixedLocalizableString("分配给下级总部"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopHeadOfDeviceFeatureDefinitionProvider.AllocToHeadName);
groups.AddPermission($"{RecycleFromHeadName}", new FixedLocalizableString("从下级总部回收"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopHeadOfDeviceFeatureDefinitionProvider.RecycleFromHeadName);
groups.AddPermission($"{EnableName}", new FixedLocalizableString("启用"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopHeadOfDeviceFeatureDefinitionProvider.EnableName);
groups.AddPermission($"{DisableName}", new FixedLocalizableString("禁用"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopHeadOfDeviceFeatureDefinitionProvider.DisableName);
}
}
}
}

View File

@ -0,0 +1,32 @@
namespace JT.Shop.Application.Service.Business.Device.Dto
{
/// <summary>
/// 映射
/// </summary>
public class CMapper : IRegister
{
/// <summary>
/// 映射配置
/// </summary>
/// <param name="config"></param>
public void Register(TypeAdapterConfig config)
{
config.ForType<DeviceTypeSubmitC2SDto, PC_DeviceType>()
.Map(dest => dest.Desc, src => src.Desc.ToStrNoEmpty())
.Map(dest => dest.SupType, src => string.Empty)
.Map(dest => dest.Pic, src => src.Pic.ToStrNoEmpty())
.Map(dest => dest.BleUrl, src => src.BleUrl.ToStrNoEmpty())
;
config.ForType<PC_DeviceType, DeviceTypeListS2CDto>()
.Map(dest => dest.PicUrl, src => src.Pic.ImgFile())
;
//设备编辑
config.ForType<DeviceSubmitC2SDto, PC_Device>()
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
.Map(dest => dest.Name, src => src.Name.ToStrNoEmpty())
.Map(dest => dest.FacCode, src => src.FacCode.ToStrNoEmpty())
.Map(dest => dest.Ecode, src => src.ECode.ToStrNoEmpty())
;
}
}
}

View File

@ -0,0 +1,243 @@
namespace JT.Shop.Application.Service.Business.Device
{
/// <summary>
/// 设备回收
/// </summary>
public class DeviceRecycleC2SDto : IValidatableObject
{
/// <summary>
/// 设备列表
/// </summary>
public List<long> ids { get; set; }
/// <summary>
/// 验证
/// </summary>
/// <param name="validationContext"></param>
/// <returns></returns>
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ids.IsEmpty())
{
yield return new ValidationResult("请先选择设备", new[] { nameof(ids) });
}
if (ids.Count > 100)
{
yield return new ValidationResult("一次最多可回收100台设备", new[] { nameof(ids) });
}
}
}
/// <summary>
/// 设备分配给门店
/// </summary>
public class DeviceAllocC2SToShopDto : DeviceRecycleC2SDto, IValidatableObject
{
/// <summary>
/// 门店ID
/// </summary>
public long ShopId { get; set; }
/// <summary>
/// 验证
/// </summary>
/// <param name="validationContext"></param>
/// <returns></returns>
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach (var validationResult in base.Validate(validationContext)) yield return validationResult;
//if (ids.IsEmpty())
//{
// yield return new ValidationResult("请先选择设备", new[] { nameof(ids) });
//}
//if (ids.Count > 100)
//{
// yield return new ValidationResult("一次最多可分配100台设备", new[] { nameof(ids) });
//}
if (ShopId.IsEmpty())
{
yield return new ValidationResult("请先选择门店", new[] { nameof(ShopId) });
}
}
}
/// <summary>
/// 设备分配给总部
/// </summary>
public class DeviceAllocC2SToShopHeadDto : DeviceRecycleC2SDto, IValidatableObject
{
/// <summary>
/// 客户ID
/// </summary>
public long BusinessId { get; set; }
/// <summary>
/// 验证
/// </summary>
/// <param name="validationContext"></param>
/// <returns></returns>
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach (var validationResult in base.Validate(validationContext)) yield return validationResult;
//if (ids.IsEmpty())
//{
// yield return new ValidationResult("请先选择设备", new[] { nameof(ids) });
//}
//if (ids.Count > 100)
//{
// yield return new ValidationResult("一次最多可分配100台设备", new[] { nameof(ids) });
//}
if (BusinessId.IsEmpty())
{
yield return new ValidationResult("请先选择总部", new[] { nameof(BusinessId) });
}
}
}
/// <summary>
/// 设备信息修改
/// </summary>
public class DeviceSubmitC2SDto : BaseNullId, IValidatableObject
{
/// <summary>
/// 设备名称
/// </summary>
[Required(ErrorMessage = "设备名称不可为空"), MaxLength(50, ErrorMessage = "设备名称最多50个字")]
public string Name { get; set; }
/// <summary>
/// 机器码,唯一
/// </summary>
[MaxLength(50, ErrorMessage = "机器码最多50个字")]
public string ECode { get; set; }
/// <summary>
/// 设备序列号,唯一
/// </summary>
[MaxLength(50, ErrorMessage = "设备序列号最多50个字")]
public string FacCode { get; set; }
/// <summary>
/// 设备类型 1 wifi 2 蓝牙
/// </summary>
public int Type { get; set; }
/// <summary>
/// 说明
/// </summary>
[MaxLength(200, ErrorMessage = "说明最多200个字")]
public string Remark { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
//wifi秤
if (Type == 1 && string.IsNullOrWhiteSpace(ECode))
{
yield return new ValidationResult("Wifi秤设备【机器码】必填", new[] { nameof(ECode) });
}
//蓝牙秤
if (Type == 2 && string.IsNullOrWhiteSpace(FacCode))
{
yield return new ValidationResult("蓝牙秤设备【序列号】必填", new[] { nameof(FacCode) });
}
}
}
/// <summary>
/// 获取设备列表
/// </summary>
public class DeviceListC2SDto : PageInputV2Base
{
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/// <summary>
/// 设备机器码
/// </summary>
public string ECode { get; set; }
/// <summary>
/// 序列号
/// </summary>
public string FacCode { get; set; }
/// <summary>
/// 设备机器码或序列号
/// </summary>
public string Search { get; set; }
/// <summary>
/// 设备状态
/// </summary>
public HashSet<DeviceStatus> Status { get; set; }
/// <summary>
/// 设备类型
/// </summary>
public HashSet<int> DevType { get; set; }
}
/// <summary>
/// 设备状态修改
/// </summary>
public class DeviceStatusC2SDto : BaseId
{
}
/// <summary>
/// 设备类型列表
/// </summary>
public class DeviceTypeListC2SDto : PageInputBase
{
/// <summary>
/// 设备类型名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 设备类型编号
/// </summary>
public int Code { get; set; }
}
/// <summary>
/// 设备类型提交
/// </summary>
public class DeviceTypeSubmitC2SDto : BaseNullId
{
/// <summary>
/// 设备类型名称
/// </summary>
[Required(ErrorMessage = "设备类型名称不可为空"), MaxLength(50, ErrorMessage = "设备类型名称最多50个字")]
public string Name { get; set; }
/// <summary>
/// 设备类型编号
/// </summary>
public int? Code { get; set; }
/// <summary>
/// 类型图片
/// </summary>
[Required(ErrorMessage = "类型图片不可为空")]
public string Pic { get; set; }
/// <summary>
/// 类型描述
/// </summary>
[MaxLength(200, ErrorMessage = "类型描述最多200个字")]
public string Desc { get; set; }
/// <summary>
/// 蓝牙协议类型
/// </summary>
public DeviceProType ProType { get; set; }
/// <summary>
/// 蓝牙跳转地址
/// </summary>
public string BleUrl { get; set; } = "";
}
}

View File

@ -0,0 +1,157 @@
namespace JT.Shop.Application.Service.Business.Device
{
/// <summary>
/// 设备分配记录
/// </summary>
public class DeviceAllocListSCDto
{
/// <summary>
/// 原先设备所属客户ID
/// </summary>
[JsonIgnore]
public long FromBusinessId { get; set; }
/// <summary>
/// 原先设备所属店铺ID
/// </summary>
[JsonIgnore]
public long FromShopId { get; set; }
/// <summary>
/// 现设备所属客户ID
/// </summary>
[JsonIgnore]
public long ToBusinessId { get; set; }
/// <summary>
/// 现设备所属店铺ID
/// </summary>
[JsonIgnore]
public long ToShopId { get; set; }
/// <summary>
/// 来源客户
/// </summary>
public string FromBusiness { get; set; }
/// <summary>
/// 来源门店
/// </summary>
public string FromShop { get; set; }
/// <summary>
/// 接收客户
/// </summary>
public string ToBusiness { get; set; }
/// <summary>
/// 接收门店
/// </summary>
public string ToShop { get; set; }
/// <summary>
/// 操作时间
/// </summary>
public DateTime CreatedTime { get; set; }
/// <summary>
/// 分配类型
/// </summary>
public DeviceAllocType Type { get; set; }
/// <summary>
/// 创建者名称
/// </summary>
public string CreatedUserName { get; set; }
}
public class DeviceListS2CDto : PageResultV2<DeviceListS2CDtoItem>
{
}
/// <summary>
/// 设备列表
/// </summary>
public class DeviceListS2CDtoItem : BaseIdAndUserInfo
{
/// <summary>
/// 设备名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 设备序列号,唯一
/// </summary>
public string FacCode { get; set; }
/// <summary>
/// 设备机器码,唯一
/// </summary>
public string Ecode { get; set; }
/// <summary>
/// 设备类型
/// </summary>
public int Type { get; set; }
/// <summary>
/// 设备状态,1-正常运行,2-已禁用
/// </summary>
public DeviceStatus Status { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 设备二维码
/// </summary>
public string Url { get; set; }
}
/// <summary>
/// 设备类型列表
/// </summary>
public class DeviceTypeListS2CDto : BaseId
{
/// <summary>
/// 类型名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 类型编号
/// </summary>
public int Code { get; set; }
/// <summary>
/// 类型图片
/// </summary>
public string Pic { get; set; }
/// <summary>
/// 类型图片网络地址
/// </summary>
public string PicUrl { get; set; }
/// <summary>
/// 类型描述
/// </summary>
public string Desc { get; set; }
/// <summary>
/// 蓝牙协议类型
/// </summary>
public DeviceProType ProType { get; set; }
/// <summary>
/// 蓝牙跳转地址
/// </summary>
public string BleUrl { get; set; } = "";
/// <summary>
/// 支持的测量类型,多个之间以英文,分隔
/// </summary>
public string SupType { get; set; } = "";
}
}

View File

@ -0,0 +1,266 @@
using JT.Shop.Application.Service.ShopApi.Member;
using JT.Shop.Core;
namespace JT.Shop.Application.Service.Business.Member
{
/// <summary>
/// 门店会员列表
/// </summary>
public class BusinessMemberListInput : PageInputV2Base
{
/// <summary>
/// 创建时间范围
/// </summary>
public DateRangeFilterInput CreateTimeRange { get; set; }
/// <summary>
/// 成交时间范围
/// </summary>
public DateRangeFilterInput DealTimeRange { get; set; }
/// <summary>
/// 转入时间范围
/// </summary>
public DateRangeFilterInput MoveInTimeRange { get; set; }
/// <summary>
/// 服务时间范围,服务指当天有接待记录的
/// </summary>
public DateRangeFilterInput ServeTimeRange { get; set; }
/// <summary>
/// 请假时间范围,状态为请假中的
/// </summary>
public DateRangeFilterInput LeaveTimeRange { get; set; }
/// <summary>
/// 达标时间范围
/// </summary>
public DateRangeFilterInput ReachStandardTimeRange { get; set; }
/// <summary>
/// 顾客标签,可多选
/// </summary>
public HashSet<RegUserTagEnum> RType { get; set; }
/// <summary>
/// 预计进店时间段
/// </summary>
public HashSet<RegUserEnterTimeType> EnterTimeType { get; set; }
/// <summary>
/// 连续未到店天数,1-1天,2-2天,3-3天及以上
/// </summary>
public int? NoEntryDay { get; set; }
/// <summary>
/// 顾客属性
/// </summary>
public RegUserProperType? PType { get; set; }
/* /// <summary>
/// 称重情况
/// </summary>
public RegUserWeightProp? WType { get; set; }*/
/// <summary>
/// 顾客达标属性
/// </summary>
public RegUserProperType? DType { get; set; }
/// <summary>
/// 塑形相关,0-不限,1-有塑形协议,2-有精护服务
/// </summary>
public int? SType { get; set; } = 0;
/// <summary>
/// 分类
/// </summary>
public RegUserGroupProp? GType { get; set; }
/// <summary>
/// 周期数,0-单周期,空-不查询,其他按照标准周期查询
/// </summary>
public HashSet<int> CycleValue { get; set; }
/// <summary>
/// 到店次数
/// </summary>
public List<NumberRangeFilterInput<int>> EntryTimes { get; set; }
/// <summary>
/// 已减斤数
/// </summary>
public List<NumberRangeFilterInput<decimal>> ReduceWeight { get; set; }
/// <summary>
/// 距离标准体重剩余斤数
/// </summary>
public List<NumberRangeFilterInput<decimal>> DistWeight { get; set; }
/// <summary>
/// 距离服务期限结束月份
/// </summary>
public int? ServeEndMonth { get; set; }
/// <summary>
/// 顾客来源
/// </summary>
public HashSet<string> RSType { get; set; }
/// <summary>
/// 年龄
/// </summary>
public List<NumberRangeFilterInput<int>> Age { get; set; }
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/// <summary>
/// 会员姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 手机号
/// </summary>
public string Phone { get; set; }
public string Search { get; set; }
/// <summary>
/// 会员状态
/// </summary>
public RegUserStatusEnum? Status { get; set; }
/// <summary>
/// 职业
/// </summary>
public RegUserCareerEnum? Career { get; set; }
///// <summary>
///// 顾客来源
///// </summary>
//public string SType { get; set; }
/// <summary>
/// 注册类型
/// </summary>
public RegUserRegiType? IType { get; set; }
}
/// <summary>
/// 门店今日会员列表
/// </summary>
public class BusinessMemberTodayListInput : PageInputV2Base
{
/// <summary>
/// 成交时间范围
/// </summary>
public DateRangeFilterInput DealTimeRange { get; set; }
/// <summary>
/// 转入时间范围
/// </summary>
public DateRangeFilterInput MoveInTimeRange { get; set; }
/// <summary>
/// 顾客标签,可多选
/// </summary>
public HashSet<RegUserTagEnum> RType { get; set; }
/// <summary>
/// 预计进店时间段
/// </summary>
public HashSet<RegUserEnterTimeType> EnterTimeType { get; set; }
/// <summary>
/// 连续未到店天数,1-1天,2-2天,3-3天及以上
/// </summary>
public int? NoEntryDay { get; set; }
/// <summary>
/// 用户状态列表,可多选
/// </summary>
public HashSet<RegUserEnterStatus> Status { get; set; }
/// <summary>
/// 顾客属性
/// </summary>
public RegUserProperType? PType { get; set; }
/// <summary>
/// 称重情况
/// </summary>
public RegUserWeightProp? WType { get; set; }
/// <summary>
/// 塑形相关
/// </summary>
public HashSet<RegUserSXProp> SType { get; set; }
/// <summary>
/// 分类
/// </summary>
public RegUserGroupProp? GType { get; set; }
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/// <summary>
/// 会员姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 手机号
/// </summary>
public string Phone { get; set; }
public string Search { get; set; }
}
public class BusinessMemberListWithLeaveWarningInput : PageInputV2Base
{
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/// <summary>
/// 请假到期日期
/// </summary>
[Required(ErrorMessage = "请选择日期")]
public DateTime? Time { get; set; }
}
public class BusinessMemberListWithZhangChengWarningInput : PageInputV2Base
{
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/// <summary>
/// 涨秤天数,1-昨日涨秤,2-连续两天涨秤
/// </summary>
[Required,Range(1,2,ErrorMessage = "1-昨日涨秤,2-连续两天涨秤")]
public int Day { get; set; }
}
public class BusinessMemberListWith3Plus1LostInput : PageInputV2Base
{
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/// <summary>
/// 时间,只会处理年月,传递格式如:2021-01-01
/// </summary>
[Required(ErrorMessage = "请选择月份")]
public DateTime? Time { get; set; }
}
public class BusinessMemberListWithSubscribeInput : PageInputV2Base
{
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
}
public class BusinessMemberListWithAgainZhangChengWarningInput : PageInputV2Base,IValidatableObject
{
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/// <summary>
/// 开始重量,斤
/// </summary>
public decimal? StartVal { get; set; }
/// <summary>
/// 结束重量,斤
/// </summary>
public decimal? EndVal { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!StartVal.HasValue && !EndVal.HasValue)
{
yield return new ValidationResult("指定范围不能同时为空", new[] { nameof(StartVal), nameof(EndVal) });
}
}
}
public class BusinessMemberListWithSummarizeWarningInput
{
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
}
}

View File

@ -0,0 +1,408 @@
namespace JT.Shop.Application.Service.Business.Member
{
#region
/// <summary>
/// 门店会员列表
/// </summary>
public class BusinessMemberListOutputItem : BaseIdAndUserInfo
{
/// <summary>
/// 客户姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 头像
/// </summary>
public string AvatarUrl { get; set; }
/// <summary>
/// 性别
/// </summary>
public Gender Gender { get; set; }
/// <summary>
/// 出生年月
/// </summary>
public string BirthDay { get; set; }
/// <summary>
/// 职业
/// </summary>
public RegUserCareerEnum Career { get; set; } = RegUserCareerEnum.Other;
/// <summary>
/// 省份
/// </summary>
public string Province { get; set; }
/// <summary>
/// 市
/// </summary>
public string City { get; set; }
/// <summary>
/// 区
/// </summary>
public string Area { get; set; }
/// <summary>
/// 详细地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 顾客来源
/// </summary>
public string SType { get; set; } = "4";
/// <summary>
/// 注册类型
/// </summary>
public RegUserRegiType IType { get; set; } = RegUserRegiType.ZRJD;
/// <summary>
/// 状态
/// </summary>
public RegUserStatusEnum Status { get; set; }
/// <summary>
/// 到店状态
/// </summary>
public RegUserEnterStatus EnterStatus { get; set; }
/// <summary>
/// 注册时间
/// </summary>
public DateTime? CreatedTime { get; set; }
/// <summary>
/// 未减体重,单位斤
/// </summary>
public decimal UnIncreaseWeight { get; set; }
/// <summary>
/// 已减重量,初始体重-末次体重,单位kg
/// </summary>
public decimal IncreaseWeight { get; set; }
/// <summary>
/// 初始体重,单位kg
/// </summary>
public decimal FirstWeight { get; set; }
/// <summary>
/// 标准体重,单位kg
/// </summary>
public decimal StandWeight { get; set; }
/// <summary>
/// 当日体重
/// </summary>
public decimal TodayWeight { get; set; }
/// <summary>
/// 上次体重,最新体重值,单位kg
/// 目前存的是最新体重值,今日体重
/// </summary>
public decimal LastWeight { get; set; }
/// <summary>
/// 用户标签
/// </summary>
public RegUserTagEnum RType { get; set; }
/// <summary>
/// 上次进店时间
/// </summary>
public string LastEntryTime { get; set; }
/// <summary>
/// 累计到店次数
/// </summary>
public int ShopEnterCnt { get; set; }
/// <summary>
/// 成交时间
/// </summary>
public string DealTime { get; set; }
/// <summary>
/// 是否关注
/// </summary>
public bool IsFollower { get; set; } = false;
/// <summary>
/// 是否在排行榜中
/// </summary>
public bool IsRank { get; set; }
/// <summary>
/// 环比重量,斤
/// </summary>
public string ChainWeight { get; set; }
/// <summary>
/// 预计到店时间
/// </summary>
public string ExpectTime { get; set; }
}
public class BusinessMemberListOutput : PageResultV2<BusinessMemberListOutputItem>
{
}
#endregion
#region
public class BusinessMemberListWithLeaveWarningOutput : PageResultV2<BusinessMemberListOutputItemWithLeaveWarning>
{
}
public class BusinessMemberListOutputItemWithLeaveWarning : CreatedEntityBaseDto<long>
{
public string ShopCode { get; set; }
public string ShopName { get; set; }
public long ShopId { get; set; }
public long BusinessId { get; set; }
/// <summary>
/// 客户名称
/// </summary>
public string BusinessName { get; set; }
public string BusinessCode { get; set; }
/// <summary>
/// 注册用户ID
/// </summary>
public long RegUserId { get; set; }
/// <summary>
/// 客户姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 请假天数
/// </summary>
public int Day { get; set; }
/// <summary>
/// 请假开始时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 请假结束时间
/// </summary>
public DateTime EndTime { get; set; }
/// <summary>
/// 请假备注
/// </summary>
public string Remark { get; set; }
}
#endregion
#region
public class BusinessMemberListWithZhangChengWarningOutput : PageResultV2<BusinessMemberListOutputItemWithZhangChengWarning>
{
}
public class BusinessMemberListOutputItemWithZhangChengWarning
{
public string ShopCode { get; set; }
public string ShopName { get; set; }
public long ShopId { get; set; }
public long BusinessId { get; set; }
/// <summary>
/// 客户名称
/// </summary>
public string BusinessName { get; set; }
public string BusinessCode { get; set; }
/// <summary>
/// 客户姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 用户标签
/// </summary>
public RegUserTagEnum RType { get; set; } = RegUserTagEnum.SJQ;
/// <summary>
/// 环比重量
/// </summary>
public decimal ChainWeight { get; set; }
/// <summary>
/// 注册用户ID
/// </summary>
public long RegUserId { get; set; }
}
#endregion
#region
public class BusinessMemberListWithAgainZhangChengWarningOutput : PageResultV2<BusinessMemberListOutputItemWithAgainZhangChengWarning>
{
}
public class BusinessMemberListOutputItemWithAgainZhangChengWarning
{
public string ShopCode { get; set; }
public string ShopName { get; set; }
public long ShopId { get; set; }
public long BusinessId { get; set; }
/// <summary>
/// 客户名称
/// </summary>
public string BusinessName { get; set; }
public string BusinessCode { get; set; }
/// <summary>
/// 客户姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 用户标签
/// </summary>
public RegUserTagEnum RType { get; set; } = RegUserTagEnum.SJQ;
/// <summary>
/// 复涨重量 斤
/// </summary>
public decimal Weight { get; set; }
/// <summary>
/// 注册用户ID
/// </summary>
public long RegUserId { get; set; }
}
#endregion
#region
public class BusinessMemberListWithSubscribeWarningOutput : PageResultV2<BusinessMemberListOutputItemWithSubscribeWarning>
{
}
public class BusinessMemberListOutputItemWithSubscribeWarning
{
public string ShopCode { get; set; }
public string ShopName { get; set; }
public long ShopId { get; set; }
public long BusinessId { get; set; }
/// <summary>
/// 客户名称
/// </summary>
public string BusinessName { get; set; }
public string BusinessCode { get; set; }
/// <summary>
/// 客户姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 注册用户ID
/// </summary>
public long RegUserId { get; set; }
}
#endregion
#region
public class BusinessMemberListWithSummarizeWarningOutput
{
/// <summary>
/// 明天请假到期顾客
/// </summary>
public int AfkCnt { get; set; }
/// <summary>
/// 昨日涨秤顾客数量
/// </summary>
public int ZTZCCnt { get; set; }
/// <summary>
/// 连续两天涨称顾客数量
/// </summary>
public int LXZCCnt { get; set; }
/// <summary>
/// 重点关注顾客
/// </summary>
public int SubscribeCnt { get; set; }
/// <summary>
/// 达标复涨顾客
/// </summary>
public int DBFZCnt { get; set; }
}
#endregion
}

View File

@ -0,0 +1,566 @@
using JT.Shop.Application.Service.Mch.Member;
using JT.Shop.Application.Service.ShopApi.Member;
using JT.Shop.Application.Service.ShopApi.Member.Dto;
using JT.Shop.Application.Service.ShopApi.Report;
using JT.Shop.Application.Service.ShopApi.Report.Dto;
using JT.Shop.Application.Service.ShopApi.Shop;
using JT.Shop.Application.Service.ShopApi.User;
using JT.Shop.Application.Service.ShopHead;
using JT.Shop.Domain.Entity.ShopHead;
using JT.Shop.Domain.FeatureDefinitions.ShopHead;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Features;
using Volo.Abp.Localization;
namespace JT.Shop.Application.Service.Business.Member
{
/// <summary>
/// 会员管理
/// </summary>
[ApiDescriptionSettings("总部")]
[Route("/api/business/[controller]")]
public class MemberService(
IRepository<PC_ShopRegUser> regUserRepository,
UserManager userManager,
IRepository<PC_Shop> shopRep,
IPcShopRegUserQueryService pcShopRegUserQueryService,
IPcShopHeadQueryService shopheadQueryService,
IPcRegUserWarningQueryService shopRegUserLeaveQueryService,
OpAuditContext opAuditContext)
: AppService, IDynamicApiController
{
/// <summary>
/// 门店会员列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("list")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<BusinessMemberListOutput> ListAsync(BusinessMemberListInput input)
{
var CurrentUser = userManager.GetCurrentShopHeadInfo();
//var list = await _regUserRepository.DetachedEntities
// .Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
// .Where(!input.Name.IsEmpty(), x => x.Name.Contains(input.Name) || x.Phone.Contains(input.Name))
// .Where(input.Status != 0, x => x.Status == input.Status)
// .Where(input.Career != 0, x => x.Career == input.Career)
// .Where(!input.SType.IsEmpty(), x => x.SType == input.SType)
// .Where(input.IType != 0, x => x.IType == input.IType)
// .OrderByDescending(x => x.CreatedTime)
// .ProjectToType<BusinessMemberListOutput>()
// .ToADPagedListAsync(input.PageNo, input.PageSize);
var list = await Mapper.From(await pcShopRegUserQueryService.GetAllChildList(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId, input.Name, input.Phone, input.Search, input.Career, input.SType, input.IType, input.Status,
input.CreateTimeRange, input.DealTimeRange, input.MoveInTimeRange, input.ServeTimeRange, input.LeaveTimeRange, input.ReachStandardTimeRange, input.RType, input.EnterTimeType, input.NoEntryDay, input.PType, input.DType,/*input.WType,*/input.GType, input.CycleValue, input.EntryTimes, input.ReduceWeight, input.DistWeight, input.ServeEndMonth, input.RSType, input.Age, input)).AdaptToTypeAsync<BusinessMemberListOutput>();
return list;
}
/// <summary>
/// 门店今日会员列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("today-list")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<BusinessMemberListOutput> TodayListAsync(BusinessMemberTodayListInput input)
{
var CurrentUser = userManager.GetCurrentShopHeadInfo();
var list = await Mapper.From(await pcShopRegUserQueryService.GetAllChildTodayList(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId, input.Name, input.Phone, input.Search, input.SType, input.Status,
input.DealTimeRange, input.MoveInTimeRange, input.RType, input.EnterTimeType, input.NoEntryDay, input.PType, input.WType,input.GType, input)).AdaptToTypeAsync<BusinessMemberListOutput>();
return list;
}
/// <summary>
/// 门店会员列表-请假预警
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
[HttpPost("warning/leaves")]
public async Task<BusinessMemberListWithLeaveWarningOutput> AFKAllListAsync(BusinessMemberListWithLeaveWarningInput input)
{
var CurrentUser = userManager.GetCurrentShopHeadInfo();
var list = await Mapper.From(await shopRegUserLeaveQueryService.QueryWithLeave(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId, input.Time.Value.Date, input)).AdaptToTypeAsync<BusinessMemberListWithLeaveWarningOutput>();
return list;
}
/// <summary>
/// 门店会员列表-涨秤预警1-昨日涨秤,2-连续两天涨秤)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
[HttpPost("warning/zhangchengs")]
public async Task<BusinessMemberListWithZhangChengWarningOutput> ZhangChengWarningAsync(BusinessMemberListWithZhangChengWarningInput input)
{
var CurrentUser = userManager.GetCurrentShopHeadInfo();
var list = await Mapper.From(await shopRegUserLeaveQueryService.QueryWithZhangChengWarning(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId, input.Day, input)).AdaptToTypeAsync<BusinessMemberListWithZhangChengWarningOutput>();
return list;
}
/// <summary>
/// 门店会员列表-达标后再次涨秤预警
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
[HttpPost("warning/again-zhangchengs")]
public async Task<BusinessMemberListWithAgainZhangChengWarningOutput> AgainZhangChengWarningAsync(BusinessMemberListWithAgainZhangChengWarningInput input)
{
var CurrentUser = userManager.GetCurrentShopHeadInfo();
var list = await Mapper.From(await shopRegUserLeaveQueryService.QueryWithAgainZhangChengWarning(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId, input.StartVal?.Jin2KG() ?? 0, input.EndVal?.Jin2KG() ?? 0, input)).AdaptToTypeAsync<BusinessMemberListWithAgainZhangChengWarningOutput>();
return list;
}
/// <summary>
/// 门店会员列表-已关注
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
[HttpPost("warning/subscribes")]
public async Task<BusinessMemberListWithSubscribeWarningOutput> SubscribeWarningAsync(BusinessMemberListWithSubscribeInput input)
{
var CurrentUser = userManager.GetCurrentShopHeadInfo();
var list = await Mapper.From(await shopRegUserLeaveQueryService.QueryWithSubscribe(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId, input)).AdaptToTypeAsync<BusinessMemberListWithSubscribeWarningOutput>();
return list;
}
/// <summary>
/// 门店会员列表-汇总
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("warning/summarize")]
public async Task<BusinessMemberListWithSummarizeWarningOutput> SummarizeWarningAsync(BusinessMemberListWithSummarizeWarningInput input)
{
var CurrentUser = userManager.GetCurrentShopHeadInfo();
var list = await Mapper.From(await shopRegUserLeaveQueryService.QueryWithSummarizeWarning(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId)).AdaptToTypeAsync<BusinessMemberListWithSummarizeWarningOutput>();
return list;
}
/// <summary>
/// 3+1流失顾客列表
/// </summary>
/// <returns></returns>
[HttpPost("tolslist")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<BusinessMemberListOutput> GetAllChildListWith3Plush1Lost(BusinessMemberListWith3Plus1LostInput input)
{
var CurrentUser = userManager.GetCurrentShopHeadInfo();
//var list = await _regUserRepository.DetachedEntities
// .Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
// .Where(!input.Name.IsEmpty(), x => x.Name.Contains(input.Name) || x.Phone.Contains(input.Name))
// .Where(input.Status != 0, x => x.Status == input.Status)
// .Where(input.Career != 0, x => x.Career == input.Career)
// .Where(!input.SType.IsEmpty(), x => x.SType == input.SType)
// .Where(input.IType != 0, x => x.IType == input.IType)
// .OrderByDescending(x => x.CreatedTime)
// .ProjectToType<BusinessMemberListOutput>()
// .ToADPagedListAsync(input.PageNo, input.PageSize);
var list = await Mapper.From(await pcShopRegUserQueryService.GetAllChildListWith3Plush1Lost(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId, input.Time.Value, input)).AdaptToTypeAsync<BusinessMemberListOutput>();
var bids = list.Rows.Select(x => x.BusinessId).ToHashSet();
var allbuss = await shopheadQueryService.Get(bids);
var sids = list.Rows.Select(x => x.ShopId).ToList();
var shops = await shopRep.DetachedEntities.Where(x => sids.Contains(x.Id))
.Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
list.Rows.ToList().ForEach(it =>
{
if (allbuss.TryGetValue(it.BusinessId, out var user))
{
it.BusinessName = user.Name;
it.BusinessCode = user.Code;
}
var shop = shops.Where(x => x.Id == it.ShopId).FirstOrDefault();
if (shop != null)
{
it.ShopName = shop.Name;
}
});
return list;
}
/// <summary>
/// 状态设置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.EnableName)]
[OpAudit("启用", "会员", OpAuditLogEventTarget.Head)]
[HttpPost("enable")]
public async Task EnableAsync(BusinessMemberStatusInput input, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
foreach (var id in input.Id)
{
var data = await regUserRepository.Where(x => x.Id == id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.AddTargetSysAccountWhenRequestNormal(data.ShopId, OpAuditLogEventTarget.Shop);
});
await pcHeadLevelChildCheckDomainService.InChildShopCheck(data.BusinessId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
data.Status = RegUserStatusEnum.Enable;
await regUserRepository.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
}
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.DisableName)]
[OpAudit("禁用", "会员", OpAuditLogEventTarget.Head)]
[HttpPost("disable")]
public async Task DisableAsync(BusinessMemberStatusInput input, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
foreach (var id in input.Id)
{
var data = await regUserRepository.Where(x => x.Id == id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.AddTargetSysAccountWhenRequestNormal(data.ShopId, OpAuditLogEventTarget.Shop);
});
await pcHeadLevelChildCheckDomainService.InChildShopCheck(data.BusinessId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
data.Status = RegUserStatusEnum.Disabled;
await regUserRepository.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
}
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.EditName)]
[UnitOfWork(true)]
[HttpPost("edit")]
[OpAudit("编辑", "会员", OpAuditLogEventTarget.Head)]
public async Task EditAsync(MemberEditInput input, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
var data = await regUserRepository.Where(x => x.Id == input.RegUserId).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
//检查手机号是否重复
if (input.DoChangePhone && data.Phone != input.Phone && await regUserRepository.DetachedEntities.AnyAsync(x => x.Phone == input.Phone && x.ShopId == data.ShopId && x.Id != input.RegUserId))
{
throw Oops.Bah(PCErrorCode.PW1004);
}
opAuditContext.Update(x =>
{
x.AddTargetSysAccountWhenRequestNormal(data.ShopId, OpAuditLogEventTarget.Shop);
});
await pcHeadLevelChildCheckDomainService.InChildShopCheck(data.BusinessId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
if (!input.DoChangePhone) input.Phone = data.Phone;
data = input.Adapt(data);
await regUserRepository.UpdateIncludeNowAsync(data, new[] { nameof(data.Name), nameof(data.Phone), nameof(data.Gender), nameof(data.BirthDay), nameof(data.Career), nameof(data.Province), nameof(data.City), nameof(data.Area), nameof(data.Address), nameof(data.SType) });
}
/// <summary>
///获取会员资料
/// </summary>
/// <returns></returns>
[HttpGet("info")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<MemberInfoOutput> InfoAsync([FromQuery] long regUserId, [FromQuery] long shopId, [FromServices] MemberAppQueryService query)
{
return await query.QueryInfo(regUserId, shopId);
}
/// <summary>
/// 会员体重趋势列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("lose-weight-trend")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<List<MemberTrendListS2CDto>> TrendListAsync(ShopHeadQueryMemberLoseWeightTrendInput input, [FromServices] MemberAppQueryService service, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
input.EndTime = input.EndTime.AddDays(1);
return await service.QueryLoseWeightTrend(input.StartTime.Date, input.EndTime.Date, input.Id, input.ShopId);
}
/// <summary>
/// 根据天数进行汇总
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("lose-weight-summarize-by-day")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<List<DayReportListOutput>> ListByDayAsync(ShopHeadQueryMemberLoseWeightSummarizeByDayInput input, [FromServices] MemberAppQueryService service, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
var nowtime = DateTime.Now.Date;
return await service.QueryLoseWeightSummarizeByDay(input, input.ShopId, nowtime);
}
/// <summary>
/// 塑形订单列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("sx-orders")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<PageResult<ShopOrderListS2CDto>> OrderListAsync(ShopHeadQueryMemberSXOrdersInput input, [FromServices] MemberAppQueryService service, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
return await service.QuerySXOrders(input, input.ShopId);
}
/// <summary>
/// 塑形订单详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("OrderDetail")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<ShopOrderDetailS2CDto> OrderDetailAsync(BaseId input, [FromServices] MemberSXService wxMemberSxService)
{
return await wxMemberSxService.OrderDetailAsync(input);
}
/// <summary>
/// 产品和身体部位列表
/// </summary>
/// <returns></returns>
[HttpPost("bodyandproduct/list")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<BodyAndProductListS2CDto> BodyAndProductListAsync(ShopHeadQueryMemberBodyAndProductListInput input, [FromServices] MemberAppQueryService service, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
return await service.QueryBodyAndProductList(input.ShopId);
}
/// <summary>
/// 身体塑形服务记录列表,默认显示一周的记录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("body/list")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<List<ShopRegUserSXBodyListS2CDto>> BodyResultAsync(ShopHeadQueryMemberSxBodyListInput input, [FromServices] MemberAppQueryService service, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
return await service.QuerySxBodyList(input, input.ShopId);
}
/// <summary>
/// 会员可使用的产品列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("product/list")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<List<RegUserProductListS2CDto>> ProductListAsync(ShopHeadQueryMemberProductListInput input, [FromServices] MemberAppQueryService service, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
return await service.QueryProductList(input, input.ShopId);
}
/// <summary>
/// 会员使用的产品使用情况列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("product/use-list")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<PageResult<RegUserProductListS2CDto>> ProductPageListAsync(ShopHeadQueryMemberProductUseResultsInput input, [FromServices] MemberAppQueryService service, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
return await service.QueryProductUseResults(input, input.ShopId);
}
/// <summary>
/// 顾客阶段减重汇总列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("report/parts")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<ShopHeadQueryMemberLoseWeightPartsOutput> PartListAsync(ShopHeadQueryMemberLoseWeightPartsInput input, [FromServices] ILoseWeightPartsQueryService service)
{
var days = (input.ServeTimeRange.End!.Value - input.ServeTimeRange.Start!.Value).TotalDays;
return await Mapper.From(await service.Query(userManager.GetCurrentShopHeadInfo().ShopHeadId, input.ChildParentHeadId, input.ShopId, input.DealTimeRange, input.ServeTimeRange, input.Search, input.Name, input.Phone, input)).AddParameters("PrevServeTime", new DateRangeFilterInput(input.ServeTimeRange.Start.Value.AddDays(-days), input.ServeTimeRange.End.Value.AddDays(-days)))
.AdaptToTypeAsync<ShopHeadQueryMemberLoseWeightPartsOutput>();
}
/// <summary>
/// 减重记录
/// </summary>
/// <param name="service"></param>
/// <returns></returns>
[HttpPost("report/lose-weight-results")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<PageResultV2<WeightListResultS2CDto>> LoseWeightResults(ShopHeadQueryMemberLoseWeightResultsInput input, [FromServices] IPCResultQueryService service, [FromServices] PcHeadLevelChildCheckDomainService pcHeadLevelChildCheckDomainService)
{
await pcHeadLevelChildCheckDomainService.InChildShopCheckByShopId(input.ShopId,
userManager.GetCurrentShopHeadInfo().ShopHeadId);
return (await service.Query(input.ServeTime, input.RegUserId, input.ShopId, input)).Adapt<PageResultV2<WeightListResultS2CDto>>();
}
/// <summary>
/// 历史减重记录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("report/weighthislist")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopMemberPermissionDefinitionProvider.ViewName)]
public async Task<List<WeightHisListOutput>> WeightHisListAsync(BaseReguserId input, [FromServices] ReportService reportService)
{
return await reportService.WeightHisListAsync(input);
}
}
public class ShopHeadQueryMemberLoseWeightTrendInput : MemberTrendListC2SDto
{
[Required]
public long ShopId { get; set; }
}
public class ShopHeadQueryMemberLoseWeightSummarizeByDayInput : BaseReguserId
{
[Required]
public long ShopId { get; set; }
}
public class ShopHeadQueryMemberSXOrdersInput : ShopOrderListC2SDto
{
[Required]
public long ShopId { get; set; }
}
public class ShopHeadQueryMemberBodyAndProductListInput
{
[Required]
public long ShopId { get; set; }
}
public class ShopHeadQueryMemberSxBodyListInput : ShopBodyListC2SDto
{
[Required]
public long ShopId { get; set; }
}
public class ShopHeadQueryMemberProductListInput : RegUserProductListC2SDto
{
[Required]
public long ShopId { get; set; }
}
public class ShopHeadQueryMemberProductUseResultsInput : RegUserProductPageListC2SDto
{
[Required]
public long ShopId { get; set; }
}
public class ShopHeadQueryMemberLoseWeightPartsInput : PageInputV2Base, IValidatableObject
{
/// <summary>
/// 会员名称或手机号
/// </summary>
public string Search { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
[Required]
public DateRangeFilterInput ServeTimeRange { get; set; }
public DateRangeFilterInput DealTimeRange { get; set; }
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ServeTimeRange == null || ServeTimeRange.IsOverTimeSpan(x => x.TotalDays > 180))
yield return new ValidationResult("时间跨度不能超过半年");
}
}
public class ShopHeadQueryMemberLoseWeightResultsInput : PageInputV2Base
{
public DateRangeFilterInput ServeTime { get; set; }
[Required]
public long ShopId { get; set; }
[Required]
public long RegUserId { get; set; }
}
public class ShopHeadQueryMemberLoseWeightPartsOutput : PageResultV2<WeightListS2CDto>
{
/// <summary>
/// 总减重斤数
/// </summary>
public decimal TotalWeight { get; set; }
/// <summary>
/// 总到店次数
/// </summary>
public int TotalEnterCnt { get; set; }
}
public class ShopHeadOfShopMemberPermissionDefinitionProvider : PermissionDefinitionProvider
{
public const string GroupName = $"{ShopHeadPermissionDefinitionNames.Prefix}.shop.member";
public const string ViewName = $"{GroupName}.view";
//public const string Report = $"{GroupName}.view.report";
//public const string AddName = $"{GroupName}.add";
//public const string DelName = $"{GroupName}.del";
public const string EditName = $"{GroupName}.edit";
public const string DisableName = $"{GroupName}.disable";
public const string EnableName = $"{GroupName}.enable";
public override void Define(IPermissionDefinitionContext context)
{
{
var groups = context.AddGroup($"{GroupName}", new FixedLocalizableString("会员管理"));
groups.AddPermission($"{ViewName}", new FixedLocalizableString("查看")).RequireFeatures(ShopHeadOfShopMemberFeatureDefinitionProvider.MANAGE);
//groups.AddPermission($"{Report}", new FixedLocalizableString("报表")).RequireFeatures(ShopHeadOfShopMemberFeatureDefinitionProvider.MANAGE);
//groups.AddPermission($"{AddName}", new FixedLocalizableString("添加"));
groups.AddPermission($"{EditName}", new FixedLocalizableString("编辑"));
//groups.AddPermission($"{DelName}", new FixedLocalizableString("删除"));
groups.AddPermission($"{DisableName}", new FixedLocalizableString("禁用")).RequireFeatures(ShopHeadOfShopMemberFeatureDefinitionProvider.MANAGE);
groups.AddPermission($"{EnableName}", new FixedLocalizableString("启用")).RequireFeatures(ShopHeadOfShopMemberFeatureDefinitionProvider.MANAGE);
}
}
}
}

View File

@ -0,0 +1,87 @@
namespace JT.Shop.Application.Service.Business.Org
{
/// <summary>
/// 用户组织机构分页查询
/// </summary>
public class UserOrgPageListC2SDto : PageInputBase
{
/// <summary>
/// 父Id
/// </summary>
public string Pid { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 总部ID
/// </summary>
public string BusinessId { get; set; }
}
/// <summary>
/// 组织结构列表
/// </summary>
public class UserOrgListCS2Dto
{
/// <summary>
/// 父Id
/// </summary>
public string Pid { get; set; }
}
/// <summary>
/// 编辑组织机构
/// </summary>
public class UserEditOrgC2SDto : UserAddOrgC2SDto
{
/// <summary>
/// 主键
/// </summary>
[Required]
public long Id { get; set; }
}
/// <summary>
/// 添加组织结构
/// </summary>
public class UserAddOrgC2SDto
{
/// <summary>
/// 父Id
/// </summary>
public long Pid { get; set; }
/// <summary>
/// 名称
/// </summary>
[Required(ErrorMessage = "名称不可为空")]
[MaxLength(100, ErrorMessage = "名称长度不可超过100字")]
public string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
[Required(ErrorMessage = "编码不可为空")]
[MaxLength(50, ErrorMessage = "编码长度不可超过50字")]
public string Code { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
[MaxLength(100, ErrorMessage = "备注最多100字")]
public string Remark { get; set; }
/// <summary>
/// 机构类型
/// </summary>
public string OrgType { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,43 @@
namespace JT.Shop.Application.Service.Business.Org
{
/// <summary>
/// 用户组织机构分页查询
/// </summary>
public class UserOrgPageListS2CDto : BaseId
{
/// <summary>
/// 父Id
/// </summary>
public long Pid { get; set; }
/// <summary>
/// 父Ids
/// </summary>
public string Pids { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 状态(字典 0正常 1停用 2删除
/// </summary>
public CommonStatus Status { get; set; }
}
}

View File

@ -0,0 +1,154 @@
namespace JT.Shop.Application.Service.Business.Org
{
/// <summary>
/// 组织结构管理
/// </summary>
[ApiDescriptionSettings("总部")]
[Route("/api/business/[controller]")]
public class OrgService//暂时关闭 : IDynamicApiController, ITransient
{
private readonly IRepository<PC_UserOrg> _userOrgRepository;
private readonly UserManager UserInfo;
public OrgService(
IRepository<PC_UserOrg> userOrgRepository,
UserManager userManager)
{
_userOrgRepository = userOrgRepository;
UserInfo = userManager;
}
/// <summary>
/// 分页查询组织结构列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PageResult<UserOrgPageListS2CDto>> PageAsync(UserOrgPageListC2SDto input)
{
var CurrentUser = UserInfo.GetCurrentShopHeadInfo();
var bid = input.BusinessId.ToLong();
var list = await _userOrgRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(CurrentUser.AccountType != AdminType.None, x => x.BusinessId == bid)
.Where(!input.Name.IsEmpty(), x => EF.Functions.Like(x.Name, $"%{input.Name.ToStr()}%"))
.Where(!input.Pid.IsEmpty(), x => x.Pid == input.Pid.ToLong())
.OrderBy(x => x.Sort).ProjectToType<UserOrgPageListS2CDto>().ToADPagedListAsync(input.PageNo, input.PageSize);
return list;
}
/// <summary>
/// 组织结构列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<UserOrgPageListS2CDto>> ListAsync(UserOrgListCS2Dto input)
{
var CurrentUser = UserInfo.GetCurrentShopHeadInfo();
return await _userOrgRepository.DetachedEntities.Where(!input.Pid.IsEmpty(), x => x.Pid == input.Pid.ToLong())
.Where(x => x.BusinessId == CurrentUser.ShopHeadId)
.OrderBy(x => x.Sort).ProjectToType<UserOrgPageListS2CDto>().ToListAsync();
}
/// <summary>
/// 获取组织机构树
/// </summary>
/// <returns></returns>
public async Task<dynamic> TreeAsync(BaseId input)
{
var CurrentUser = UserInfo.GetCurrentShopHeadInfo();
var orgs = await _userOrgRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(CurrentUser.AccountType != AdminType.None, x => x.BusinessId == input.Id)
.Where(u => u.Status == CommonStatus.Enable)
.OrderBy(u => u.Sort)
.ProjectToType<OrgTreeNode>()
.ToListAsync();
return new TreeBuildUtil<OrgTreeNode>().Build(orgs);
}
/// <summary>
/// 添加组织结构
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task AddAsync(UserAddOrgC2SDto input)
{
if (await _userOrgRepository.DetachedEntities.Where(u => u.Name == input.Name || u.Code == input.Code).AnyAsync())
throw Oops.Bah(ErrorCode.D2002);
var CurrentUser = UserInfo.GetCurrentShopHeadInfo();
var data = input.Adapt<PC_UserOrg>();
data.BusinessId = CurrentUser.ShopHeadId;
data.Id = YitIdHelper.NextId();
await FillPids(data);
await _userOrgRepository.InsertNowAsync(data);
}
/// <summary>
/// 编辑组织结构
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task EditAsync(UserEditOrgC2SDto input)
{
var CurrentUser = UserInfo.GetCurrentUserInfo();
if (input.Pid != 0)
{
var org = await _userOrgRepository.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Pid && u.BusinessId == CurrentUser.UserId);
_ = org ?? throw Oops.Bah(ErrorCode.D2000);
}
if (input.Id == input.Pid)
throw Oops.Bah(ErrorCode.D2001);
// 如果是编辑父id不能为自己的子节点
var childIdListById = await GetChildIdListWithSelfById(input.Id);
if (childIdListById.Contains(input.Pid))
throw Oops.Bah(ErrorCode.D2001);
var sysOrg = await _userOrgRepository.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
var isExist = await _userOrgRepository.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != sysOrg.Id && u.BusinessId == CurrentUser.UserId);
if (isExist)
throw Oops.Bah(ErrorCode.D2002);
sysOrg = input.Adapt<PC_UserOrg>();
await FillPids(sysOrg);
await _userOrgRepository.UpdateIncludeNowAsync(sysOrg, new[] { nameof(sysOrg.Name), nameof(sysOrg.Pid), nameof(sysOrg.Code), nameof(sysOrg.Sort), nameof(sysOrg.Remark) });
}
/// <summary>
/// 根据节点Id获取所有子节点Id集合包含自己
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private async Task<List<long>> GetChildIdListWithSelfById(long id)
{
var CurrentUser = UserInfo.GetCurrentUserInfo();
var childIdList = await _userOrgRepository.DetachedEntities
.Where(u => u.BusinessId == CurrentUser.UserId)
.Where(u => EF.Functions.Like(u.Pids, $"%{id}%"))
.Select(u => u.Id).ToListAsync();
childIdList.Add(id);
return childIdList;
}
/// <summary>
/// 填充父Ids字段
/// </summary>
/// <param name="sysOrg"></param>
/// <returns></returns>
private async Task FillPids(PC_UserOrg sysOrg)
{
if (sysOrg.Pid == 0L)
{
sysOrg.Pids = "[" + 0 + "],";
}
else
{
var t = await _userOrgRepository.DetachedEntities.FirstOrDefaultAsync(u => u.Id == sysOrg.Pid);
sysOrg.Pids = t.Pids + "[" + t.Id + "],";
}
}
}
}

View File

@ -0,0 +1,24 @@
namespace JT.Shop.Application.Service.Business.Pos.Dto
{
/// <summary>
/// 映射
/// </summary>
public class CMapper : IRegister
{
/// <summary>
/// 映射配置
/// </summary>
/// <param name="config"></param>
public void Register(TypeAdapterConfig config)
{
//添加职位
config.ForType<AddPosInput, PC_ShopPos>()
.Map(dest => dest.Name, src => src.Name.ToStrNoEmpty())
.Map(dest => dest.Code, src => src.Code.ToStrNoEmpty())
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
.Map(dest => dest.Status, src => CommonStatus.Enable)
.Map(dest => dest.Id, src => YitIdHelper.NextId())
;
}
}
}

View File

@ -0,0 +1,28 @@
namespace JT.Shop.Application.Service.Business.Pos
{
/// <summary>
/// 职位列表
/// </summary>
public class BusinessPosListOutput : BaseIdAndUserInfo
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
}

View File

@ -0,0 +1,155 @@
using Furion.DatabaseAccessor.Extensions;
namespace JT.Shop.Application.Service.Business.Pos
{
/// <summary>
/// 职位管理
/// </summary>
[ApiDescriptionSettings("总部")]
[Route("/api/business/[controller]")]
public class PosService //暂时关闭: IDynamicApiController, ITransient
{
private readonly IRepository<PC_ShopPos> _posRepository;
private readonly IRepository<PC_User> _userRepository;
private readonly UserManager _userManager;
private readonly IRepository<PC_Shop> _shopRep;
private readonly IMyRepository<SysUser> _sysUserRepository;
public PosService(
IRepository<PC_ShopPos> posRepositor,
UserManager userManager,
IRepository<PC_User> userRepository,
IRepository<PC_Shop> shopRep,
IMyRepository<SysUser> sysUserRepository)
{
_posRepository = posRepositor;
_userManager = userManager;
_userRepository = userRepository;
_shopRep = shopRep;
_sysUserRepository = sysUserRepository;
}
/// <summary>
/// 分页获取职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PageResult<BusinessPosListOutput>> PageAsync(PosInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var list = await _posRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(!input.Name.IsEmpty(), u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%"))
.Where(!input.Code.IsEmpty(), u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
.Where(u => u.Status == CommonStatus.Enable)
.OrderBy(u => u.Sort)
.ProjectToType<BusinessPosListOutput>()
.ToADPagedListAsync(input.PageNo, input.PageSize);
var uids = list.Rows.Select(x => x.BusinessId).ToList();
var users = await _sysUserRepository.DetachedEntities.Where(x => uids.Contains(x.Id))
.Select(x => new SysUser
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
var sids = list.Rows.Select(x => x.ShopId).ToList();
var shops = await _shopRep.DetachedEntities.Where(x => sids.Contains(x.Id))
.Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
list.Rows.ToList().ForEach(it =>
{
var user = users.Where(x => x.Id == it.BusinessId).FirstOrDefault();
if (user != null)
{
it.BusinessName = user.Name;
}
var shop = shops.Where(x => x.Id == it.ShopId).FirstOrDefault();
if (shop != null)
{
it.ShopName = shop.Name;
}
});
return list;
}
/// <summary>
/// 获取职位列表
/// </summary>
/// <returns></returns>
public async Task<List<PC_ShopPos>> ListAsync(PosInput input)
{
var code = !string.IsNullOrEmpty(input.Code?.Trim());
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
return await _posRepository.DetachedEntities.Where(x => x.BusinessId == CurrentUser.ShopHeadId).Where(code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
.OrderBy(u => u.Sort).ToListAsync();
}
/// <summary>
/// 增加职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task AddAsync(AddPosInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var isExist = await _posRepository.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.BusinessId == CurrentUser.UserId);
if (isExist)
throw Oops.Bah(ErrorCode.D6000);
var pos = input.Adapt<PC_ShopPos>();
pos.BusinessId = CurrentUser.UserId;
pos.Status = CommonStatus.Enable;
await _posRepository.InsertNowAsync(pos);
}
/// <summary>
/// 删除职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task DeleteAsync(DeletePosInput input)
{
var CurrentUser = _userManager.GetCurrentUserInfo();
// 该职位下是否有员工
var hasPosEmp = await _userRepository.DetachedEntities.AnyAsync(x => x.PosId == input.Id);
if (hasPosEmp)
throw Oops.Bah(ErrorCode.D6001);
var pos = await _posRepository.FirstOrDefaultAsync(u => u.Id == input.Id);
await pos.DeleteNowAsync();
}
/// <summary>
/// 更新职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task EditAsync(UpdatePosInput input)
{
var CurrentUser = _userManager.GetCurrentUserInfo();
var isExist = await _posRepository.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id && u.BusinessId == CurrentUser.UserId);
if (isExist)
throw Oops.Bah(ErrorCode.D6000);
var pos = input.Adapt<PC_ShopPos>();
await _posRepository.UpdateIncludeNowAsync(pos, new[] { nameof(pos.Name), nameof(pos.Code), nameof(pos.Remark), nameof(pos.Sort) });
}
/// <summary>
/// 获取职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PC_ShopPos> DetailAsync([FromQuery] QueryPosInput input)
{
var CurrentUser = _userManager.GetCurrentUserInfo();
return await _posRepository.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
}
}

View File

@ -0,0 +1,81 @@
using JT.Shop.Application.Service.Mch.Product;
namespace JT.Shop.Application.Service.Business.Product
{
/// <summary>
/// 门店产品
/// </summary>
public class BusinessProductListInput : PageInputV2Base
{
/// <summary>
/// 创建时间范围
/// </summary>
public DateRangeFilterInput CreateTimeRange { get; set; }
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
public HashSet<long> ProductShareNameId { get; set; }
/// <summary>
/// 状态
/// </summary>
public GoodsStatus? Status { get; set; }
}
/// <summary>
/// 门店产品提交
/// </summary>
public class BusinessSubmitProductInput : MchSubmitProductInput
{
}
/// <summary>
/// 产品购买记录
/// </summary>
public class BusinessProductPayListInput : PageInputV2Base
{
public DateRangeFilterInput CreateTimeRange { get; set; }
public DateRangeFilterInput StartTimeRange { get; set; }
public DateRangeFilterInput EndTimeRange { get; set; }
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
public HashSet<long> ProductShareNameId { get; set; }
/// <summary>
/// 产品使用状态
/// </summary>
public RegUserProductStatusEnum? Status { get; set; }
/// <summary>
/// 用户ID
/// </summary>
public long? RegUserId { get; set; }
}
/// <summary>
/// 产品使用记录
/// </summary>
public class BusinessProductResultListInput : PageInputV2Base
{
public DateRangeFilterInput CreateTimeRange { get; set; }
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
public HashSet<long> ProductShareNameId { get; set; }
/// <summary>
/// 用户ID
/// </summary>
public long? RegUserId { get; set; }
/// <summary>
/// 关联的服务ID
/// </summary>
public long? ServeId { get; set; }
/// <summary>
/// 店员ID
/// </summary>
public long? UserId { get; set; }
public long? ResultId { get; set; }
}
}

View File

@ -0,0 +1,147 @@
namespace JT.Shop.Application.Service.Business.Product
{
/// <summary>
/// 门店产品列表
/// </summary>
public class BusinessProductListOutputItem : BaseIdAndUserInfo
{
/// <summary>
/// 产品名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 排序,数字越小越靠前
/// </summary>
public int SortCode { get; set; }
/// <summary>
/// 状态
/// </summary>
public GoodsStatus Status { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
public class BusinessProductListOutput : PageResultV2<BusinessProductListOutputItem>
{
}
/// <summary>
/// 产品购买记录
/// </summary>
public class BusinessProductPayListOutputItem : BaseIdAndUserInfo
{
/// <summary>
/// 产品名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 用户ID
/// </summary>
public long RegUserId { get; set; }
/// <summary>
/// 产品ID
/// </summary>
public long ProductId { get; set; }
/// <summary>
/// 产品开启时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 产品结束时间
/// </summary>
public DateTime? EndTime { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Desc { get; set; }
/// <summary>
/// 已使用次数
/// </summary>
public int UsedCnt { get; set; }
/// <summary>
/// 产品使用状态
/// </summary>
public RegUserProductStatusEnum Status { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime? CreatedTime { get; set; }
}
public class BusinessProductPayListOutput:PageResultV2<BusinessProductPayListOutputItem> {}
/// <summary>
/// 产品使用记录
/// </summary>
public class BusinessProductResultListOutputItem : BaseIdAndUserInfo
{
/// <summary>
/// 产品ID
/// </summary>
public long ProductId { get; set; }
/// <summary>
/// 产品名称
/// </summary>
public string ProductName { get; set; }
/// <summary>
/// 用户ID
/// </summary>
public long RegUserId { get; set; }
/// <summary>
/// 用户名称
/// </summary>
public string RegUserName { get; set; }
/// <summary>
/// 关联的服务ID
/// </summary>
[Comment("关联的服务ID")]
public long ServeId { get; set; }
/// <summary>
/// 服务名称
/// </summary>
public string ServeName { get; set; }
/// <summary>
/// 店员ID
/// </summary>
[Comment("店员ID")]
public long UserId { get; set; }
/// <summary>
/// 店员名称
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime? CreatedTime { get; set; }
}
public class BusinessProductResultListOutput:PageResultV2<BusinessProductResultListOutputItem>
{
}
}

View File

@ -0,0 +1,568 @@
using JT.Shop.Application.Service.Business.Serve;
using JT.Shop.Application.Service.Mch.Product;
using JT.Shop.Application.Service.ShopHead;
using JT.Shop.Domain;
using JT.Shop.Domain.Entity.Business;
using JT.Shop.Domain.Entity.ShopHead;
using JT.Shop.Domain.FeatureDefinitions.ShopHead;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.Users;
namespace JT.Shop.Application.Service.Business.Product
{
/// <summary>
/// 产品管理
/// </summary>
[ApiDescriptionSettings("总部")]
[Route("/api/business/[controller]")]
public class ProductService : IDynamicApiController, ITransient
{
private readonly IRepository<PC_ShopProduct> _productRepository;
private readonly IRepository<PC_ShopRegUser> _regUserRepository;
private readonly IRepository<PC_ShopAccount> _accountRepository;
private readonly IRepository<PC_ShopService> _shopServiceRepository;
private readonly IRepository<PC_Shop> _shopRep;
private readonly IPcShopHeadQueryService _sysUserRepository;
private readonly UserManager _userManager;
private readonly IRepository<PC_BusinessShopProduct> _BusinessShopProduct;
private readonly OpAuditContext opAuditContext;
private readonly IPcShopProductQueryService _pcShopProductQueryService;
private readonly IPcShopProductUseRecordQueryService lcShopProductUseRecordQueryService;
private readonly IPcShopProductBuyRecordQueryService pcShopProductBuyRecordQueryService;
public ProductService(
IRepository<PC_ShopProduct> productRepository,
UserManager userManager,
IRepository<PC_ShopRegUser> regUserRepository,
IRepository<PC_ShopAccount> accountRepository,
IRepository<PC_ShopService> shopServiceRepository,
IRepository<PC_Shop> shopRep,
IRepository<PC_BusinessShopProduct> BusinessShopProduct,
IPcShopHeadQueryService sysUserRepository, OpAuditContext opAuditContext, IPcShopProductQueryService pcShopProductQueryService, IPcShopProductUseRecordQueryService lcShopProductUseRecordQueryService, IPcShopProductBuyRecordQueryService pcShopProductBuyRecordQueryService)
{
_productRepository = productRepository;
_userManager = userManager;
_regUserRepository = regUserRepository;
_accountRepository = accountRepository;
_shopServiceRepository = shopServiceRepository;
_shopRep = shopRep;
_BusinessShopProduct = BusinessShopProduct;
_sysUserRepository = sysUserRepository;
this.opAuditContext = opAuditContext;
_pcShopProductQueryService = pcShopProductQueryService;
this.lcShopProductUseRecordQueryService = lcShopProductUseRecordQueryService;
this.pcShopProductBuyRecordQueryService = pcShopProductBuyRecordQueryService;
}
/// <summary>
/// 产品列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopProductPermissionDefinitionProvider.ViewName)]
public async Task<BusinessProductListOutput> ListAsync(BusinessProductListInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
/* var list = await _productRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(!input.Name.IsEmpty(), x => x.Name.Contains(input.Name))
.Where(input.Status != 0, x => x.Status == input.Status)
.OrderBy(x => x.SortCode)
.ProjectToType<BusinessProductListOutput>()
.ToADPagedListAsync(input.PageNo, input.PageSize);*/
var list = (await _pcShopProductQueryService.GetAllChildList(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId, input.ProductShareNameId, input.Status, input.CreateTimeRange, input)).Adapt<BusinessProductListOutput>();
var uids = list.Rows.Select(x => x.BusinessId).ToList();
var users = await _sysUserRepository.Get(uids.ToHashSet());
var sids = list.Rows.Select(x => x.ShopId).ToList();
var shops = await _shopRep.DetachedEntities.Where(x => sids.Contains(x.Id))
.Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
list.Rows.ToList().ForEach(it =>
{
if (users.TryGetValue(it.BusinessId, out var user))
{
it.BusinessName = user.Name;
it.BusinessCode = user.Code;
}
var shop = shops.Where(x => x.Id == it.ShopId).FirstOrDefault();
if (shop != null)
{
it.ShopName = shop.Name;
}
});
return list;
}
/// <summary>
/// 状态设置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopProductPermissionDefinitionProvider.EnableName)]
[OpAudit("上架", "门店产品", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task Enable(MchSetStatusInput input, [FromServices] PcHeadLevelChildCheckDomainService headLevelChildCheckDomainService)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _productRepository.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.AddTargetSysAccountWhenRequestNormal(data.ShopId, OpAuditLogEventTarget.Shop);
x.Msg = "上架";
});
await headLevelChildCheckDomainService.InChildShopCheck(data.BusinessId, CurrentUser.ShopHeadId);
data.Status = GoodsStatus.ENABLE;
await _productRepository.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopProductPermissionDefinitionProvider.DisableName)]
[OpAudit("下架", "门店产品", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task Disable(MchSetStatusInput input, [FromServices] PcHeadLevelChildCheckDomainService headLevelChildCheckDomainService)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _productRepository.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.AddTargetSysAccountWhenRequestNormal(data.ShopId, OpAuditLogEventTarget.Shop);
x.Msg = "下架" ;
});
await headLevelChildCheckDomainService.InChildShopCheck(data.BusinessId, CurrentUser.ShopHeadId);
data.Status = GoodsStatus.DISABLE;
await _productRepository.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
/// <summary>
/// 信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopProductPermissionDefinitionProvider.EditName)]
[OpAudit("编辑", "门店产品", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task SubmitAsync(BusinessSubmitProductInput input, [FromServices] PcHeadLevelChildCheckDomainService headLevelChildCheckDomainService)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _productRepository.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(data.ShopId, OpAuditLogEventTarget.Shop));
await headLevelChildCheckDomainService.InChildShopCheck(data.BusinessId, CurrentUser.ShopHeadId);
//检测名称是否重复
if (await _productRepository.DetachedEntities
.Where(x => x.ShopId == data.ShopId && x.Name == input.Name)
.Where(x => x.Id != input.Id)
.AnyAsync())
{
throw Oops.Bah(PCErrorCode.PW1023);
}
data.Name = input.Name;
data.SortCode = input.SortCode;
data.Remark = input.Remark;
await _productRepository.UpdateIncludeNowAsync(data, new[] { nameof(data.Name), nameof(data.SortCode), nameof(data.Remark) });
}
/// <summary>
/// 产品购买记录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopProductPermissionDefinitionProvider.ViewBuyRecordName)]
public async Task<BusinessProductPayListOutput> PayListAsync(BusinessProductPayListInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
/* var list = await _regUserProductRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.OrderByDescending(x => x.CreatedTime)
.ProjectToType<BusinessProductPayListOutput>()
.ToADPagedListAsync(input.PageNo, input.PageSize);*/
var list = (await pcShopProductBuyRecordQueryService.GetAllChildList(CurrentUser.ShopHeadId,
input.ChildParentHeadId, input.ShopId, input.RegUserId, input.Status, input.ProductShareNameId, input.CreateTimeRange, input.StartTimeRange, input.EndTimeRange,
input)).Adapt<BusinessProductPayListOutput>();
var pids = list.Rows.Select(x => x.ProductId).ToList();
var products = await _productRepository.DetachedEntities.Where(x => pids.Contains(x.Id)).ToListAsync();
var uids = list.Rows.Select(x => x.RegUserId).ToList();
var users = await _regUserRepository.DetachedEntities.Where(x => uids.Contains(x.Id)).ToListAsync();
var bids = list.Rows.Select(x => x.BusinessId).ToList();
var allbuss = await _sysUserRepository.Get(bids.ToHashSet());
var sids = list.Rows.Select(x => x.ShopId).ToList();
var shops = await _shopRep.DetachedEntities.Where(x => sids.Contains(x.Id))
.Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
list.Rows.ToList().ForEach(it =>
{
var product = products.Where(x => x.Id == it.ProductId).FirstOrDefault();
if (product != null)
{
it.Name = product.Name;
}
var user = users.Where(x => x.Id == it.RegUserId).FirstOrDefault();
if (user != null)
{
it.UserName = user.Name;
}
if (allbuss.TryGetValue(it.BusinessId, out var bus))
{
it.BusinessName = bus.Name;
it.BusinessCode = bus.Code;
}
var shop = shops.Where(x => x.Id == it.ShopId).FirstOrDefault();
if (shop != null)
{
it.ShopName = shop.Name;
}
});
return list;
}
/// <summary>
/// 产品使用记录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopProductPermissionDefinitionProvider.ViewUseRecordName)]
public async Task<BusinessProductResultListOutput> ResultListAsync(BusinessProductResultListInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
/* var list = await _regUserProductResultRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.OrderByDescending(x => x.CreatedTime)
.ProjectToType<BusinessProductResultListOutput>()
.ToADPagedListAsync(input.PageNo, input.PageSize);*/
var list = (await lcShopProductUseRecordQueryService.GetAllChildList(CurrentUser.ShopHeadId,
input.ChildParentHeadId, input.ShopId, input.RegUserId, input.ServeId, input.UserId, input.ProductShareNameId, input.CreateTimeRange,input.ResultId,
input)).Adapt<BusinessProductResultListOutput>();
var pids = list.Rows.Select(x => x.ProductId).ToList();
var products = await _productRepository.DetachedEntities.Where(x => pids.Contains(x.Id)).ToListAsync();
var uids = list.Rows.Select(x => x.RegUserId).ToList();
var users = await _regUserRepository.DetachedEntities.Where(x => uids.Contains(x.Id)).ToListAsync();
var aids = list.Rows.Select(x => x.UserId).ToList();
var accounts = await _accountRepository.DetachedEntities.Where(x => aids.Contains(x.Id)).ToListAsync();
var sids = list.Rows.Select(x => x.ServeId).ToList();
var services = await _shopServiceRepository.DetachedEntities.Where(x => sids.Contains(x.Id)).ToListAsync();
var bids = list.Rows.Select(x => x.BusinessId).ToList().ToHashSet();
var allbuss = await _sysUserRepository.Get(bids);
var shopids = list.Rows.Select(x => x.ShopId).ToList();
var shops = await _shopRep.DetachedEntities.Where(x => shopids.Contains(x.Id))
.Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
list.Rows.ToList().ForEach(it =>
{
var product = products.Where(x => x.Id == it.ProductId).FirstOrDefault();
if (product != null)
{
it.ProductName = product.Name;
}
var user = users.Where(x => x.Id == it.RegUserId).FirstOrDefault();
if (user != null)
{
it.RegUserName = user.Name;
}
var account = accounts.Where(x => x.Id == it.UserId).FirstOrDefault();
if (account != null)
{
it.UserName = account.Name;
}
var service = services.Where(x => x.Id == it.ServeId).FirstOrDefault();
if (service != null)
{
it.ServeName = service.Name;
}
if (allbuss.TryGetValue(it.BusinessId, out var bus))
{
it.BusinessName = bus.Name;
it.BusinessCode = bus.Code;
}
var shop = shops.Where(x => x.Id == it.ShopId).FirstOrDefault();
if (shop != null)
{
it.ShopName = shop.Name;
}
});
return list;
}
#region -
/// <summary>
/// 总部产品配置列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("BusinessShopProduct")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultProductPermissionDefinitionProvider.ViewName)]
public async Task<PageResult<MchProductListOutput>> ListAsync(MchProductListInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var list = await _BusinessShopProduct.DetachedEntities
.Where(x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(!input.Name.IsEmpty(), x => x.Name.Contains(input.Name))
.Where(input.Status != 0, x => x.Status == input.Status)
.OrderBy(x => x.SortCode)
.ProjectToType<MchProductListOutput>()
.ToADPagedListAsync(input.PageNo, input.PageSize);
return list;
}
/// <summary>
/// 总部产品配置信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("BusinessShopProduct-add")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultProductPermissionDefinitionProvider.AddName)]
[OpAudit("添加", "总部产品配置", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task SubmitAsync(MchSubmitProductInput input, [FromServices] IFeatureChecker _featureChecker)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
if (await _BusinessShopProduct
.DetachedEntities
.Where(x => x.BusinessId == CurrentUser.ShopHeadId && x.Name == input.Name)
.Where(input.Id > 0, x => x.Id != input.Id)
.AnyAsync())
{
throw Oops.Bah(PCErrorCode.PW1023);
}
{
var maxLimitCount = await _featureChecker.GetAsync<int>(ShopHeadOfProductFeatureDefinitionProvider.LIMIT_MAX);
if (await _BusinessShopProduct
.DetachedEntities
.Where(x => x.BusinessId == CurrentUser.ShopHeadId)
.CountAsync() >= maxLimitCount)
{
throw Oops.Bah(PCErrorCode.LIMIT_MAX_COUNT10001, maxLimitCount);
}
}
var data = input.Adapt<PC_BusinessShopProduct>();
/* if (!input.Id.IsEmpty())
{
data.BusinessId = CurrentUser.ShopHeadId;
data.UpdatedUserId = CurrentUser.UserId;
data.UpdatedUserName = CurrentUser.Name;
await _BusinessShopProduct.UpdateIncludeNowAsync(data, new[] { nameof(data.Name), nameof(data.SortCode), nameof(data.Remark) });
}
else*/
{
data.Status = GoodsStatus.ENABLE;
data.BusinessId = CurrentUser.ShopHeadId;
data.CreatedUserId = CurrentUser.UserId;
data.CreatedUserName = CurrentUser.Name;
await _BusinessShopProduct.InsertNowAsync(data);
}
}
[HttpPost("BusinessShopProduct-edit")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultProductPermissionDefinitionProvider.EditName)]
[OpAudit("编辑", "总部产品配置", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task SubmitEditAsync(MchSubmitProductInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
if (await _BusinessShopProduct
.DetachedEntities
.Where(x => x.BusinessId == CurrentUser.ShopHeadId && x.Name == input.Name)
.Where(input.Id > 0, x => x.Id != input.Id)
.AnyAsync())
{
throw Oops.Bah(PCErrorCode.PW1023);
}
// var data = input.Adapt<PC_BusinessShopProduct>();
if (!input.Id.IsEmpty())
{
var _ = await _BusinessShopProduct.Where(x => x.Id == input.Id && x.BusinessId == CurrentUser.ShopHeadId).FirstOrDefaultAsync();
if (_.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
var data = input.Adapt(_);
//data.BusinessId = CurrentUser.ShopHeadId;
data.UpdatedUserId = CurrentUser.UserId;
data.UpdatedUserName = CurrentUser.Name;
await _BusinessShopProduct.UpdateIncludeNowAsync(data, new[] { nameof(data.Name), nameof(data.SortCode), nameof(data.Remark) });
}
/* else
{
data.Status = GoodsStatus.WAIT;
data.BusinessId = CurrentUser.ShopHeadId;
data.CreatedUserId = CurrentUser.UserId;
data.CreatedUserName = CurrentUser.Name;
await _BusinessShopProduct.InsertNowAsync(data);
}*/
}
/// <summary>
/// 状态设置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("BusinessShopProduct-enable")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultProductPermissionDefinitionProvider.EnableName)]
[OpAudit("上架", "总部产品配置", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task ZBEnable(MchSetStatusInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _BusinessShopProduct.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.Msg = "上架";
});
data.Status = GoodsStatus.ENABLE;
data.UpdatedUserId = CurrentUser.UserId;
data.UpdatedUserName = CurrentUser.Name;
await _BusinessShopProduct.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
[HttpPost("BusinessShopProduct-disable")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultProductPermissionDefinitionProvider.DisableName)]
[OpAudit("下架", "总部产品配置", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task ZBSetStatusAsync(MchSetStatusInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _BusinessShopProduct.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.Msg = "下架" ;
});
data.Status = GoodsStatus.DISABLE;
data.UpdatedUserId = CurrentUser.UserId;
data.UpdatedUserName = CurrentUser.Name;
await _BusinessShopProduct.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
#endregion -
}
public class ShopHeadOfShopProductPermissionDefinitionProvider : PermissionDefinitionProvider
{
public const string GroupName = $"{ShopHeadPermissionDefinitionNames.Prefix}.shop.product";
public const string ViewName = $"{GroupName}.view";
public const string ViewUseRecordName = $"{GroupName}.use.record.view";
public const string ViewBuyRecordName = $"{GroupName}.buy.record.view";
//public const string AddName = $"{GroupName}.add";
//public const string DelName = $"{GroupName}.del";
public const string EditName = $"{GroupName}.edit";
public const string EnableName = $"{GroupName}.enable";
public const string DisableName = $"{GroupName}.disable";
public override void Define(IPermissionDefinitionContext context)
{
{
var groups = context.AddGroup($"{GroupName}", new FixedLocalizableString("门店产品管理"));
groups.AddPermission($"{ViewName}", new FixedLocalizableString("查看产品")).RequireFeatures(ShopHeadOfShopProductFeatureDefinitionProvider.Shop_MANAGE);
groups.AddPermission($"{ViewUseRecordName}", new FixedLocalizableString("查看使用记录")).RequireFeatures(ShopHeadOfShopProductFeatureDefinitionProvider.Shop_MANAGE);
groups.AddPermission($"{ViewBuyRecordName}", new FixedLocalizableString("查看购买记录")).RequireFeatures(ShopHeadOfShopProductFeatureDefinitionProvider.Shop_MANAGE);
//groups.AddPermission($"{AddName}", new FixedLocalizableString("添加")).RequireFeatures(ShopHeadOfShopProductFeatureDefinitionProvider.Shop_MANAGE);
groups.AddPermission($"{EditName}", new FixedLocalizableString("编辑")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfShopProductFeatureDefinitionProvider.Shop_MANAGE);
////groups.AddPermission($"{DelName}", new FixedLocalizableString("删除"));
groups.AddPermission($"{EnableName}", new FixedLocalizableString("启用")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfShopProductFeatureDefinitionProvider.Shop_MANAGE);
groups.AddPermission($"{DisableName}", new FixedLocalizableString("禁用")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfShopProductFeatureDefinitionProvider.Shop_MANAGE);
}
}
}
public class ShopHeadOfDefaultProductPermissionDefinitionProvider : PermissionDefinitionProvider
{
public const string GroupName = $"{ShopHeadPermissionDefinitionNames.Prefix}.self.product";
public const string ViewName = $"{GroupName}.view";
public const string AddName = $"{GroupName}.add";
//public const string DelName = $"{GroupName}.del";
public const string EditName = $"{GroupName}.edit";
public const string EnableName = $"{GroupName}.enable";
public const string DisableName = $"{GroupName}.disable";
public override void Define(IPermissionDefinitionContext context)
{
{
var groups = context.AddGroup($"{GroupName}", new FixedLocalizableString("总部产品管理"));
groups.AddPermission($"{ViewName}", new FixedLocalizableString("查看")).RequireFeatures(ShopHeadOfProductFeatureDefinitionProvider.Self_MANAGE);
groups.AddPermission($"{AddName}", new FixedLocalizableString("添加")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfProductFeatureDefinitionProvider.Self_MANAGE);
groups.AddPermission($"{EditName}", new FixedLocalizableString("编辑")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfProductFeatureDefinitionProvider.Self_MANAGE);
//groups.AddPermission($"{DelName}", new FixedLocalizableString("删除"));
groups.AddPermission($"{EnableName}", new FixedLocalizableString("上架")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfProductFeatureDefinitionProvider.Self_MANAGE);
groups.AddPermission($"{DisableName}", new FixedLocalizableString("下架")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfProductFeatureDefinitionProvider.Self_MANAGE);
}
}
}
}

View File

@ -0,0 +1,22 @@
namespace JT.Shop.Application.Service.Business.Retailer
{
/// <summary>
/// 分销商管理
/// </summary>
public interface IRetailerService
{
/// <summary>
/// 分销商列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<PageResult<BusiensslistS2CDto>> ListAsync(BusinessListC2SDto input);
/// <summary>
/// 信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task SubmitAsync(BusinessSubmitC2SDto input);
}
}

View File

@ -0,0 +1,38 @@
namespace JT.Shop.Application.Service.Business.Retailer
{
/// <summary>
/// 分销商管理
/// </summary>
[ApiDescriptionSettings("管理平台")]
[Route("/api/business/account")]
public class RetailerAppService //暂时关闭: IDynamicApiController
{
private readonly IRetailerService _retailerService;
public RetailerAppService(IRetailerService retailerService)
{
_retailerService = retailerService;
}
/// <summary>
/// 分销商列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PageResult<BusiensslistS2CDto>> ListAsync(BusinessListC2SDto input)
{
return await _retailerService.ListAsync(input);
}
/// <summary>
/// 信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public Task SubmitAsync(BusinessSubmitC2SDto input)
{
return _retailerService.SubmitAsync(input);
}
}
}

View File

@ -0,0 +1,155 @@
using Yitter.IdGenerator;
namespace JT.Shop.Application.Service.Business.Retailer
{
/// <summary>
/// 分销商管理
/// </summary>
public class RetailerService : IRetailerService, ITransient
{
private readonly IMyRepository<SysUser> _sysUserRep;
private readonly IRepository<PC_User> _retailerRep;
private readonly IRepository<SysUserRole> _userroleRep;
private readonly IRepository<SysEmp> _empRep;
private readonly IRepository<SysEmpPos> _sysempposRep;
private readonly UserManager UserInfo;
public RetailerService(
IMyRepository<SysUser> sysUserRep,
IRepository<PC_User> retailerRep,
IRepository<SysUserRole> userroleRep,
IRepository<SysEmp> empRep,
IRepository<SysEmpPos> sysempposRep,
UserManager userManager)
{
_sysUserRep = sysUserRep;
_retailerRep = retailerRep;
_userroleRep = userroleRep;
_empRep = empRep;
_sysempposRep = sysempposRep;
UserInfo = userManager;
}
/// <summary>
/// 分销商列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PageResult<BusiensslistS2CDto>> ListAsync(BusinessListC2SDto input)
{
var CurrentUser = UserInfo.GetCurrentUserInfo();
input.Phone = input.Phone.ToStr();
input.Name = input.Name.ToStr();
var list = await _retailerRep.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.Pid == CurrentUser.UserId)
.Where(!input.Phone.IsEmpty(), x => _sysUserRep.DetachedEntities.Where(e => (e.Phone == input.Phone || e.Account == input.Phone) && e.Id == x.Id).Any())
.Where(!input.Name.IsEmpty(), x => _sysUserRep.DetachedEntities.Where(e => e.Name == input.Name && e.Id == x.Id).Any())
.OrderByDescending(x => x.CreatedTime)
.ProjectToType<BusiensslistS2CDto>()
.ToADPagedListAsync(input.PageNo, input.PageSize);
var ids = list.Rows.Select(x => x.Id).ToList();
var alluser = await _sysUserRep.GetAllNoFilterAsync(x => ids.Contains(x.Id), x => new SysUser
{
Id = x.Id,
Name = x.Name,
Phone = x.Phone,
Account = x.Account,
Status = x.Status
});
list.Rows.ToList().ForEach(it =>
{
var user = alluser.FirstOrDefault(x => x.Id == it.Id);
it.Name = user?.Name;
it.Phone = user?.Phone;
it.Account = user?.Account;
it.Status = user.IsEmpty() ? CommonStatus.Enable : user.Status;
});
return list;
}
/// <summary>
/// 信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task SubmitAsync(BusinessSubmitC2SDto input)
{
var CurrentUser = UserInfo.GetCurrentUserInfo();
if (await _sysUserRep.DetachedEntities
.Where(input.Id > 0, x => x.Account == input.Account && x.Id != input.Id)
.Where(!input.Id.HasValue || input.Id == 0, x => x.Account == input.Account)
.AnyAsync())
{
throw Oops.Bah(ErrorCode.D1003);
}
if (input.Id > 0)
{
// 更新账户
var updateuser = input.Adapt<SysUser>();
updateuser.NickName = updateuser.Name;
await _sysUserRep.UpdateIncludeNowAsync(updateuser, new[] { nameof(updateuser.Account), nameof(updateuser.Name), nameof(updateuser.Phone), nameof(updateuser.NickName) });
}
else
{
// 添加账户
var insertuser = input.Adapt<SysUser>();
insertuser.Id = YitIdHelper.NextId();
insertuser.Password = Hinse.Util.Security.MD5Encryption.Encrypt(input.Password, 32);
insertuser.NickName = insertuser.Name;
insertuser.AdminType = AdminType.None;
input.Id = insertuser.Id;
await _sysUserRep.InsertNowAsync(insertuser);
// 绑定角色
var sysuserrole = new SysUserRole
{
SysUserId = insertuser.Id,
SysRoleId = 142307070910555
};
await _userroleRep.InsertNowAsync(sysuserrole);
// 添加员工信息
var sysemp = new SysEmp
{
Id = insertuser.Id,
JobNum = "",
OrgId = 142307070910539,
OrgName = "郑州巨天"
};
await _empRep.InsertNowAsync(sysemp);
// 添加职位信息
var sysemppos = new SysEmpPos
{
SysEmpId = insertuser.Id,
SysPosId = 142307070910550
};
await _sysempposRep.InsertNowAsync(sysemppos);
// 添加金额配置
var retailer = input.Adapt<PC_User>();
retailer.Id = insertuser.Id;
retailer.Pid = CurrentUser.AccountType == AdminType.None ? CurrentUser.UserId : 0;
retailer.Pids = await CreateNewPids(retailer.Pid);
await _retailerRep.InsertNowAsync(retailer);
}
}
/// <summary>
/// 创建Pids格式 如果pid是0顶级节点pids就是 [0]; 如果pid不是顶级节点pids就是 pid菜单的 pids + [pid] + ,
/// </summary>
/// <param name="pid"></param>
/// <returns></returns>
private async Task<string> CreateNewPids(long pid)
{
if (pid == 0L)
{
return "[0],";
}
else
{
var pmenu = await _retailerRep
.Where(u => u.Id == pid && !u.IsDeleted, false, true)
.FirstOrDefaultAsync();
return pmenu.Pids + "[" + pid + "],";
}
}
}
}

View File

@ -0,0 +1,30 @@
namespace JT.Shop.Application.Service.Business.Role.Dto
{
/// <summary>
/// 映射
/// </summary>
public class CMapper : IRegister
{
/// <summary>
/// </summary>
/// <param name="config"></param>
/// <exception cref="NotImplementedException"></exception>
public void Register(TypeAdapterConfig config)
{
//编辑角色
config.ForType<UpdateUserRoleInput, PC_Role>()
.Map(dest => dest.Name, src => src.Name.ToStrNoEmpty())
.Map(dest => dest.Code, src => src.Code.ToStrNoEmpty())
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
;
//新增角色
config.ForType<AddUserRoleInput, PC_Role>()
.Map(dest => dest.Name, src => src.Name.ToStrNoEmpty())
.Map(dest => dest.Code, src => src.Code.ToStrNoEmpty())
.Map(dest => dest.Remark, src => src.Remark.ToStrNoEmpty())
.Map(dest => dest.Status, src => CommonStatus.Enable)
.Map(dest => dest.DataScopeType, src => DataScopeType.ALL)
;
}
}
}

View File

@ -0,0 +1,47 @@
namespace JT.Shop.Application.Service.Business.Role
{
/// <summary>
/// 添加角色
/// </summary>
public class AddUserRoleInput
{
/// <summary>
/// 名称
/// </summary>
[Required(ErrorMessage = "角色名称不能为空")]
public string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
[Required(ErrorMessage = "角色编码不能为空")]
public string Code { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 数据范围类型(字典 1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据
/// </summary>
public int DataScopeType { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
/// <summary>
/// 更新角色
/// </summary>
public class UpdateUserRoleInput : AddUserRoleInput
{
/// <summary>
/// 角色Id
/// </summary>
[Required(ErrorMessage = "角色Id不能为空")]
public long Id { get; set; }
}
}

View File

@ -0,0 +1,33 @@
namespace JT.Shop.Application.Service.Business.Role
{
/// <summary>
/// 角色分页列表
/// </summary>
public class UserRolePageListS2CDto : BaseIdAndUserInfo
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 数据范围类型(字典 1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据
/// </summary>
public DataScopeType DataScopeType { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
}

View File

@ -0,0 +1,191 @@
namespace JT.Shop.Application.Service.Business.Role
{
/// <summary>
/// 角色管理
/// </summary>
[ApiDescriptionSettings("管理平台")]
[Route("/api/business/[controller]")]
public class UserRoleService //暂时关闭: ITransient, IDynamicApiController
{
private readonly IRepository<PC_Role> _roleRepository;
private readonly IRepository<PC_UserRole> _userRoleRepository;
private readonly IRepository<PC_RoleMenu> _roleMenuRepository;
private readonly IRepository<SysMenu> _sysMenuRepository;
private readonly IMyRepository<SysUser> _sysUserRepository;
private readonly UserManager UserInfo;
public UserRoleService(
IRepository<PC_Role> roleRep,
UserManager userManager,
IRepository<PC_UserRole> userRoleRepository,
IRepository<PC_RoleMenu> roleMenuRepository,
IRepository<SysMenu> sysMenuRepository,
IMyRepository<SysUser> sysUserRepository)
{
_roleRepository = roleRep;
UserInfo = userManager;
_userRoleRepository = userRoleRepository;
_roleMenuRepository = roleMenuRepository;
_sysMenuRepository = sysMenuRepository;
_sysUserRepository = sysUserRepository;
}
/// <summary>
/// 分页获取角色列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PageResult<UserRolePageListS2CDto>> PageAsync(RolePageInput input)
{
var CurrentUser = UserInfo.GetCurrentShopHeadInfo();
var list = await _roleRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(!input.Name.IsEmpty(), u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%"))
.Where(!input.Code.IsEmpty(), u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
.OrderBy(x => x.Sort)
.ProjectToType<UserRolePageListS2CDto>()
.ToADPagedListAsync(input.PageNo, input.PageSize);
var bids = list.Rows.Select(x => x.BusinessId).ToList();
var allbuss = await _sysUserRepository.DetachedEntities.Where(x => bids.Contains(x.Id))
.Select(x => new SysUser
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
list.Rows.ToList().ForEach(it =>
{
var user = allbuss.Where(x => x.Id == it.BusinessId).FirstOrDefault();
if (user != null)
{
it.BusinessName = user.Name;
}
});
return list;
}
/// <summary>
/// 获取角色列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<dynamic> ListAsync(RoleInput input)
{
var CurrentUser = UserInfo.GetCurrentUserInfo();
return await _roleRepository.DetachedEntities
.Where(u => u.BusinessId == CurrentUser.UserId)
.Where(!input.Name.IsEmpty(), u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%"))
.Where(!input.Code.IsEmpty(), u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
.Where(u => u.Status == CommonStatus.Enable)
.OrderBy(u => u.Sort)
.Select(u => new
{
u.Id,
Name = u.Name + "[" + u.Code + "]",
})
.ToListAsync();
}
/// <summary>
/// 角色下拉(用于授权角色时选择)
/// </summary>
/// <returns></returns>
public async Task<List<RoleOutput>> DropDownAsync()
{
var CurrentUserInfo = UserInfo.GetCurrentUserInfo();
return await _roleRepository.DetachedEntities
.Where(u => u.BusinessId == CurrentUserInfo.UserId)
.Where(u => u.Status == CommonStatus.Enable)
.OrderBy(u => u.Sort)
.ProjectToType<RoleOutput>()
.ToListAsync();
}
/// <summary>
/// 添加角色
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task AddAsync(AddUserRoleInput input)
{
var CurrentUserInfo = UserInfo.GetCurrentUserInfo();
var isExist = await _roleRepository.DetachedEntities.AnyAsync(u => (u.Code == input.Code || u.Name == input.Name) && u.BusinessId == CurrentUserInfo.UserId);
if (isExist)
throw Oops.Bah(ErrorCode.D1006);
var role = input.Adapt<PC_Role>();
role.BusinessId = CurrentUserInfo.UserId;
await _roleRepository.InsertNowAsync(role);
}
/// <summary>
/// 更新角色
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task EditAsync(UpdateUserRoleInput input)
{
var CurrentUserInfo = UserInfo.GetCurrentUserInfo();
var adminRole = await _roleRepository.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
if (adminRole.Code == CommonConst.SYS_MANAGER_ROLE_CODE)
throw Oops.Bah(ErrorCode.D1020);
var isExist = await _roleRepository.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id && u.BusinessId == CurrentUserInfo.UserId);
if (isExist)
throw Oops.Bah(ErrorCode.D1006);
var sysRole = input.Adapt<PC_Role>();
await _roleRepository.UpdateIncludeNowAsync(sysRole, new[] { nameof(sysRole.Name), nameof(sysRole.Code), nameof(sysRole.Remark), nameof(sysRole.Sort) });
}
/// <summary>
/// 获取角色
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PC_Role> DetailAsync(QueryRoleInput input)
{
return await _roleRepository.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
/// <summary>
/// 授权角色菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task GrantMenuAsync(GrantRoleMenuInput input)
{
var CurrentUserInfo = UserInfo.GetCurrentUserInfo();
await _roleMenuRepository.Where(x => x.RoleId == input.Id).DeleteAsync();
var roleMenuPidsList = await _sysMenuRepository.DetachedEntities.Where(u => input.GrantMenuIdList.Contains(u.Id))
.Select(u => u.Pids).ToListAsync();
var roleMenuSplitPids = roleMenuPidsList
.SelectMany(u => u.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(v => long.Parse(v[1..^1]))
.Where(v => v != 0))
.Union(input.GrantMenuIdList);
var menus = roleMenuSplitPids.Select(u => new PC_RoleMenu
{
RoleId = input.Id,
MenuId = u
}).ToList();
menus.ForEach(u => u.Id = YitIdHelper.NextId());
await _roleMenuRepository.InsertAsync(menus);
}
/// <summary>
/// 获取角色拥有菜单Id集合
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<List<long>> OwnMenuAsync(QueryRoleInput input)
{
return await _roleMenuRepository.DetachedEntities
.Where(u => u.RoleId == input.Id)
.Select(u => u.MenuId).ToListAsync();
}
}
}

View File

@ -0,0 +1,93 @@
namespace JT.Shop.Application.Service.Business.Serve
{
/// <summary>
/// 门店服务列表
/// </summary>
public class BusinessServeListC2SDto : PageInputV2Base
{
/// <summary>
/// 是否为非精护
/// </summary>
public bool? IsWeight { get; set; }
/// <summary>
/// 创建时间范围
/// </summary>
public DateRangeFilterInput CreateTimeRange { get; set; }
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/* /// <summary>
/// 服务编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 服务名称
/// </summary>
public string Name { get; set; }*/
public HashSet<long> ServiceShareNameId { get; set; }
/// <summary>
/// 状态
/// </summary>
public GoodsStatus? Status { get; set; }
}
/// <summary>
/// 门店服务提交
/// </summary>
public class BusinessSubmitServeInput : BaseNullId
{
/// <summary>
/// 服务名称
/// </summary>
[Required(ErrorMessage = "服务名称不能为空")]
[MaxLength(50, ErrorMessage = "服务名称不能超过50个字符")]
public string Name { get; set; }
/// <summary>
/// 展示名称
/// </summary>
[Required(ErrorMessage = "展示名称不能为空")]
[MaxLength(50, ErrorMessage = "展示名称不能超过50个字符")]
public string ShowName { get; set; }
/// <summary>
/// 是否为非精护
/// </summary>
public bool IsWeight { get; set; } = false;
/// <summary>
/// 排序,数字越小越靠前
/// </summary>
public int SortCode { get; set; }
/// <summary>
/// 备注
/// </summary>
[MaxLength(200, ErrorMessage = "备注不能超过200个字符")]
public string Remark { get; set; }
}
/// <summary>
/// 服务记录
/// </summary>
public class BusinessServeResultListInput : PageInputV2Base
{
/// <summary>
/// 创建时间范围
/// </summary>
public DateRangeFilterInput CreateTimeRange { get; set; }
public long? ChildParentHeadId { get; set; }
public long? ShopId { get; set; }
/// <summary>
/// 会员名称或电话
/// </summary>
public string Name { get; set; }
public string Phone { get; set; }
public long? RegUserId { get; set; }
/// <summary>
/// 完成状态
/// </summary>
public ServeStatus? Status { get; set; }
}
}

View File

@ -0,0 +1,106 @@
using JT.Shop.Core;
namespace JT.Shop.Application.Service.Business.Serve
{
/// <summary>
/// 服务列表
/// </summary>
public class BusinessServeListS2CDto : BaseIdAndUserInfo
{
/// <summary>
/// 服务名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 展示名称
/// </summary>
public string ShowName { get; set; }
/// <summary>
/// 编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 排序,数字越小越靠前
/// </summary>
public int SortCode { get; set; }
/// <summary>
/// 状态
/// </summary>
public GoodsStatus Status { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 是否为非精护
/// </summary>
public bool IsWeight { get; set; } = false;
public DateTime CreatedTime { get; set; }
/// <summary>
/// 服务计算次数
/// </summary>
public int ComputeTimes { get; set; }
}
public class BusinessServeListS2CDtoOutput: PageResultV2<BusinessServeListS2CDto>
{
}
/// <summary>
/// 服务记录
/// </summary>
public class BusinessServeResultListOutputItem : BaseIdAndUserInfo
{
/// <summary>
/// 注册用户ID
/// </summary>
public long RegUserId { get; set; }
/// <summary>
/// 用户名称
/// </summary>
public string RegUserName { get; set; }
/// <summary>
/// 完成状态
/// </summary>
public ServeStatus Status { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime? CreatedTime { get; set; }
/// <summary>
/// 服务ID
/// </summary>
public long ServeId { get; set; }
/// <summary>
/// 店员ID
/// </summary>
public long UserId { get; set; }
/// <summary>
/// 服务名称
/// </summary>
public string ServeName { get; set; }
/// <summary>
/// 店员名称
/// </summary>
public string UserName { get; set; }
public long ProductId { get; set; }
public string ProductName { get; set; }
}
public class BusinessServeResultListOutput: PageResultV2<BusinessServeResultListOutputItem>
{
}
}

View File

@ -0,0 +1,441 @@
using JT.Shop.Application.Service.Mch.Product;
using JT.Shop.Application.Service.Mch.Serve;
using JT.Shop.Application.Service.ShopHead;
using JT.Shop.Core;
using JT.Shop.Domain.Entity.ShopHead;
using JT.Shop.Domain.FeatureDefinitions.ShopHead;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Features;
using Volo.Abp.Localization;
namespace JT.Shop.Application.Service.Business.Serve
{
/// <summary>
/// 服务管理
/// </summary>
[ApiDescriptionSettings("总部")]
[Route("/api/business/[controller]")]
public class ServeService : AppService, IDynamicApiController
{
private readonly IRepository<PC_ShopService> _serveRepository;
private readonly IRepository<PC_ShopServiceResult> _resultRepository;
private readonly IRepository<PC_ShopRegUser> _regUserRepository;
private readonly IRepository<PC_Shop> _shopRep;
private readonly IPcShopHeadQueryService _sysUserRepository;
private readonly IRepository<PC_BusinessShopService> _BusinessShopService;
private readonly UserManager _userManager;
private readonly IPcShopServiceQueryService pcShopServiceQueryService;
private readonly IPcShopServiceResultQueryService pcShopServiceResultQueryService;
private readonly OpAuditContext opAuditContext;
public ServeService(
IRepository<PC_ShopService> serveRepository,
UserManager userManager,
IRepository<PC_ShopServiceResult> resultRepository,
IRepository<PC_ShopRegUser> regUserRepository,
IRepository<PC_Shop> shopRep,
IRepository<PC_BusinessShopService> BusinessShopService,
IPcShopHeadQueryService sysUserRepository, IPcShopServiceQueryService pcShopServiceQueryService, IPcShopServiceResultQueryService pcShopServiceResultQueryService, OpAuditContext opAuditContext)
{
_serveRepository = serveRepository;
_userManager = userManager;
_resultRepository = resultRepository;
_regUserRepository = regUserRepository;
_shopRep = shopRep;
_BusinessShopService = BusinessShopService;
_sysUserRepository = sysUserRepository;
this.pcShopServiceQueryService = pcShopServiceQueryService;
this.pcShopServiceResultQueryService = pcShopServiceResultQueryService;
this.opAuditContext = opAuditContext;
}
/// <summary>
/// 获取服务列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopServePermissionDefinitionProvider.ViewName)]
public async Task<BusinessServeListS2CDtoOutput> ListAsync(BusinessServeListC2SDto input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
/* var list = await _serveRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(!input.Name.IsEmpty(), x => EF.Functions.Like(x.Name, $"%{input.Name}%"))
.Where(input.Status != 0, x => x.Status == input.Status)
.OrderBy(x => x.SortCode)
.ProjectToType<BusinessServeListS2CDto>()
.ToADPagedListAsync(input.PageNo, input.PageSize);*/
var list = (await pcShopServiceQueryService.GetAllChildList(CurrentUser.ShopHeadId, input.ChildParentHeadId,
input.ShopId, input.ServiceShareNameId, input.IsWeight, input.Status, input.CreateTimeRange, input)).Adapt<BusinessServeListS2CDtoOutput>();
if (list.TotalRows == 0) return list;
var uids = list.Rows.Select(x => x.BusinessId).ToList();
var users = await _sysUserRepository.Get(uids.ToHashSet());
var sids = list.Rows.Select(x => x.ShopId).ToHashSet();
var shops = await _shopRep.DetachedEntities.Where(x => sids.Contains(x.Id))
.Select(x => new PC_Shop
{
Id = x.Id,
Name = x.Name
})
.ToListAsync();
list.Rows.ToList().ForEach(it =>
{
if (users.TryGetValue(it.BusinessId, out var user))
{
it.BusinessName = user.Name;
it.BusinessCode = user.Code;
}
var shop = shops.Where(x => x.Id == it.ShopId).FirstOrDefault();
if (shop != null)
{
it.ShopName = shop.Name;
}
});
return list;
}
/// <summary>
/// 状态设置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopServePermissionDefinitionProvider.EnableName)]
[OpAudit("上架", "门店服务", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task Enable(MchSetStatusInput input, [FromServices] PcHeadLevelChildCheckDomainService headLevelChildCheckDomainService)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _serveRepository.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.AddTargetSysAccountWhenRequestNormal(data.ShopId, OpAuditLogEventTarget.Shop);
x.Msg = "上架";
});
await headLevelChildCheckDomainService.InChildShopCheck(data.BusinessId, CurrentUser.ShopHeadId);
data.Status = GoodsStatus.ENABLE;
await _serveRepository.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopServePermissionDefinitionProvider.DisableName)]
[OpAudit("下架", "门店服务", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task Disable(MchSetStatusInput input, [FromServices] PcHeadLevelChildCheckDomainService headLevelChildCheckDomainService)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _serveRepository.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.AddTargetSysAccountWhenRequestNormal(data.ShopId, OpAuditLogEventTarget.Shop);
x.Msg = "下架";
});
await headLevelChildCheckDomainService.InChildShopCheck(data.BusinessId, CurrentUser.ShopHeadId);
data.Status = GoodsStatus.DISABLE;
await _serveRepository.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
/// <summary>
/// 信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopServePermissionDefinitionProvider.EditName)]
[OpAudit("编辑", "门店服务", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task SubmitAsync(MchSubmitServeInput input, [FromServices] PcHeadLevelChildCheckDomainService headLevelChildCheckDomainService)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _serveRepository.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x => x.AddTargetSysAccountWhenRequestNormal(data.ShopId, OpAuditLogEventTarget.Shop));
await headLevelChildCheckDomainService.InChildShopCheck(data.BusinessId, CurrentUser.ShopHeadId);
//检测名称是否重复
if (await _serveRepository
.Where(x => x.ShopId == data.ShopId && x.Name == input.Name)
.Where(input.Id > 0, x => x.Id != input.Id)
.AnyAsync())
{
throw Oops.Bah(PCErrorCode.PW1023);
}
data = input.Adapt(data);
await _serveRepository.UpdateNowAsync(data);
}
/// <summary>
/// 服务记录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("resultlist")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfShopServePermissionDefinitionProvider.ViewRecordName)]
public async Task<BusinessServeResultListOutput> ResultListAsync(BusinessServeResultListInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
/* var list = await _resultRepository.DetachedEntities
.Where(CurrentUser.AccountType == AdminType.None, x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(!input.Name.IsEmpty(), x => _regUserRepository.DetachedEntities.Where(e => e.Id == x.RegUserId).Where(e => EF.Functions.Like(e.Name, $"%{input.Name}%") || EF.Functions.Like(e.Phone, $"%{input.Name}%")).Any())
.Where(input.Status != 0, x => x.Status == input.Status)
.OrderByDescending(x => x.CreatedTime)
.ProjectToType<BusinessServeResultListOutput>()
.ToADPagedListAsync(input.PageNo, input.PageSize);*/
var list = await Mapper.From(await pcShopServiceResultQueryService.GetAllChildList(CurrentUser.ShopHeadId,
input.ChildParentHeadId, input.ShopId, input.Name, input.Phone, input.Status, input.CreateTimeRange, input.RegUserId,
input)).AdaptToTypeAsync<BusinessServeResultListOutput>();
return list;
}
#region -
/// <summary>
/// 获取服务列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("BusinessServiceList")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultServePermissionDefinitionProvider.ViewName)]
public async Task<PageResult<MchServeListS2CDto>> ServiceListAsync(MchServeListC2SDto input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();//总部账号ID其实就是对应sysuser表的ID
var list = await _BusinessShopService.DetachedEntities
.Where(x => x.BusinessId == CurrentUser.ShopHeadId)
.Where(!input.Name.IsEmpty(), x => EF.Functions.Like(x.Name, $"%{input.Name}%"))
.Where(input.Status.HasValue, x => x.Status == input.Status)
.Where(input.IsWeight.HasValue, x => x.IsWeight == input.IsWeight)
.OrderBy(x => x.SortCode)
.ProjectToType<MchServeListS2CDto>()
.ToADPagedListAsync(input.PageNo, input.PageSize);
return list;
}
/// <summary>
/// 信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("BusinessService-add")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultServePermissionDefinitionProvider.AddName)]
[OpAudit("添加服务", "总部服务配置", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task ZBServiceSubmitAddAsync(MchSubmitServeInput input, [FromServices] IFeatureChecker _featureChecker)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
if (await _BusinessShopService
.DetachedEntities
.Where(x => x.BusinessId == CurrentUser.ShopHeadId && x.Name == input.Name)
.Where(input.Id > 0, x => x.Id != input.Id)
.AnyAsync())
{
throw Oops.Bah(PCErrorCode.PW1023);
}
{
var maxLimitCount = await _featureChecker.GetAsync<int>(ShopHeadOfServeFeatureDefinitionProvider.LIMIT_MAX);
if (await _BusinessShopService
.DetachedEntities
.Where(x => x.BusinessId == CurrentUser.ShopHeadId)
.CountAsync() >= maxLimitCount)
{
throw Oops.Bah(PCErrorCode.LIMIT_MAX_COUNT10001, maxLimitCount);
}
}
var data = input.Adapt<PC_BusinessShopService>();
/* if (!input.Id.IsEmpty())
{
await _BusinessShopService.UpdateIncludeNowAsync(data, new[] { nameof(data.Name), nameof(data.SortCode), nameof(data.Remark), nameof(data.ShowName), nameof(data.IsWeight) });
}
else*/
{
data.Status = GoodsStatus.ENABLE;
//data.ShopId = CurrentUser.UserId;
data.BusinessId = CurrentUser.ShopHeadId;
data.Id = YitIdHelper.NextId();
await _BusinessShopService.InsertNowAsync(data);
}
}
[HttpPost("BusinessService-edit")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultServePermissionDefinitionProvider.EditName)]
[OpAudit("编辑服务", "总部服务配置", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task ZBServiceSubmitEditAsync(MchSubmitServeInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
if (await _BusinessShopService
.DetachedEntities
.Where(x => x.BusinessId == CurrentUser.ShopHeadId && x.Name == input.Name)
.Where(input.Id > 0, x => x.Id != input.Id)
.AnyAsync())
{
throw Oops.Bah(PCErrorCode.PW1023);
}
if (!input.Id.IsEmpty())
{
var _ = await _BusinessShopService.Where(x => x.Id == input.Id && x.BusinessId == CurrentUser.ShopHeadId).FirstOrDefaultAsync();
if (_.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
var data = input.Adapt(_);
await _BusinessShopService.UpdateNowAsync(data);
}
/* else
{
data.Status = GoodsStatus.WAIT;
data.ShopId = CurrentUser.UserId;
data.BusinessId = CurrentUser.ShopHeadId;
data.Id = YitIdHelper.NextId();
await _BusinessShopService.InsertNowAsync(data);
}*/
}
/// <summary>
/// 状态设置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("BusinessZBFW-enable")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultServePermissionDefinitionProvider.EnableName)]
[OpAudit("上架", "总部服务配置", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task ZBFWEnable(MchSetStatusInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _BusinessShopService.Where(x => x.Id == input.Id && x.BusinessId == CurrentUser.ShopHeadId).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.Msg = "上架";
});
data.Status = GoodsStatus.ENABLE;
await _BusinessShopService.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
[HttpPost("BusinessZBFW-disable")]
[ShopHeadSystemBusinessVersionAuthorize(ShopHeadOfDefaultServePermissionDefinitionProvider.DisableName)]
[OpAudit("下架", "总部服务配置", OpAuditLogEventTarget.Head)]
[UnitOfWork(true)]
public async Task ZBFWSetStatusAsync(MchSetStatusInput input)
{
var CurrentUser = _userManager.GetCurrentShopHeadInfo();
var data = await _BusinessShopService.Where(x => x.Id == input.Id && x.BusinessId == CurrentUser.ShopHeadId).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
opAuditContext.Update(x =>
{
x.Msg = "下架";
});
data.Status = GoodsStatus.DISABLE;
await _BusinessShopService.UpdateIncludeNowAsync(data, new[] { nameof(data.Status) });
}
#endregion -
}
public class ShopHeadOfShopServePermissionDefinitionProvider : PermissionDefinitionProvider
{
public const string GroupName = $"{ShopHeadPermissionDefinitionNames.Prefix}.shop.service";
public const string ViewName = $"{GroupName}.view";
public const string ViewRecordName = $"{GroupName}.record.view";
//public const string AddName = $"{GroupName}.add";
//public const string DelName = $"{GroupName}.del";
public const string EditName = $"{GroupName}.edit";
public const string EnableName = $"{GroupName}.enable";
public const string DisableName = $"{GroupName}.disable";
public override void Define(IPermissionDefinitionContext context)
{
{
var groups = context.AddGroup($"{GroupName}", new FixedLocalizableString("门店服务管理"));
groups.AddPermission($"{ViewName}", new FixedLocalizableString("查看服务")).RequireFeatures(ShopHeadOfShopServeFeatureDefinitionProvider.Shop_MANAGE);
groups.AddPermission($"{ViewRecordName}", new FixedLocalizableString("查看服务记录")).RequireFeatures(ShopHeadOfShopServeFeatureDefinitionProvider.Shop_MANAGE);
//groups.AddPermission($"{AddName}", new FixedLocalizableString("添加")).RequireFeatures(ShopHeadOfShopServeFeatureDefinitionProvider.Shop_MANAGE);
groups.AddPermission($"{EditName}", new FixedLocalizableString("编辑")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfShopServeFeatureDefinitionProvider.Shop_MANAGE);
////groups.AddPermission($"{DelName}", new FixedLocalizableString("删除"));
groups.AddPermission($"{EnableName}", new FixedLocalizableString("启用")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfShopServeFeatureDefinitionProvider.Shop_MANAGE);
groups.AddPermission($"{DisableName}", new FixedLocalizableString("禁用")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfShopServeFeatureDefinitionProvider.Shop_MANAGE);
}
}
}
public class ShopHeadOfDefaultServePermissionDefinitionProvider : PermissionDefinitionProvider
{
public const string GroupName = $"{ShopHeadPermissionDefinitionNames.Prefix}.self.service";
public const string ViewName = $"{GroupName}.view";
public const string AddName = $"{GroupName}.add";
//public const string DelName = $"{GroupName}.del";
public const string EditName = $"{GroupName}.edit";
public const string EnableName = $"{GroupName}.enable";
public const string DisableName = $"{GroupName}.disable";
public override void Define(IPermissionDefinitionContext context)
{
{
var groups = context.AddGroup($"{GroupName}", new FixedLocalizableString("总部服务管理"));
groups.AddPermission($"{ViewName}", new FixedLocalizableString("查看")).RequireFeatures(ShopHeadOfServeFeatureDefinitionProvider.Self_MANAGE);
groups.AddPermission($"{AddName}", new FixedLocalizableString("添加")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfServeFeatureDefinitionProvider.Self_MANAGE);
groups.AddPermission($"{EditName}", new FixedLocalizableString("编辑")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfServeFeatureDefinitionProvider.Self_MANAGE);
//groups.AddPermission($"{DelName}", new FixedLocalizableString("删除"));
groups.AddPermission($"{EnableName}", new FixedLocalizableString("上架")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfServeFeatureDefinitionProvider.Self_MANAGE);
groups.AddPermission($"{DisableName}", new FixedLocalizableString("下架")).RequirePermissions(ViewName).RequireFeatures(ShopHeadOfServeFeatureDefinitionProvider.Self_MANAGE);
}
}
}
}

View File

@ -0,0 +1,40 @@
using static JT.Shop.Application.Service.ShopHead.Shop.HeadShopListQueryService;
using static JT.Shop.Domain.IPcHeadShopQueryService;
namespace JT.Shop.Application.Service.Business.Shop.Dto
{
/// <summary>
/// 映射
/// </summary>
public class CMapper : IRegister
{
/// <summary>
/// 注册
/// </summary>
/// <param name="config"></param>
public void Register(TypeAdapterConfig config)
{
// 门店添加
config.ForType<ShopAddInput, PC_Shop>()
.Map(dest => dest.Status, src => CommonStatus.Enable)
;
// 门店编辑
config.ForType<ShopEditInput, PC_Shop>()
.Map(dest => dest.Desc, src => src.Desc.ToStrNoEmpty())
;
// 门店列表
config.ForType<PC_Shop, ShopPageListS2CDto>()
.Map(dest => dest.AvatarUrl, src => src.Avatar.ImgFile())
.Map(dest => dest.Url, src => src.Id.ShopUrl())
;
config.ForType<PC_Shop, AppBaseInfoOutput>()
//.Map(dest => dest.AvatarUrl, src => src.Avatar.ImgFile())
.Map(dest => dest.H5Url, src => src.Id.ShopUrl())
;
config.ForType<PcHeadShopDto, HeadShopListOutputItem>()
.Map(dest => dest.AvatarUrl, src => src.Avatar.ImgFile())
.Map(dest => dest.Url, src => src.Id.ShopUrl())
;
}
}
}

View File

@ -0,0 +1,148 @@
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
namespace JT.Shop.Application.Service.Business.Shop
{
/// <summary>
/// 门店添加
/// </summary>
public class ShopAddInput
{
/// <summary>
/// 头像
/// </summary>
[MaxLength(500, ErrorMessage = "头像最多500个字")]
public string Avatar { get; set; }
/// <summary>
/// 门店名称
/// </summary>
[MaxLength(64, ErrorMessage = "门店名称最多64个字")]
[Required(ErrorMessage = "门店名称不可为空")]
public string Name { get; set; }
/// <summary>
/// 门店编号
/// </summary>
[MaxLength(32, ErrorMessage = "门店编号最多32个字")]
[Required(ErrorMessage = "门店编号不可为空")]
public string ShopCode { get; set; }
/// <summary>
/// 联系人
/// </summary>
[MaxLength(50, ErrorMessage = "联系人最多50个字")]
[Required(ErrorMessage = "联系人不可为空")]
public string Contact { get; set; }
/// <summary>
/// 联系电话
/// </summary>
[MaxLength(20, ErrorMessage = "联系电话最多20个字")]
[Required(ErrorMessage = "联系电话不可为空")]
public string Phone { get; set; }
/* /// <summary>
/// 账户密码
/// </summary>
[MinLength(6, ErrorMessage = "账户密码最少6位")]
[Required(ErrorMessage = "账户密码不可为空")]
public virtual string Password { get; set; }*/
/// <summary>
/// 省份
/// </summary>
[Required(ErrorMessage = "省份不可为空")]
[MaxLength(100, ErrorMessage = "省份最多100个字")]
public string Province { get; set; }
/// <summary>
/// 市
/// </summary>
[Required(ErrorMessage = "市不可为空")]
[MaxLength(100, ErrorMessage = "市最多100个字")]
public string City { get; set; }
/// <summary>
/// 区
/// </summary>
[Required(ErrorMessage = "区不可为空")]
[MaxLength(100, ErrorMessage = "区最多100个字")]
public string Area { get; set; }
/// <summary>
/// 详细地址
/// </summary>
[MaxLength(100, ErrorMessage = "详细地址最多100个字")]
[Required(ErrorMessage = "详细地址不可为空")]
public string Address { get; set; }
/// <summary>
/// 联系人性别
/// </summary>
public Gender? Gender { get; set; }
/// <summary>
/// 联系人出生年月
/// </summary>
public DateTime? BirthDay { get; set; }
/* /// <summary>
/// 角色ID
/// </summary>
[Required(ErrorMessage = "角色信息不可为空")]
public long RoleId { get; set; }
*/
/// <summary>
/// 机构ID
/// </summary>
[Required(ErrorMessage = "机构信息不可为空")]
public long OrgId { get; set; }
/// <summary>
/// 说明
/// </summary>
[MaxLength(200, ErrorMessage = "说明最多200个字")]
public string Desc { get; set; }
}
/// <summary>
/// 门店编辑
/// </summary>
public class ShopEditInput : ShopAddInput
{
/// <summary>
/// 门店ID
/// </summary>
[Required(ErrorMessage = "门店ID不可为空")]
public long Id { get; set; }
/* /// <summary>
/// 账户密码
/// </summary>
[ValidateNever]
public override string Password { get; set; }*/
}
/// <summary>
/// 门店列表
/// </summary>
public class ShopPageListC2SDto : PageInputBase
{
/// <summary>
/// 门店名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string Phone { get; set; }
}
/// <summary>
/// 同步总部配置
/// </summary>
public class TBZBpeizhiInput : DEntityBaseId
{
}
}

View File

@ -0,0 +1,104 @@
namespace JT.Shop.Application.Service.Business.Shop
{
/// <summary>
/// 门店列表
/// </summary>
public class ShopPageListS2CDto : BaseId
{
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 头像
/// </summary>
public string AvatarUrl { get; set; }
/// <summary>
/// 门店名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 门店编号
/// </summary>
public string ShopCode { get; set; }
/// <summary>
/// 联系人
/// </summary>
public string Contact { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 省份
/// </summary>
public string Province { get; set; }
/// <summary>
/// 市
/// </summary>
public string City { get; set; }
/// <summary>
/// 区
/// </summary>
public string Area { get; set; }
/// <summary>
/// 详细地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 所属客户ID
/// </summary>
public long BusinessId { get; set; }
/// <summary>
/// 客户名称
/// </summary>
public string BusinessName { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime? CreatedTime { get; set; }
/// <summary>
/// 状态
/// </summary>
public CommonStatus Status { get; set; }
/// <summary>
/// 性别
/// </summary>
public Gender Gender { get; set; }
/// <summary>
/// 出生年月
/// </summary>
public DateTime? BirthDay { get; set; }
/// <summary>
/// 机构ID
/// </summary>
public long OrgId { get; set; }
/// <summary>
/// 说明
/// </summary>
public string Desc { get; set; }
/// <summary>
/// 门店地址
/// </summary>
public string Url { get; set; }
public long DianZhangShopAccountId { get; set; }
}
}

View File

@ -0,0 +1,554 @@
using JT.Shop.Domain.Entity.Business;
using Microsoft.AspNetCore.Authorization;
using System.Linq.Dynamic.Core;
namespace JT.Shop.Application.Service.Business.Shop
{
/// <summary>
/// 门店管理
/// </summary>
[ApiDescriptionSettings("管理平台")]
[Route("/api/business/[controller]")]
public class ShopService //暂时关闭: IDynamicApiController, ITransient
{
private readonly IRepository<PC_Shop> _shopRepository;
private readonly IRepository<PC_ShopAccount> _shopUserRepository;
private readonly IRepository<PC_ShopPos> _posRepository;
private readonly UserManager _userManager;
private readonly IRepository<PC_Role> _roleRepository;
private readonly IRepository<PC_ShopAccountRole> _shopAccountRoleRepository;
private readonly IRepository<PC_ShopRealData> _shopRealDataRepository;
private readonly IMyRepository<SysUser> _sysUserRepository;
private readonly IRepository<PC_ShopBody> _bodyRep;
private readonly IRepository<PC_ShopBodyRel> _bodyRelRepository;
private readonly IRepository<PC_BusinessShopService> _BusinessShopService;//总部服务
private readonly IRepository<PC_BusinessShopProduct> _BusinessShopProduct;//总部产品
private readonly IRepository<PC_BusinessBody> _businessBodyRepository;//总部位置
private readonly IRepository<PC_ShopService> _serveRepository;//门店的服务
private readonly IRepository<PC_ShopProduct> _productRepository;//门店的产品
public ShopService(
IRepository<PC_Shop> shopRepository,
IRepository<PC_ShopAccount> shopUserRepository,
UserManager userManager,
IRepository<PC_ShopPos> posRepository,
IRepository<PC_Role> roleRepository,
IRepository<PC_ShopAccountRole> shopAccountRoleRepository,
IRepository<PC_ShopRealData> shopRealDataRepository,
IMyRepository<SysUser> sysUserRepository,
IRepository<PC_ShopBody> bodyRep,
IRepository<PC_BusinessShopService> BusinessShopService,
IRepository<PC_BusinessShopProduct> BusinessShopProduct,
IRepository<PC_BusinessBody> BusinessBody,
IRepository<PC_ShopService> serveRepository,
IRepository<PC_ShopProduct> productRepository,
IRepository<PC_ShopBodyRel> bodyRelRepository)
{
_shopRepository = shopRepository;
_shopUserRepository = shopUserRepository;
_userManager = userManager;
_posRepository = posRepository;
_roleRepository = roleRepository;
_shopAccountRoleRepository = shopAccountRoleRepository;
_shopRealDataRepository = shopRealDataRepository;
_sysUserRepository = sysUserRepository;
_bodyRep = bodyRep;
_BusinessShopService = BusinessShopService;
_BusinessShopProduct = BusinessShopProduct;
_businessBodyRepository = BusinessBody;
_serveRepository = serveRepository;
_productRepository = productRepository;
_bodyRelRepository = bodyRelRepository;
}
//TODO 添加门店
/* /// <summary>
/// 门店添加
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task AddAsync(ShopAddInput input)
{
var UserInfo = _userManager.GetCurrentAdminShopInfo();
if (await _shopRepository.DetachedEntities.AnyAsync(x => x.ShopCode == input.ShopCode && x.BusinessId == UserInfo.ShopHeadId))
{
throw Oops.Bah(PCErrorCode.PW1012);
}
var shop = input.Adapt<PC_Shop>();
shop.Id = YitIdHelper.NextId();
shop.BusinessId = UserInfo.UserId;
//添加门店
await _shopRepository.InsertNowAsync(shop);
//添加门店数据信息
var realdata = new PC_ShopRealData
{
Id = shop.Id,
ShopId = shop.Id,
BusinessId = UserInfo.UserId,
CreatedTime = DateTime.Now,
TotalUserCnt = 0
};
await _shopRealDataRepository.InsertNowAsync(realdata);
var password = MD5Encryption.Encrypt(input.Password, true);
//初始化职位
var postlist = new List<PC_ShopPos>
{
new PC_ShopPos
{
Id = YitIdHelper.NextId(),
Name = "店长",
Status = CommonStatus.Enable,
Sort = 1,
BusinessId = UserInfo.UserId,
Code = "0001",
Remark = "店长",
CreatedTime = DateTime.Now,
CreatedUserId = UserInfo.UserId,
CreatedUserName = UserInfo.Name,
ShopId = shop.Id
},
new PC_ShopPos
{
Id = YitIdHelper.NextId(),
Name = "店员",
Status = CommonStatus.Enable,
Sort = 2,
BusinessId = UserInfo.UserId,
Code = "0002",
Remark = "店员",
CreatedTime = DateTime.Now,
CreatedUserId = UserInfo.UserId,
CreatedUserName = UserInfo.Name,
ShopId = shop.Id
}
};
await _posRepository.InsertAsync(postlist);
//添加管理员账户
var shopUser = new PC_ShopAccount
{
ShopId = shop.Id,
Account = input.Phone,
Avatar = input.Avatar,
BirthDay = input.BirthDay,
Gender = input.Gender,
BusinessId = UserInfo.UserId,
Id = shop.Id,
Name = input.Contact,
Phone = input.Phone,
Password = password,
Status = CommonStatus.Enable,
Code = "0001",
LastLoginAddress = string.Empty,
LastLoginIp = string.Empty,
PosId = postlist.FirstOrDefault(x => x.Code == "0001").Id,
};
await _shopUserRepository.InsertNowAsync(shopUser);
//添加管理员角色
var shoprole = new PC_ShopAccountRole
{
Id = YitIdHelper.NextId(),
RoleId = input.RoleId,
UserId = shopUser.Id
};
await _shopAccountRoleRepository.InsertNowAsync(shoprole);
////添加门店产品
//var shopProduct = new PC_ShopProduct
//{
// Id = YitIdHelper.NextId(),
// ShopId = shop.Id,
// BusinessId = UserInfo.UserId,
// CreatedTime = DateTime.Now,
// CreatedUserId = UserInfo.UserId,
// CreatedUserName = UserInfo.Name,
// SortCode = 1,
// Status = GoodsStatus.ENABLE,
// Name = "紧肤膏",
// Remark = "紧肤膏"
//};
//await _shopAccountRoleRepository.Change<PC_ShopProduct>().InsertNowAsync(shopProduct);
////添加门店服务
//var servicelist = new List<PC_ShopService>()
//{
// new PC_ShopService
// {
// Id = YitIdHelper.NextId(),
// ShopId = shop.Id,
// BusinessId = UserInfo.UserId,
// CreatedTime = DateTime.Now,
// CreatedUserId = UserInfo.UserId,
// CreatedUserName = UserInfo.Name,
// SortCode = 1,
// Status = GoodsStatus.ENABLE,
// Name = "减重",
// Remark = "减重美体师",
// ShowName = "减重美体师",
// IsWeight=true,
// Code="0001"
// },
// new PC_ShopService
// {
// Id = YitIdHelper.NextId(),
// ShopId = shop.Id,
// BusinessId = UserInfo.UserId,
// CreatedTime = DateTime.Now,
// CreatedUserId = UserInfo.UserId,
// CreatedUserName = UserInfo.Name,
// SortCode = 2,
// Status = GoodsStatus.ENABLE,
// Name = "腹部",
// Remark = "腹部美体师",
// ShowName = "腹部美体师",
// IsWeight=true,
// Code="0002"
// },
// new PC_ShopService
// {
// Id = YitIdHelper.NextId(),
// ShopId = shop.Id,
// BusinessId = UserInfo.UserId,
// CreatedTime = DateTime.Now,
// CreatedUserId = UserInfo.UserId,
// CreatedUserName = UserInfo.Name,
// SortCode = 3,
// Status = GoodsStatus.ENABLE,
// Name = "手臂",
// Remark = "手臂美体师",
// ShowName = "手臂美体师",
// IsWeight=true,
// Code="0003"
// },
// new PC_ShopService
// {
// Id = YitIdHelper.NextId(),
// ShopId = shop.Id,
// BusinessId = UserInfo.UserId,
// CreatedTime = DateTime.Now,
// CreatedUserId = UserInfo.UserId,
// CreatedUserName = UserInfo.Name,
// SortCode = 4,
// Status = GoodsStatus.ENABLE,
// Name = "前大腿",
// Remark = "前大腿美体师",
// ShowName = "前大腿美体师",
// IsWeight=true,
// Code="0004"
// },
// new PC_ShopService
// {
// Id = YitIdHelper.NextId(),
// ShopId = shop.Id,
// BusinessId = UserInfo.UserId,
// CreatedTime = DateTime.Now,
// CreatedUserId = UserInfo.UserId,
// CreatedUserName = UserInfo.Name,
// SortCode = 5,
// Status = GoodsStatus.ENABLE,
// Name = "后大腿",
// Remark = "后大腿美体师",
// ShowName = "后大腿美体师",
// IsWeight=true,
// Code="0005"
// },
// new PC_ShopService
// {
// Id = YitIdHelper.NextId(),
// ShopId = shop.Id,
// BusinessId = UserInfo.UserId,
// CreatedTime = DateTime.Now,
// CreatedUserId = UserInfo.UserId,
// CreatedUserName = UserInfo.Name,
// SortCode = 6,
// Status = GoodsStatus.ENABLE,
// Name = "小腿",
// Remark = "小腿美体师",
// ShowName = "小腿美体师",
// IsWeight=true,
// Code="0006"
// },
//};
//await _shopAccountRoleRepository.InsertAsync(servicelist);
////获取所有身体部位
//var bodylist = await _bodyRep.DetachedEntities.Where(x => x.Status == CommonStatus.Enable).ToListAsync();
////添加门店身体部位
//var shopBodyRelList = new List<PC_ShopBodyRel>();
//bodylist.ForEach(x =>
//{
// shopBodyRelList.Add(new PC_ShopBodyRel
// {
// Id = YitIdHelper.NextId(),
// ShopId = shop.Id,
// BodyId = x.Id,
// BusinessId = shop.BusinessId
// });
//});
//await _bodyRelRepository.InsertAsync(shopBodyRelList);
//TODO:服务、身体部位、产品使用总部的配置
}*/
/// <summary>
/// 同步总部配置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("BusinessZBPZ")]
public async Task AddZbPZToShopAsync(TBZBpeizhiInput input)
{
var UserInfo = _userManager.GetCurrentUserInfo();
if (!await _shopRepository.DetachedEntities.AnyAsync(x => x.Id == input.Id))
{
throw Oops.Bah(PCErrorCode.PD0000);
}
//获取操作的门店
var shop = await _shopRepository.DetachedEntities.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
#region
//获取总部配置的服务
var zbservicelist = await _BusinessShopService.DetachedEntities
.Where(x => x.BusinessId == UserInfo.UserId).ToListAsync();
//获取总部下的门店服务
var mchservicelist = await _serveRepository.DetachedEntities
.Where(x => x.BusinessId == UserInfo.UserId)
.Where(x => x.ShopId == shop.Id)
.OrderByDescending(x => x.SortCode).FirstOrDefaultAsync();
int sortcode = 0;
if (mchservicelist != null)
{
sortcode = mchservicelist.SortCode;
}
List<PC_ShopService> servicelist = new List<PC_ShopService>();
if (zbservicelist.Count > 0)
{
zbservicelist.ForEach(x =>
{
//只同步不存在的服务名字
if (!_serveRepository.DetachedEntities.Where(x => x.BusinessId == UserInfo.UserId)
.Where(x => x.ShopId == shop.Id).Any(m => m.Name == x.Name.Trim()))
{
servicelist.Add(new PC_ShopService
{
Id = YitIdHelper.NextId(),
ShopId = shop.Id,
BusinessId = UserInfo.UserId,
CreatedTime = DateTime.Now,
CreatedUserId = UserInfo.UserId,
CreatedUserName = UserInfo.Name,
SortCode = sortcode + 1,//最大序号累加
Status = x.Status,
Name = x.Name,
Remark = x.Remark,
ShowName = x.ShowName,
IsWeight = x.IsWeight,
Code = x.Code,
ComputeTimes = x.ComputeTimes
});
sortcode++;
}
});
}
//批量添加
await _serveRepository.InsertAsync(servicelist);
#endregion
#region
//获取总部配置的产品配置
var zbshopproductlist = await _BusinessShopProduct.DetachedEntities.Where(x => x.BusinessId == UserInfo.UserId).ToListAsync();
//获取总部下的门店产品配置
var mchprductlist = await _productRepository.DetachedEntities.Where(x => x.BusinessId == UserInfo.UserId)
.Where(x => x.ShopId == shop.Id).OrderByDescending(x => x.SortCode).FirstOrDefaultAsync();
sortcode = 0;
if (mchprductlist != null)
{
sortcode = mchprductlist.SortCode;
}
List<PC_ShopProduct> addShopProductlist = new List<PC_ShopProduct>();
if (zbshopproductlist.Count > 0)
{
zbshopproductlist.ForEach(x =>
{
//只同步不存在的产品名字
if (!_productRepository.DetachedEntities.Where(x => x.BusinessId == UserInfo.UserId)
.Where(x => x.ShopId == shop.Id).Any(m => m.Name == x.Name.Trim()))
{
addShopProductlist.Add(new PC_ShopProduct
{
Id = YitIdHelper.NextId(),
ShopId = shop.Id,
BusinessId = UserInfo.UserId,
CreatedTime = DateTime.Now,
CreatedUserId = UserInfo.UserId,
CreatedUserName = UserInfo.Name,
SortCode = sortcode + 1,//最大序号累加
Status = GoodsStatus.ENABLE,
Name = x.Name,
Remark = x.Remark,
});
sortcode++;
}
});
}
await _productRepository.InsertAsync(addShopProductlist);
#endregion
#region
//获取总部的部位配置
var zbbody = await _businessBodyRepository.DetachedEntities.Where(x => x.BusinessId == UserInfo.UserId).ToListAsync();
//获取总部下的门店自己的部位配置
var mchbody = await _bodyRelRepository.DetachedEntities.Where(x => x.BusinessId == UserInfo.UserId)
.Where(x => x.ShopId == shop.Id).ToListAsync();
var shopBodyRelList = new List<PC_ShopBodyRel>();
if (zbbody.Count > 0)
{
zbbody.ForEach(x =>
{
if (!mchbody.Any(n => n.BodyId == x.BodyId))
{
shopBodyRelList.Add(new PC_ShopBodyRel
{
Id = YitIdHelper.NextId(),
ShopId = shop.Id,
BodyId = x.BodyId,
BusinessId = shop.BusinessId
});
}
});
}
await _bodyRelRepository.InsertAsync(shopBodyRelList);
#endregion
}
/// <summary>
/// 门店编辑
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AppAuthorize("shop:edit")]
public async Task EditAsync(ShopEditInput input)
{
var UserInfo = _userManager.GetCurrentAdminShopInfo();
/* //判断手机号是否已存在
if (await _shopUserRepository.DetachedEntities.AnyAsync(x => x.Account == input.Phone && x.ShopId == input.Id && x.Id != input.Id))
{
throw Oops.Bah(PCErrorCode.PW1004);
}*/
if (await _shopRepository.DetachedEntities.AnyAsync(x => x.ShopCode == input.ShopCode && x.BusinessId == UserInfo.ShopHeadId && x.Id != input.Id))
{
throw Oops.Bah(PCErrorCode.PW1012);
}
var shop = await _shopRepository.DetachedEntities.Where(x => x.Id == input.Id && x.BusinessId == UserInfo.ShopHeadId).FirstAsync();
//更新门店基础信息
shop = input.Adapt<ShopEditInput, PC_Shop>(shop);
/* //更新门店管理员信息
var shopuser = await _shopUserRepository.FirstOrDefaultAsync(x => x.Phone == input.Phone && x.ShopId == UserInfo.ShopId);
if (shopuser != null)
{
shopuser.Edit(input.Avatar, input.Contact, shopuser.Code, input.Gender, input.BirthDay);
//shopuser.Name = input.Contact;
//shopuser.Account = input.Phone;
//shopuser.Avatar = input.Avatar;
//shopuser.Phone = input.Phone;
//shopuser.Gender = input.Gender;
//shopuser.BirthDay = input.BirthDay;
await _shopUserRepository.UpdateIncludeNowAsync(shopuser, new[] { nameof(shopuser.Name), nameof(shopuser.Avatar), nameof(shopuser.Gender), nameof(shopuser.BirthDay) });
}
else
{
shopuser = new PC_ShopAccount(id: YitIdHelper.NextId(), adminType: AdminType.Admin, accountId: 0, avatar: input.Avatar, name: input.Name, phone: input.Phone, code: string.Empty, gender: input.Gender, birthDay: input.BirthDay, posId: 0, shopId: UserInfo.ShopId, shopHeadId: UserInfo.ShopHeadId);
*//* shopuser.Id = YitIdHelper.NextId();
shopuser.Name = input.Contact;
//shopuser.Account = input.Phone;
shopuser.Avatar = input.Avatar;
shopuser.Phone = input.Phone;
shopuser.Gender = input.Gender;
shopuser.BirthDay = input.BirthDay;
shopuser.Status = CommonStatus.Enable;*//*
await _shopUserRepository.InsertAsync(shopuser);
shop.DianZhangShopAccountId = shopuser.Id;
//更新门店管理员角色
//先删除原有角色
await _shopAccountRoleRepository.Where(x => x.ShopId == UserInfo.ShopId && x.RoleId == shop.DianZhangRoleId).DeleteAsync();
//添加新角色
var shopRole = new PC_ShopAccountRole
{
RoleId = shop.DianZhangRoleId,
UserId = shopuser.AccountId,
ShopId = shopuser.ShopId
};
await _shopAccountRoleRepository.InsertNowAsync(shopRole);
}*/
await _shopRepository.UpdateIncludeNowAsync(shop, new[] { nameof(PC_Shop.ShopCode), nameof(PC_Shop.Name), nameof(PC_Shop.Contact), nameof(PC_Shop.Phone), nameof(PC_Shop.Province), nameof(PC_Shop.City), nameof(PC_Shop.Area), nameof(PC_Shop.Address), nameof(shop.Desc), nameof(PC_Shop.OrgId) });
}
/// <summary>
/// 门店列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PageResult<ShopPageListS2CDto>> PageAsync(ShopPageListC2SDto input)
{
var UserInfo = _userManager.GetCurrentUserInfo();
if (UserInfo.UserId == 0)
{
throw Oops.Bah("请登录总部账号查看门店管理!");
}
var list = await _shopRepository.DetachedEntities
.Where(UserInfo.AccountType == AdminType.None, x => x.BusinessId == UserInfo.UserId)
.Where(!input.Name.IsEmpty(), x => EF.Functions.Like(x.Name, $"%{input.Name}%"))
.Where(!input.Phone.IsEmpty(), x => EF.Functions.Like(x.Phone, $"%{input.Phone}%"))
.OrderBy(x => x.SortCode)
.ThenByDescending(x => x.CreatedTime)
.ProjectToType<ShopPageListS2CDto>()
.ToADPagedListAsync(input.PageNo, input.PageSize);
//获取门店管理员信息
var shopids = list.Rows.Select(x => x.Id).ToList();
var accountIds = list.Rows.Select(x => x.DianZhangShopAccountId).ToList();
var shopuserlist = await _shopUserRepository.DetachedEntities.Where(x => accountIds.Contains(x.Id))
.ToListAsync();
//var shopuserrolelist = await _shopAccountRoleRepository.DetachedEntities.Where(x => shopids.Contains(x.UserId))
//.ToListAsync();
var bids = list.Rows.Select(x => x.BusinessId).ToList();
var allbuss = await _sysUserRepository.GetAllNoFilterAsync(x => bids.Contains(x.Id), x => new SysUser
{
Id = x.Id,
Name = x.Name
});
list.Rows.ToList().ForEach(it =>
{
var shopuser = shopuserlist.FirstOrDefault(x => x.Id == it.Id);
if (shopuser != null)
{
it.BirthDay = shopuser.BirthDay;
it.Gender = shopuser.Gender;
}
//var shopuserrole = shopuserrolelist.FirstOrDefault(x => x.UserId == it.Id);
/* if (shopuserrole != null)
{
it.RoleId = shopuserrole.RoleId;
}*/
var user = allbuss.FirstOrDefault(x => x.Id == it.BusinessId);
if (user != null)
{
it.BusinessName = user.Name;
}
});
return list;
}
}
}

View File

@ -0,0 +1,149 @@
// ------------------------------------------------------------------------
// 版权信息
// ------------------------------------------------------------------------
using JT.Shop.Application.Service.ShopHead.Finance;
using JT.Shop.Domain.Entity.Business;
using JT.Shop.Domain.Entity.DianShu;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static JT.Shop.Application.Service.ShopHead.Finance.ShopHeadDianShuQueryService;
using static JT.Shop.Domain.Entity.Business.ISystemBusinessVersionQueryService;
using static JT.Shop.Domain.Entity.DianShu.IPcDianShuQueryService;
namespace JT.Shop.Application.Service.Business.Version
{
public class BusinessVersionListQueryService(ISystemBusinessVersionQueryService queryService, IPcDianShuQueryService dianShuQueryService, SystemBusinessVersionUpgradeComputeService computeService, SystemBusinessVersionTimeRangeComputeService timeRangeComputeService) : ITransient
{
public async Task<BusinessVersionListOutput> GetList(long dianshuId, BusinessVersionListQueryInput input, BusinessSystemApp app)
{
if (input.OrderType is SystemBusinessVersionConfigOrderType.Open)
{
return await GetList(dianshuId, await queryService.GetByList(app, input.AuthorizationMode, null, null, notConfigId: null, shopHeadId: input.ShopHeadId,
input as IPageInput), x => x.DianShu, x => timeRangeComputeService.ComputeOrder(null, new SystemBusinessVersionDuration(x.UnitOfTime, x.Time), input.OrderType));
}
if (!(input.OrderId > 0)) throw Oops.Bah("消费订单参数必填");
var order = await dianShuQueryService.GetConsume(input.OrderId.Value);
if (order == null) throw Oops.Bah("消费订单记录不存在").WithData(new { input.OrderId });
if (input.OrderType is SystemBusinessVersionConfigOrderType.Renewal)
{
return await GetList(dianshuId, await queryService.GetByList(app, input.AuthorizationMode, null, null, notConfigId: null, shopHeadId: input.ShopHeadId,
input as IPageInput), x => x.DianShu, x => timeRangeComputeService.ComputeOrder(order.SBV.ExpireTime, new SystemBusinessVersionDuration(x.UnitOfTime, x.Time), input.OrderType), order);
}
if (order.SBV.Mode == SystemAuthorizationMode.Probation)
{//试用期升级里面生效
return await GetList(dianshuId, await queryService.GetByList(app, input.AuthorizationMode, null, null, notConfigId: null, shopHeadId: input.ShopHeadId,
input as IPageInput), x => x.DianShu, x => timeRangeComputeService.ComputeOrder(DateTime.Now, new SystemBusinessVersionDuration(x.UnitOfTime, x.Time), input.OrderType), order);
}
return await GetList(dianshuId, await queryService.GetByList(app, input.AuthorizationMode, order.SBV.Time, order.SBV.UnitOfTime, notConfigId: order.SBV.ConfigId, shopHeadId: input.ShopHeadId,
input as IPageInput), x => computeService.Compute(order.SBV.StartTime, order.SBV.ExpireTime, order.SBV.DianShu, x.DianShu), x => timeRangeComputeService.ComputeOrder(order.SBV.ExpireTime, new SystemBusinessVersionDuration(x.UnitOfTime, x.Time), input.OrderType), order);
}
private async Task<BusinessVersionListOutput> GetList(long dianshuId, SystemBusinessVersionQueryListDto dto, Func<ShopHeadBusinessVersionListOutputItem, uint> ActualDianShu, Func<ShopHeadBusinessVersionListOutputItem, SystemBusinessVersionTimeRange> timeRangeFunc, ShopHeadDianShuConsumeDto order = null)
{
var output =
dto.Adapt<BusinessVersionListOutput>();
foreach (var item in output.Rows)
{
item.ActualDianShu = ActualDianShu(item);// input.OrderType == SystemBusinessVersionConfigOrderType.Upgrade ? computeService.Compute(order.SBV.StartTime, order.SBV.ExpireTime, order.DianShu,
// item.DianShu) : item.DianShu;
var timeRange = timeRangeFunc(item);// timeRangeComputeService.ComputeOrder(order.SBV.ExpireTime,
// new SystemBusinessVersionDuration(item.UnitOfTime, item.Time), input.OrderType);
item.ExpireTime = timeRange.ExpireTime;
item.StartTime = timeRange.StartTime;
}
if (order != null) output.ConsumeOrder = order.Adapt<BusinessVersionConsumeOrderOutput>();
output.CurrentDianShu = (await dianShuQueryService.GetById(dianshuId, null)).Adapt<ShopHeadDianShuOutput>();
return output;
}
public class BusinessVersionListQueryInput : PageInputV2Base
{
public SystemBusinessVersionConfigOrderType OrderType { get; set; }
/// <summary>
/// 授权模式
/// </summary>
public SystemAuthorizationMode? AuthorizationMode { get; set; }
public long? OrderId { get; set; }
public long ShopHeadId { get; set; }
}
public class BusinessVersionListOutput : PageResultV2<ShopHeadBusinessVersionListOutputItem>
{
public BusinessVersionConsumeOrderOutput ConsumeOrder { get; set; }
public ShopHeadDianShuQueryService.ShopHeadDianShuOutput CurrentDianShu { get; set; }
}
public class BusinessVersionConsumeOrderOutput
{
public long Id { get; set; }
public string No { get; set; }
public long DianShuId { get; set; }
/// <summary>
/// 订单消费点数
/// </summary>
public uint DianShu { get; set; }
public PcDianShuConsumeType Type { get; set; }
public SystemBusinessVersionConfig SBV { get; set; }
}
public class ShopHeadBusinessVersionListOutputItem
{
public long Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
// public string Description { get; set; }
/// <summary>
/// 需要点数
/// </summary>
public uint DianShu { get; set; }
/// <summary>
/// 真实点数
/// </summary>
public uint ActualDianShu { get; set; }
/// <summary>
/// 时间单位
/// </summary>
public SystemBusinessVersionUnitOfTime UnitOfTime { get; set; }
/// <summary>
/// 时间数量
/// </summary>
public uint Time { get; set; }
public DateTime ExpireTime { get; set; }
public DateTime StartTime { get; set; }
/// <summary>
/// 授权模式
/// </summary>
public SystemAuthorizationMode AuthorizationMode { get; set; }
}
}
}

View File

@ -0,0 +1,53 @@
namespace JT.Shop.Application.Service.Business.WX
{
/// <summary>
/// 小程序管理
/// </summary>
public interface IWXService
{
/// <summary>
/// 信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task SubmitAsync(WXSubmitC2SDto input);
/// <summary>
/// 小程序列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<PageResult<WXListS2CDto>> ListAsync(WXListC2SDto input);
/// <summary>
/// 小程序删除
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task DeleteAsync(WXDeleteC2SDto input);
/// <summary>
/// 所有小程序列表
/// </summary>
/// <returns></returns>
Task<List<WXListS2CDto>> AllListAsync();
/// <summary>
/// 获取域名列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<MiniDomainListS2CDto> GetDomainAsync(BaseRequestId input);
/// <summary>
/// 获取体验码
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<string> GetQRCodeAsync(BaseRequestId input);
Task<(string AccessToken, string Result)> GetRequestToken(BaseRequestId input);
Task<ActionResult> OpenOAuthCallbackAsync(string id, string auth_code, int expires_in, string appId);
}
}

View File

@ -0,0 +1,89 @@
using Microsoft.AspNetCore.Authorization;
namespace JT.Shop.Application.Service.Business.WX
{
/// <summary>
/// 小程序管理
/// </summary>
[ApiDescriptionSettings("管理平台")]
[Route("/api/business/[controller]")]
[AllowAnonymous]
public class WXAppService : IDynamicApiController
{
private readonly IWXService _wxService;
public WXAppService(IWXService wxService)
{
_wxService = wxService;
}
/// <summary>
/// 小程序列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PageResult<WXListS2CDto>> ListAsync(WXListC2SDto input)
{
return await _wxService.ListAsync(input);
}
/// <summary>
/// 所有小程序列表
/// </summary>
/// <returns></returns>
public async Task<List<WXListS2CDto>> AllListAsync()
{
return await _wxService.AllListAsync();
}
/// <summary>
/// 信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task SubmitAsync(WXSubmitC2SDto input)
{
await _wxService.SubmitAsync(input);
}
/// <summary>
/// 小程序删除
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task DeleteAsync(WXDeleteC2SDto input)
{
await _wxService.DeleteAsync(input);
}
/// <summary>
/// 获取域名列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task<MiniDomainListS2CDto> GetDomainAsync(BaseRequestId input)
{
return await _wxService.GetDomainAsync(input);
}
/// <summary>
/// 获取体验码
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task<string> GetQRCodeAsync(BaseRequestId input)
{
return await _wxService.GetQRCodeAsync(input);
}
[HttpGet]
public async Task<ActionResult> OpenOAuthCallbackAsync(string id, string auth_code, int expires_in,
string appId)
{
return await _wxService.OpenOAuthCallbackAsync(id, auth_code, expires_in, appId);
}
}
}

View File

@ -0,0 +1,399 @@
using JT.Shop.Application.Service.BaseCommon;
using Microsoft.Extensions.Caching.Memory;
using Senparc.CO2NET.Utilities;
using Senparc.Weixin.Exceptions;
using Senparc.Weixin.MP.Containers;
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using Volo.Abp.Users;
using Yitter.IdGenerator;
namespace JT.Shop.Application.Service.Business.WX
{
/// <summary>
/// 小程序管理
/// </summary>
public class WXService : IWXService, ITransient
{
private readonly IHttpClientFactory _clientFactory;
private readonly IRepository<PC_BusinessWX> _businessWXRepository;
private readonly IMyRepository<SysUser> _sysuserRep;
private readonly IMyRepository<SysLogEx> _sysLogEx;
public WXService(
IRepository<PC_BusinessWX> businessWXRepository,
IMyRepository<SysUser> sysuserRep,
IHttpClientFactory httpClientFactory,
IMyRepository<SysLogEx> sysLogEx)
{
_businessWXRepository = businessWXRepository;
_sysuserRep = sysuserRep;
_clientFactory = httpClientFactory;
_sysLogEx = sysLogEx;
}
/// <summary>
/// 所有小程序列表
/// </summary>
/// <returns></returns>
public async Task<List<WXListS2CDto>> AllListAsync()
{
var list = await _businessWXRepository.DetachedEntities
.OrderByDescending(x => x.CreatedTime)
.ProjectToType<WXListS2CDto>()
.ToListAsync();
return list;
}
/// <summary>
/// 小程序删除
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task DeleteAsync(WXDeleteC2SDto input)
{
var data = await _businessWXRepository.Where(x => x.Id == input.Id, true).Select(x => new PC_BusinessWX
{
Id = x.Id,
AppId = x.AppId
}).FirstOrDefaultAsync();
if (data.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
await _businessWXRepository.FakeDeleteNowAsync(data);
//删除公众号
if (await AccessTokenContainer.CheckRegisteredAsync(data.AppId))
{
await AccessTokenContainer.RemoveFromCacheAsync(data.AppId);
}
}
/// <summary>
/// 小程序列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<PageResult<WXListS2CDto>> ListAsync(WXListC2SDto input)
{
var list = await _businessWXRepository.DetachedEntities
.Where(!input.Name.IsEmpty(), x => x.Name == input.Name.ToStr())
.Where(!input.AppId.IsEmpty(), x => x.AppId == input.AppId.ToStr())
.OrderByDescending(x => x.CreatedTime)
.ProjectToType<WXListS2CDto>()
.ToADPagedListAsync(input.PageNo, input.PageSize);
return list;
}
/// <summary>
/// 信息提交
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task SubmitAsync(WXSubmitC2SDto input)
{
//检查appid是否重复
if (await _businessWXRepository.DetachedEntities.Where(x => x.AppId == input.AppId)
.Where(!input.Id.IsEmpty(), x => x.Id != input.Id)
.AnyAsync())
{
throw Oops.Bah(PCErrorCode.PD0001);
}
if (input.Id.IsEmpty())
{
var insertdata = input.Adapt<PC_BusinessWX>();
insertdata.Id = YitIdHelper.NextId();
await _businessWXRepository.InsertNowAsync(insertdata);
await RegisterWxOpen(insertdata.AppId, insertdata.AppSecret);
}
else
{
var olddata = await _businessWXRepository.Where(x => x.Id == input.Id, true).Select(x => new PC_BusinessWX
{
Id = x.Id,
AppId = x.AppId,
AppSecret = x.AppSecret
}).FirstOrDefaultAsync();
if (olddata.IsEmpty())
{
throw Oops.Bah(PCErrorCode.PD0000);
}
var appid = olddata.AppSecret;
var appsecret = olddata.AppSecret;
var updatedata = input.Adapt<PC_BusinessWX>();
await _businessWXRepository.UpdateIncludeNowAsync(updatedata, new[] { nameof(updatedata.Name), nameof(updatedata.AppId), nameof(updatedata.AppSecret), nameof(updatedata.Desc) });
if (appid != updatedata.AppId || appsecret != updatedata.AppSecret)
{
await RegisterWxOpen(updatedata.AppId, updatedata.AppSecret);
}
}
}
/// <summary>
/// 注册公众号
/// </summary>
/// <param name="appid"></param>
/// <param name="appsecret"></param>
/// <returns></returns>
private async Task RegisterWxOpen(string appid, string appsecret)
{
if (appid.IsEmpty() || appsecret.IsEmpty())
{
return;
}
//尝试重新注册公众号
if (!await AccessTokenContainer.CheckRegisteredAsync(appid))
{
await AccessTokenContainer.TryGetAccessTokenAsync(appid, appsecret);
}
}
public async Task<(string AccessToken, string Result)> GetRequestToken(BaseRequestId input)
{
var office = await _businessWXRepository.Where(x => x.Id == input.Id, true).Select(x => new PC_BusinessWX
{
Id = x.Id,
AppId = x.AppId,
AppSecret = x.AppSecret
}).FirstOrDefaultAsync();
if (office == null)
{
throw Oops.Bah("小程序未找到");
}
var valueTuple = await GetRequestToken(office.AppId, office.AppSecret);
if (valueTuple.AccessToken.IsEmpty())
{
throw Oops.Bah("获取token失败" + valueTuple.Result);
}
return (valueTuple.AccessToken, valueTuple.Result);
}
private async Task<(string AccessToken, string Result)> GetRequestToken(string appid, string appsecret)
{
var url = $"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={appsecret}";
var request = new HttpRequestMessage(HttpMethod.Get, url);
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
var tokenResult = result.ToObject<TokenResult>();
if (tokenResult != null)
{
return (tokenResult.access_token, result);
}
}
return (null, null);
}
private async Task<string> HttpPost(string url, string requestJson)
{
var request = new HttpRequestMessage(HttpMethod.Post, url);
if (!requestJson.IsNullOrEmpty())
{
request.Content = new StringContent(requestJson, Encoding.UTF8, "application/json");
}
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
return result;
}
return null;
}
private async Task<string> HttpGet(string url)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
return result;
}
return "";
}
/// <summary>
/// 获取域名列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<MiniDomainListS2CDto> GetDomainAsync(BaseRequestId input)
{
var office = await _businessWXRepository.Where(x => x.Id == input.Id, true).Select(x => new PC_BusinessWX
{
Id = x.Id,
AppId = x.AppId,
AppSecret = x.AppSecret
}).FirstOrDefaultAsync();
if (office == null)
{
throw Oops.Bah("小程序未找到");
}
var valueTuple = await GetRequestToken(office.AppId, office.AppSecret);
if (valueTuple.AccessToken.IsEmpty())
{
throw Oops.Bah("获取token失败" + valueTuple.Result);
}
var url = "https://api.weixin.qq.com/wxa/getwxadevinfo?access_token=" + valueTuple.AccessToken;
var result = await HttpPost(url, null);
if (!result.IsNullOrEmpty())
{
var miniDomain = JsonConvert.DeserializeObject<MiniDomainListS2CDto>(result);
return miniDomain;
}
return new MiniDomainListS2CDto();
}
/// <summary>
/// 获取体验码
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<string> GetQRCodeAsync(BaseRequestId input)
{
var office = await _businessWXRepository.Where(x => x.Id == input.Id, true).Select(x => new PC_BusinessWX
{
Id = x.Id,
AppId = x.AppId,
AppSecret = x.AppSecret
}).FirstOrDefaultAsync();
if (office == null)
{
throw Oops.Bah("小程序未找到");
}
var valueTuple = await GetRequestToken(office.AppId, office.AppSecret);
if (valueTuple.AccessToken.IsEmpty())
{
throw Oops.Bah("获取token失败" + valueTuple.Result);
}
var scene = JsonConvert.SerializeObject(new {
scene = "1"
});
var url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + valueTuple.AccessToken;
var result = await HttpPost(url, scene);
if (!result.IsNullOrEmpty())
{
return result;
}
return null;
}
IMemoryCache cache = new MemoryCache(new MemoryCacheOptions());
public void GetAuthorizerAccessToken()
{
//1.先获取微信回调的component_verify_ticket
//2.https://api.weixin.qq.com/cgi-bin/component/api_component_token 再用 第三方平台 appid、第三方平台 appsecret、微信后台推送的 ticket 去获取component_access_token
//3.https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=COMPONENT_ACCESS_TOKEN 再用component_access_token、第三方平台 appid去获取pre_auth_code 预授权码
//4.再用预授权码、第三方平台方 appid 去https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=xxxx&pre_auth_code = xxxxx & redirect_uri = xxxx & auth_type = xxx 获取正式授权码
//5.https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=COMPONENT_ACCESS_TOKEN使用 component_access_token、component_appid、正式授权码 去获取 authorizer_refresh_token、authorizer_access_token
//6.使用authorizer_refresh_token 请求接口
//wxd1788d0fabf835f3
//ticket@@@MQTPTAol0o-hB524vw-sIiV90bXGv-64ZjvxyU6hRAUSvCiD8CrGTPPzoLajxe4aDtJaKo32ON3Wv-yhqmpilw
// 设置缓存项,并指定过期时间
//cache.Set("key", "value", new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(30)));
// 获取缓存项
//string result = cache.Get<string>("key");
// 移除缓存项
//cache.Remove("key");
}
public async Task<ActionResult> OpenOAuthCallbackAsync(string id, string auth_code, int expires_in, string appId)
{
var param = $"授权回调,auth_code={auth_code},expires_in={expires_in},appid={appId},id={id}";
var info = new SysLogEx();
info.Id = YitIdHelper.NextId();
info.Account = "1";
info.Name = param.Length > 128 ? "超出长度" : param;
info.ExceptionTime = DateTime.Now;
await _sysLogEx.InsertNowAsync(info);
return null;
}
/// <summary>
/// 发布已经通过审核的小程序
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<string> ReleaseAsync(BaseRequestId input)
{
var office = await _businessWXRepository.Where(x => x.Id == input.Id, true).Select(x => new PC_BusinessWX
{
Id = x.Id,
AppId = x.AppId,
AppSecret = x.AppSecret
}).FirstOrDefaultAsync();
if (office == null)
{
throw Oops.Bah("小程序未找到");
}
var valueTuple = await GetRequestToken(office.AppId, office.AppSecret);
if (valueTuple.AccessToken.IsEmpty())
{
throw Oops.Bah("获取token失败" + valueTuple.Result);
}
var scene = JsonConvert.SerializeObject(new {
});
var url = "https://api.weixin.qq.com/wxa/release?access_token=" + valueTuple.AccessToken;
var result = await HttpPost(url, scene);
if (!result.IsNullOrEmpty())
{
return result;
}
return null;
}
/// <summary>
/// 查询最新一次提交的审核状态
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<string> GetLatestAuditStatusAsync(BaseRequestId input)
{
var office = await _businessWXRepository.Where(x => x.Id == input.Id, true).Select(x => new PC_BusinessWX
{
Id = x.Id,
AppId = x.AppId,
AppSecret = x.AppSecret
}).FirstOrDefaultAsync();
if (office == null)
{
throw Oops.Bah("小程序未找到");
}
var valueTuple = await GetRequestToken(office.AppId, office.AppSecret);
if (valueTuple.AccessToken.IsEmpty())
{
throw Oops.Bah("获取token失败" + valueTuple.Result);
}
var url = "https://api.weixin.qq.com/wxa/get_latest_auditstatus?access_token=" + valueTuple.AccessToken;
var result = await HttpGet(url);
if (!result.IsNullOrEmpty())
{
return result;
}
return null;
}
}
public class TokenResult
{
public string access_token { get; set; }
public int expires_in { get; set; }
}
}

View File

@ -0,0 +1,817 @@
/****************************************************************
* liuzl
* PCXBC
* 2022/10/9 15:27:40
*
*
* PC-2022
* :
*
*****************************************************************/
using Hinse.Util.Security;
using IPTools.Core;
using JT.Shop.Application.Upload;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using System.ComponentModel;
using System.Data.SqlTypes;
using System.Text;
using Volo.Abp.Threading;
using ZXing;
using ZXing.Common;
using ZXing.QrCode;
using static System.Text.RegularExpressions.Regex;
namespace JT.Shop.Application.Service
{
/// <summary>
/// 通用方法
/// </summary>
public static class CommonService
{
/// <summary>
/// 图片文件地址
/// </summary>
public static string ImgUrl = App.Configuration["ApiUrlSetting:Img"];
/// <summary>
/// 文件地址
/// </summary>
public static string FileUrl = App.Configuration["ApiUrlSetting:File"];
/// <summary>
/// 接口地址
/// </summary>
public static string ApiUrl = App.Configuration["ApiUrlSetting:Api"];
public static string UserWXBindH5 = App.Configuration["ApiUrlSetting:UserWXBindH5"];
/// <summary>
/// 图片文件展示
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static string ImgFile(this string url)
{
return url.NetFile(ImgUrl);
}
/// <summary>
/// 图片文件展示,带版本号防止缓存
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static string ImgFileWithVersion(this string url)
{
if (url.IsEmpty())
{
return string.Empty;
}
return $"{url.NetFile(ImgUrl)}?v={DateTime.Now:yyyyMMddHHmmss}";
}
/// <summary>
/// 文件展示
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static string File(this string url)
{
return url.NetFile(FileUrl);
}
public static string DeviceEntryUrl(this WXClientType type, long devid)
{
return type == WXClientType.MinProgram
? devid.DeviceWxMinProgramEntryUrl()
: devid.DeviceWxGzH5EntryUrl();
}
/// <summary>
/// 根据设备id获取入口-微信公众号H5
/// </summary>
/// <param name="devid">设备ID</param>
/// <returns></returns>
public static string DeviceWxGzH5EntryUrl(this long devid)
{
var useridstr = Convert.ToBase64String(Encoding.UTF8.GetBytes(devid.ToString()));
return $"{ApiUrl}/api/public/qr/r/{useridstr}";
//return $"{ApiUrl}/qr/d?sn={devid}";
}
/// <summary>
/// 根据设备id获取入口-微信小程序
/// </summary>
/// <param name="devid"></param>
/// <returns></returns>
public static string DeviceWxMinProgramEntryUrl(this long devid)
{
return $"{ApiUrl}/qr/d?sn={devid}";
}
/// <summary>
/// H5-根据门店ID获取入口
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static string ShopH5Url(this long id)
{
//return $"{ApiUrl}/api/public/shop/index/{id}";
return $"{ApiUrl}/qr/s?id={id}";
}
public static string ShopUrl(this long id)
{
var type = AsyncHelper.RunSync(async () => await App.GetRequiredService<PCShopSettingProvider>().GetWXClientType(id));
if (type == WXClientType.Gz)
{
return $"{ApiUrl}/qr/s?id={id}";
}
else if (type == WXClientType.MinProgram)
{
return id.ShopWXMinProgramUrl();
}
return string.Empty;
}
/// <summary>
/// 微信小程序-门店手机端入口
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static string ShopWXMinProgramUrl(this long id)
{
return $"{ApiUrl}/qr/s-e?id={id}";
// return $"{ApiUrl}/qr/s?id={id}";
}
public static string MemberWXMinProgramBindUrl(this long shopid, string payload)
{
return $"{ApiUrl}/qr/wxb-m?shopid={shopid}&payload={payload}";
}
public static string MemberWXGzBindUrl(this long shopid, string payload)
{
return $"{UserWXBindH5}?id={shopid}&payload={payload}";
}
public static Task<string> ToQrCodeImageToBase64String(this string text, int width, int height, int margin = 1)
{
BarcodeWriterPixelData writer = new BarcodeWriterPixelData();
writer.Format = BarcodeFormat.QR_CODE;
QrCodeEncodingOptions codeEncodingOptions = new QrCodeEncodingOptions();
codeEncodingOptions.DisableECI = true;
codeEncodingOptions.CharacterSet = "UTF-8";
codeEncodingOptions.Width = width;
codeEncodingOptions.Height = height;
codeEncodingOptions.Margin = margin;
writer.Options = (EncodingOptions)codeEncodingOptions;
return Task.FromResult(writer.WriteAsImageSharp<Rgba32>(text).ToBase64String(PngFormat.Instance));
}
/// <summary>
/// 加载头像,如果为空则加载默认头像
/// </summary>
/// <param name="url"></param>
/// <param name="sex">性别</param>
/// <returns></returns>
public static string HeadImg(this string url, Gender sex)
{
if (url.IsEmpty())
{
if (sex == Gender.MALE)
{
return $"{ImgUrl}/image/headimg_male.png";
}
//返回默认头像
return $"{ImgUrl}/image/headimg.png";
}
return url.ImgFile();
}
/// <summary>
/// 本地默认头像
/// </summary>
/// <param name="url"></param>
/// <param name="sex"></param>
/// <returns></returns>
public static string LocalHeadImg(this string url, Gender sex)
{
if (url.IsEmpty())
{
if (sex == Gender.MALE)
{
return "/image/headimg_male.png";
}
//返回默认头像
return "/image/headimg.png";
}
return url;
}
/// <summary>
/// 获取本地地址
/// </summary>
/// <returns></returns>
public static string LocalUrl(this string file)
{
if (file.IsEmpty())
{
return string.Empty;
}
var _uploadOptions = App.GetRequiredService<UploadDomainService>();
return $"{_uploadOptions.GetUploadPhysicalRootPath()}{file}";
}
/// <summary>
/// 获取导出路径
/// </summary>
/// <returns></returns>
public static string GetExportPath(string type)
{
return $"/download/result/{DateTime.Now:yyyyMMdd_HHmmss}_{type}.xlsx";
}
/// <summary>
/// 时间格式化,带时分,如果同一年则不显示年,否则显示年份
/// </summary>
/// <param name="date"></param>
/// <returns></returns>
public static string ToYearDateTimeFromOffset(this DateTime date)
{
if (date == SqlDateTime.MinValue.Value)
{
return "";
}
if (date.Year == DateTime.Now.Year)
return date.ToString("MM/dd HH:mm");
return date.ToString("yyyy/MM/dd HH:mm");
}
/// <summary>
/// 时间格式化,带时分,如果同一年则不显示年,否则显示年份
/// </summary>
/// <param name="date"></param>
/// <returns></returns>
public static string ToYearDateTimeFromOffset(this DateTime? date)
{
if (date.IsEmpty())
{
return string.Empty;
}
return ToYearDateTimeFromOffset(date.Value);
}
/// <summary>
/// 出生日期转换
/// </summary>
/// <param name="birthday"></param>
/// <returns></returns>
public static string ToBirthday(this DateTime birthday)
{
if (birthday == DateTime.MinValue)
{
return string.Empty;
}
if (birthday == SqlDateTime.MinValue)
{
return string.Empty;
}
return birthday.ToString("yyyy-MM-dd");
}
/// <summary>
/// 获取格式化时间
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static string GetFormatTime(this DateTime time)
{
return GetFormatTime(time, true);
}
/// <summary>
/// 获取格式化时间
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static string GetFormatTime(this DateTime time, bool showThisYear = true)
{
return showThisYear ? time.ToString("yyyy/MM/dd") : time.ToString("MM/dd");
}
/// <summary>
/// 获取格式化时间
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static string GetFormatTime(this DateTime? time)
{
return GetFormatTime(time, true);
}
/// <summary>
/// 获取格式化时间
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static string GetFormatTime(this DateTime? time, bool showThisYear)
{
if (time.IsEmpty())
{
return string.Empty;
}
return showThisYear ? time!.Value.ToString("yyyy/MM/dd") : time!.Value.ToString("MM/dd");
}
/// <summary>
/// 获取总天数
/// </summary>
/// <param name="endtime"></param>
/// <param name="starttime"></param>
/// <returns></returns>
public static int GetDays(this DateTime endtime, DateTime starttime, bool plusOne = true)
{
return (endtime - starttime).Days + (plusOne ? 1 : 0);
}
/// <summary>
/// 时间格式化 yyyy-MM-dd
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static string GetFormatTime1(this DateTime time)
{
return time.ToString("yyyy-MM-dd");
}
/// <summary>
/// 时间格式化 yyyy-MM-dd
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static string GetFormatTime1(this DateTime? time)
{
return time?.ToString("yyyy-MM-dd") ?? string.Empty;
}
/// <summary>
/// 获取时分时间
/// </summary>
/// <param name="time">时间</param>
/// <returns></returns>
public static string GetHourTime(this DateTime? time)
{
if (time.IsEmpty())
{
return string.Empty;
}
return time.Value.ToString("HH:mm");
}
/// <summary>
/// 计算家庭成员的类型
/// </summary>
/// <param name="birthday">出生年月</param>
/// <param name="nowtime">当前时间</param>
/// <returns></returns>
public static FamilyType GetFamilyType(this DateTime birthday, DateTime? nowtime)
{
if (birthday == DateTime.MinValue || birthday == SqlDateTime.MinValue)
{
return FamilyType.Baby;
}
nowtime = nowtime.IsEmpty() ? DateTime.Now : nowtime;
//获取年龄
var age = birthday.ToAge(nowtime);
return age >= FamilyTypeLevel.Adult ? FamilyType.Adult : (age < FamilyTypeLevel.Child ? FamilyType.Baby : FamilyType.Children);
}
/// <summary>
/// 转换成带几岁几个月的年龄
/// </summary>
/// <param name="birthday"></param>
/// <returns></returns>
public static string ToAgeStr(this DateTime birthday)
{
if (birthday == DateTime.MinValue || birthday == SqlDateTime.MinValue)
{
return string.Empty;
}
return birthday.ToAAge();
}
/// <summary>
/// 转换为非空字符串
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string ToStrNoEmpty(this string str)
{
if (str.IsEmpty())
{
return string.Empty;
}
return str.Trim();
}
/// <summary>
/// 解析IP地址
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static (string ipLocation, double? longitude, double? latitude) GetIpAddress(string ip)
{
try
{
var ipInfo = IpTool.Search(ip);
var addressList = new List<string>() { ipInfo.Country, ipInfo.Province, ipInfo.City, ipInfo.NetworkOperator };
return (string.Join("|", addressList.Where(it => it != "0").ToList()), ipInfo.Longitude, ipInfo.Latitude); // 去掉0并用|连接
}
catch { }
return ("未知", 0, 0);
}
/// <summary>
/// 千克转换为斤
/// </summary>
/// <param name="kgval">千克值</param>
/// <returns></returns>
public static decimal KG2Jin(this decimal kgval)
{
return kgval * 2;
}
/// <summary>
/// 千克转换为斤,保留一位小数
/// </summary>
/// <param name="kgval"></param>
/// <returns></returns>
public static decimal KG2Jin1(this decimal kgval)
{
return kgval * 2.ToDecimal(1);
}
/// <summary>
/// 是否为正数
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
public static bool ZhengFu(this decimal val)
{
//正数返回1负数返回-1零返回0。
bool ret;
if (Math.Sign(val) == 1)
{
ret = true;
}
else if (Math.Sign(val) == -1)
{
ret = false;
}
else
{
ret = false;
}
return ret;
}
/// <summary>
/// 名字打码
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static string HideName(this string name)
{
//如果为空则返回空
if (name.IsEmpty())
{
return string.Empty;
}
//如果长度等于2则最后一个字符显示*
if (name.Length == 2)
{
return name.Substring(0, 1) + "*";
}
//如果长度大于2则第二个字符到倒数第二个字符显示*
if (name.Length > 2)
{
return name.Substring(0, 1) + "*" + name.Substring(name.Length - 1, 1);
}
return name;
}
/// <summary>
/// 名字中去除数字
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static string RemoveNum(this string name)
{
if (name.IsEmpty())
{
return string.Empty;
}
return Replace(name, @"\d", "");
}
/// <summary>
/// 千克转换为斤,小于0则返回0
/// </summary>
/// <param name="kgval">千克值</param>
/// <returns></returns>
public static decimal KG2JinNoZero(this decimal kgval)
{
if (kgval < 0)
{
return 0;
}
return kgval * 2;
}
/// <summary>
/// 斤转换为千克
/// </summary>
/// <param name="jinval">斤值</param>
/// <returns></returns>
public static decimal Jin2KG(this decimal jinval)
{
return jinval / 2.0M;
}
/// <summary>
/// 斤转换为千克
/// </summary>
/// <param name="jinval">斤值</param>
/// <returns></returns>
public static decimal Jin2KG(this int jinval)
{
return jinval / 2;
}
/// <summary>
/// 生成塑形订单号,规则:年月日+6位随机数
/// </summary>
/// <returns></returns>
public static string GetSXOrderNo()
{
return $"JT{DateTime.Now:yyyyMMdd}{new Random().Next(100000, 999999)}";
}
/// <summary>
/// 计算所需的周期,每5kg减一个周期,不足5kg按5kg计算,小于等于0则为1个周期
/// </summary>
/// <param name="shouldweight">应减重量,kg</param>
/// <returns></returns>
public static int CycleValue(this decimal shouldweight)
{
//if (shouldweight <= 0)
//{
// return 1;
//}
//var val = shouldweight / 5;
//周期数=值+1
//return val.ToInt() + 1;
//依据新的范围计算:
//标准周期根据标准体重计算应减体重应减体重20斤以内是2个周期20.130斤 3个周期30.140斤 4个周期40.150斤 5个周期依次类推
decimal weight = shouldweight.KG2Jin();
// 确定每个周期的重量起点
decimal baseWeight = 20.0.ToDecimal();
// 确定每个周期的增量重量
decimal incrementWeight = 10.0.ToDecimal();
// 初始化周期数为最低周期数
int cycle = 3; // 最低周期数对应20.130斤
if (weight <= 20)
{
return 2;
}
// 计算体重所属的周期
while (weight > (baseWeight + incrementWeight))
{
cycle++;
baseWeight += incrementWeight; // 更新下一个周期的起始重量
}
// 确保体重在当前周期范围内
if (weight < baseWeight || weight <= baseWeight + incrementWeight)
{
// 体重在当前周期内,返回计算出的周期数
return cycle;
}
else
{
//异常
return 0;
}
}
/// <summary>
/// 计算周期时间
/// </summary>
/// <param name="cyclevalue">周期值</param>
/// <param name="type">周期类型</param>
/// <param name="StartTime">开始时间</param>
/// <returns></returns>
public static (DateTime, DateTime, DateTime?, DateTime?) GetWeightStartEnd(this int cyclevalue, ShopCycleEnum type, DateTime StartTime)
{
//如果是标准周期
if (type == ShopCycleEnum.Stand)
{
//如果周期数为1,则为标准周期的一个周期,没有售后服务期
if (cyclevalue == 1)
{
//减重期结束时间=开始时间+1月-1天
var endtime = StartTime.AddMonths(1).AddDays(-1);
return (StartTime, endtime, null, null);
}
else
{
//减重期结束时间=开始时间+周期数*月+1月-1天
var endtime = StartTime.AddMonths(cyclevalue).AddMonths(1).AddDays(-1);
//售后服务期开始时间=减重期结束时间+1天
var shfwqstarttime = endtime.AddDays(1);
//售后服务期结束时间=售后服务期开始时间+2年-1天
var shfwqendtime = shfwqstarttime.AddYears(2).AddDays(-1);
return (StartTime, endtime, shfwqstarttime, shfwqendtime);
}
}
//单周期,固定30天
else
{
//减重期结束时间=开始时间的本月-1天
var endtime = StartTime.AddDays(30).AddDays(-1);
return (StartTime, endtime, null, null);
}
}
/// <summary>
/// 计算售后服务年限
/// </summary>
/// <param name="starttime">开始时间</param>
/// <param name="endtime">结束时间</param>
/// <returns></returns>
public static int AfterYear(this DateTime? starttime, DateTime? endtime)
{
if (starttime.IsEmpty() || endtime.IsEmpty())
{
return 0;
}
var year = endtime.Value.Year - starttime.Value.Year;
return Math.Abs(year);
}
/// <summary>
/// 计算体重的完成率
/// </summary>
/// <param name="weight"></param>
/// <param name="standweight"></param>
/// <returns></returns>
public static decimal WeightComper(this decimal weight, decimal standweight)
{
if (weight == 0 || standweight == 0)
{
return 0;
}
var val = weight / standweight;
return val >= 1 ? 100 : val * 100.ToDecimal(1);
}
/// <summary>
/// 计算时间是否为今天
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static bool IsToday(this DateTime time)
{
var nowtime = DateTime.Now;
return time.Date == nowtime.Date;
}
/// <summary>
/// 计算时间是否为今天
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static bool IsToday(this DateTime? time)
{
if (!time.HasValue)
{
return false;
}
return IsToday(time.Value);
}
/// <summary>
/// 系统默认Logo
/// </summary>
/// <returns></returns>
public static string DefaultLogo()
{
return string.Empty;
}
/// <summary>
/// 系统默认颜色
/// </summary>
/// <returns></returns>
public static string DefaultColor()
{
return "#ff677b";
}
/// <summary>
/// 系统默认字体颜色
/// </summary>
/// <returns></returns>
public static string DefaultFontColor()
{
return "#ffffff";
}
/// <summary>
/// 默认门店名称
/// </summary>
/// <returns></returns>
public static string DefaultShopName()
{
return string.Empty;
}
/// <summary>
/// 获取枚举成员的描述
/// </summary>
/// <param name="value">枚举成员的值</param>
/// <returns>枚举成员的描述,如果没有描述则返回枚举成员的名称</returns>
public static string GetDescription(Enum value)
{
var type = value.GetType();
var memInfo = type.GetMember(value.ToString());
if (memInfo.Length > 0)
{
var attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs.Length > 0)
{
return ((DescriptionAttribute)attrs[0]).Description;
}
}
//// 如果没有找到描述,返回枚举成员的名字
//return value.ToString();
return "";
}
public static long GetLongId(this IDynamicApiController _, string id)
{
return GetLongId(id);
}
public static long GetLongId(this ControllerBase _, string id)
{
return GetLongId(id);
}
public static long GetLongId(string id)
{
if (string.IsNullOrWhiteSpace(id)) return 0;
if (IsMatch(id.Trim(), "^\\d+$"))
{
return id.ToLong();
}
return Base64Encryption.IsBase64(id) ? Encoding.UTF8.GetString(Convert.FromBase64String(id)).ToLong() : 0;
}
public static string AddUrlParam(this string url, string keyValue)
{
return url.LastIndexOf('&') > url.LastIndexOf('?') ? $"{url}&{keyValue}" : $"{url}?{keyValue}";
}
/// <summary>
/// 获取公斤的体重值
/// </summary>
/// <param name="weight"></param>
/// <param name="unit">体重单位</param>
/// <returns></returns>
public static decimal GetWeightKg(this WeightUnit unit, decimal weight)
{
if (unit == WeightUnit.LB)
{
return (weight * 0.4536m).ToDecimal(2);
}
if (unit == WeightUnit.JIN)
{
return (weight / 2.0m).ToDecimal(2);
}
if (unit == WeightUnit.ST)
{
return (weight * 6.35m).ToDecimal(2);
}
if (unit == WeightUnit.G)
{
return (weight / 1000.0m).ToDecimal(2);
}
return weight.ToDecimal(2);
}
}
}

View File

@ -0,0 +1,244 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Furion.Authorization;
using JetBrains.Annotations;
using JT.Shop.Domain.Entity.Business;
using MapsterMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
namespace JT.Shop.Application.Service
{
public interface IPermissionAppService
{
Task<GetPermissionListResultDto> GetAsync([NotNull] string providerName, [NotNull] string providerKey, [NotNull] string prefix);
Task UpdateAsync([NotNull] string providerName, [NotNull] string providerKey, UpdatePermissionsDto input);
}
public class GetPermissionListResultDto
{
public string EntityDisplayName { get; set; }
public List<PermissionGroupDto> Groups { get; set; }
}
public class PermissionGroupDto
{
public string Name { get; set; }
public string DisplayName { get; set; }
public string DisplayNameKey { get; set; }
public string DisplayNameResource { get; set; }
public List<PermissionGrantInfoDto> Permissions { get; set; }
}
public class UpdatePermissionsDto
{
public UpdatePermissionDto[] Permissions { get; set; } = [];
}
public class UpdatePermissionDto
{
public string Name { get; set; }
public bool IsGranted { get; set; }
}
public class PermissionGrantInfoDto
{
public string Name { get; set; }
public string DisplayName { get; set; }
public string ParentName { get; set; }
public bool IsGranted { get; set; }
public List<string> AllowedProviders { get; set; }
public List<ProviderInfoDto> GrantedProviders { get; set; }
}
public class ProviderInfoDto
{
public string ProviderName { get; set; }
public string ProviderKey { get; set; }
}
public class SystemBusinessVersionAuthorizationRequirement : IAuthorizationRequirement
{
public SystemBusinessVersionAuthorizationRequirement(BusinessSystemApp app)
{
App = app;
}
public BusinessSystemApp App { get; }
}
/// <summary>
/// 到期不允许访问
/// </summary>
[SuppressSniffer, AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Method)]
public class SystemBusinessVersionAuthorizeAttribute : AuthorizeAttribute
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="policies">多个策略</param>
public SystemBusinessVersionAuthorizeAttribute(BusinessSystemApp app, params string[] policies)
{
App = app;
if (policies != null && policies.Length > 0)
{
Policies = policies;
}
else
{
Policy = SystemBusinessVersionPolicyProvider.FullPrefix(App);
}
}
public BusinessSystemApp App { get; }
/// <summary>
/// 策略
/// </summary>
public string[] Policies
{
get
{
if (string.IsNullOrWhiteSpace(Policy)) return Array.Empty<string>();
return Policy[SystemBusinessVersionPolicyProvider.FullPrefix(App).Length..].Split(',', StringSplitOptions.RemoveEmptyEntries);
}
internal set => Policy = $"{SystemBusinessVersionPolicyProvider.FullPrefix(App)}{string.Join(',', value)}";
}
}
/// <summary>
/// 总部到期不允许访问
/// </summary>
[SuppressSniffer, AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Method)]
public class ShopHeadSystemBusinessVersionAuthorizeAttribute : SystemBusinessVersionAuthorizeAttribute
{
public ShopHeadSystemBusinessVersionAuthorizeAttribute(params string[] policies) : base(BusinessSystemApp.ShopHead, policies)
{
}
}
/// <summary>
/// 门店到期不允许访问
/// </summary>
[SuppressSniffer, AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Method)]
public class ShopSystemBusinessVersionAuthorizeAttribute : SystemBusinessVersionAuthorizeAttribute
{
public ShopSystemBusinessVersionAuthorizeAttribute(params string[] policies) : base(BusinessSystemApp.Shop, policies)
{
}
}
/// <summary>
///
/// </summary>
public class SystemBusinessVersionPolicyProvider : DefaultAuthorizationPolicyProvider
{
public const string POLICY_PREFIX = "<SystemBusinessVersion>";
public SystemBusinessVersionPolicyProvider([NotNull][ItemNotNull] IOptions<AuthorizationOptions> options) : base(options)
{
}
public static string FullPrefix(BusinessSystemApp app) => $"{POLICY_PREFIX}<{(byte)app:000}>";
public static bool TryPrefixRead(string policyName, out BusinessSystemApp app, out string[] policies)
{
policies = null;
app = default;
if (!policyName.StartsWith(POLICY_PREFIX))
{
return false;
}
var start = $"{POLICY_PREFIX}<".Length;
if (!byte.TryParse(policyName[start..(start + 3)], out var v))
{
return false;
}
if (Enum.IsDefined(typeof(BusinessSystemApp), v))
{
app = (BusinessSystemApp)v;
policies = policyName[(start + 4)..].Split(',', StringSplitOptions.RemoveEmptyEntries);
return true;
}
return false;
}
public override async Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
var policy = await base.GetPolicyAsync(policyName);
if (policy != null)
{
return policy;
}
// 判断是否是包含授权策略前缀
if (TryPrefixRead(policyName, out var app, out var policies))
{
// 添加策略需求
var policyBuilder = new AuthorizationPolicyBuilder();
policyBuilder.AddRequirements(new SystemBusinessVersionAuthorizationRequirement(app));
policyBuilder.AddRequirements(new AppAuthorizeRequirement(policies));
return policyBuilder.Build();
}
if (policyName.StartsWith(Penetrates.AppAuthorizePrefix))
{
// 解析策略名并获取策略参数
policies = policyName[Penetrates.AppAuthorizePrefix.Length..].Split(',', StringSplitOptions.RemoveEmptyEntries);
// 添加策略需求
var policyBuilder = new AuthorizationPolicyBuilder();
policyBuilder.AddRequirements(new AppAuthorizeRequirement(policies));
return policyBuilder.Build();
}
return null;
}
}
/// <summary>
/// 常量、公共方法配置类
/// </summary>
internal static class Penetrates
{
/// <summary>
/// 授权策略前缀
/// </summary>
internal const string AppAuthorizePrefix = "<Furion.Authorization.AppAuthorizeRequirement>";
}
public abstract class AppService : ITransientDependency
{
//public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!;
public IFeatureChecker FeatureChecker => App.GetRequiredService<IFeatureChecker>();
public IPermissionChecker PermissionChecker => App.GetRequiredService<IPermissionChecker>();
public IMapper Mapper => App.GetRequiredService<IMapper>();
}
}

View File

@ -0,0 +1,25 @@
// 品传科技
// 开发:李鹏鹏
// ------------------------------------------------------------------------
using Microsoft.AspNetCore.DataProtection;
using Volo.Abp.DependencyInjection;
namespace JT.Shop.Application.Service;
public class JTDataProtectionService(IDataProtectionProvider provider) : ITransientDependency
{
public string Protect(string purpose, string content)
{
var _protector = provider.CreateProtector(purpose);
return _protector.Protect(content);
}
public string Unprotect(string purpose, string protectedPayload)
{
var _protector = provider.CreateProtector(purpose);
return _protector.Unprotect(protectedPayload);
}
}

View File

@ -0,0 +1,228 @@
using JT.Shop.Application.Service.Shop;
using JT.Shop.Application.Service.ShopHead.Colleague;
using JT.Shop.Domain.Entity.Business;
using JT.Shop.Domain.Entity.GeneralAccount;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using UAParser;
namespace JT.Shop.Application.Service.Mch.Account
{
/// <summary>
/// 门店账号管理
/// </summary>
[ApiDescriptionSettings("门店管理平台")]
[Route("/api/mch/[controller]")]
public class AccountService(
IRepository<PC_ShopAccount> shopaccountRep,
IRepository<PC_ShopAccountRole> shopaccountroleRep,
IRepository<PcGeneralAccount> pcmanageAccountRep,
IRepository<PC_Shop> shopRep,
IHttpContextAccessor httpContextAccessor,
UserManager userManager,
IPcShopAccountRoleQueryService sysRoleService,
GeneralAccountLoginVerifyDomainService manageAccountLoginVerifyDomainService,
GeneralAccountAuthAppService authAppService,
ISmsService smsService)
: ITransient, IDynamicApiController
{
/// <summary>
/// 账户登录
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AllowAnonymous]
[OpAudit("登录", "账号", OpAuditLogEventTarget.Shop)]
public async Task<string> LoginAsync(LoginInput input, [FromServices] PcShopAccountVerifyCheckOwnerShopDomainService loginVerifyDomainService)
{
var shopid = input.Id;
var (accountId, tokenVersion) =
await manageAccountLoginVerifyDomainService.LoginVerifyPassword(input.Account, input.Password);
var (_, user, shop,_) = await loginVerifyDomainService.VerifyShopAccount(accountId, shopid);
return (await authAppService.Login(accountId, (await shopaccountroleRep.DetachedEntities.Where(x => x.UserId == user.Id && x.ShopId == user.ShopId).Select(x => x.RoleId).ToListAsync()), AccountIdentity.Shop, user.AdminType, name: user.Name, shopId: user.ShopId, shopHeadId: user.BusinessId, tokenVersion: tokenVersion, versionConfig: shop.SystemAuthorization?.ConfigId, userId: user.Id)).accessToken;
}
/// <summary>
/// 获取登录信息
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<LoginOutput> GetLoginUserAsync([FromServices] IAccountIdentityRolePermissionAppService abpApplicationConfigurationAppService, [FromServices] ISystemBusinessVersionQueryService systemBusinessVersionQueryService, [FromServices] GeneralAccountWxLoginBindDomainService generalAccountWxLoginBindDomainService)
{
var CurrentUser = userManager.GetCurrentAdminShopInfo();
var accountId = CurrentUser.AccountId;
//var userId = CurrentUser.UserId;
var data = await shopaccountRep.DetachedEntities.Where(x => x.AccountId == accountId && x.ShopId == CurrentUser.ShopId).FirstOrDefaultAsync();
if (data.IsEmpty())
throw Oops.Bah(ErrorCode.D1011);
var account = await pcmanageAccountRep.DetachedEntities.FirstOrDefaultAsync(x => x.Id == accountId);
var loginOutput = account.Adapt<LoginOutput>();
var httpContext = httpContextAccessor.HttpContext;
loginOutput.WxBind = await generalAccountWxLoginBindDomainService.IsBind(accountId);
loginOutput.PwdNotYetSet = string.IsNullOrWhiteSpace(account.Password);
loginOutput.LastLoginTime = account.LastLoginTime;
loginOutput.LastLoginIp = account.LastLoginIp;
var client = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
loginOutput.LastLoginBrowser = client.UA.Family + client.UA.Major;
loginOutput.LastLoginOs = client.OS.Family + client.OS.Major;
//角色门店角色信息
loginOutput.Roles = (await sysRoleService.GetRolesByUserId(data.Id)).Select(x => new RoleOutput { Id = x.Id, Name = x.Name }).ToList();
loginOutput.AccountEnable = data.Status == CommonStatus.Disable;
loginOutput.ShopId = data.ShopId;
loginOutput.Name = data.Name;
loginOutput.Sex = (int)data.Gender;
loginOutput.PwdNotYetSet = string.IsNullOrWhiteSpace(account.Password);
loginOutput.AccountEnable = data.Status == CommonStatus.Disable;
loginOutput.AdminType = (int)CurrentUser.AccountType;
loginOutput.ShopHeadId = data.BusinessId;
var shop = await shopRep.DetachedEntities.FirstOrDefaultAsync(x => x.Id == data.ShopId);
if (shop.IsEmpty()) throw Oops.Bah(PC_SHOP_ERROR_CODE.SHOP_NOTFOUND40004).WithData(data.ShopId);
if (shop.Status == CommonStatus.Disable) throw Oops.Bah(HCErrorCode.SHOP0004).WithData(data.ShopId);
if (shop.IsDeleted) throw Oops.Bah(HCErrorCode.SHOP0003).WithData(data.ShopId);
loginOutput.App = shop.Adapt<AppBaseInfoOutput>();
loginOutput.App.SystemAuthorization.BusinessVersion = (await systemBusinessVersionQueryService.GetDetail(shop.SystemAuthorization.ConfigId)).Adapt<BusinessVersionOutput>();
var Auth = await abpApplicationConfigurationAppService.GetAuthConfigAsync(ShopPermissionDefinitionNames.Prefix);
// 权限信息
loginOutput.Permissions = Auth.GrantedPolicies.Where(x => x.Value).Select(x => x.Key).ToList();
loginOutput.Features = (await abpApplicationConfigurationAppService.GetFeaturesConfigAsync(ShopPermissionDefinitionNames.Prefix)).Values;
////获取权限信息
//user.Permissions = await sysMenuService.GetPermissionList(accountId, AccountIdentity.Shop, data.AdminType == AdminType.SuperAdmin);
////获取系统所有权限
//user.AllPermissions = await sysMenuService.GetAllPermissionList(AccountIdentity.Shop);
//// 具备应用信息(多系统,默认激活一个,可根据系统切换菜单),返回的结果中第一个为激活的系统
//user.Apps = await sysAppService.GetShopLoginApps(accountId);
////获取菜单信息
//if (user.Apps.Any())
//{
// var activeApp = user.Apps.FirstOrDefault(u => u.Active == YesOrNot.Y.ToString());
// var defaultActiveAppCode = activeApp != null ? activeApp.Code : user.Apps.FirstOrDefault().Code;
// user.Menus = await sysMenuService.GetLoginMenusAntDesign(accountId, defaultActiveAppCode, CurrentUser.AccountIdentity, CurrentUser.IsSuperAdmin);
//}
return loginOutput;
}
/// <summary>
/// 退出
/// </summary>
/// <param name="openid">用户openid</param>
/// <returns></returns>
[QueryParameters]
[HttpGet]
public void Logout(string openid = "")
{
var CurrentUser = userManager.GetCurrentAdminShopInfo();
var ip = httpContextAccessor.HttpContext.GetRequestIPv4();
httpContextAccessor.HttpContext.SignoutToSwagger();
//_httpContextAccessor.HttpContext.Response.Headers["access-token"] = "invalid token";
}
[HttpGet("shoplogininfo")]
[AllowAnonymous]
public async Task<ShopLoginInfoOutput> GetShopLoginInfo([FromQuery] long id)
{
var entity = await shopRep.DetachedEntities.Where(x => x.Id == id).FirstOrDefaultAsync();
if (entity == null) throw Oops.Bah("门店标识不存在");
return entity.Adapt<ShopLoginInfoOutput>();
}
/// <summary>
/// 邀请门店注册链接码
/// </summary>
/// <returns></returns>
[HttpPost("invite-shop-reg")]
[AnyAccountIdentityAuthorize]
public async Task<InviteRegShopOutput> GetInviteRegShop([FromServices] IdentityInfoVisitor identityInfoVisitor/*, [FromServices] IRepository<SystemBusinessVersion> repository*/)
{
var headid = identityInfoVisitor.ShopHeadId;
/* var ver = await repository.DetachedEntities.Where(x =>
x.Enable == true && x.AuthorizationMode == SystemAuthorizationMode.Probation &&
x.SystemApp == BusinessSystemApp.Shop).FirstOrDefaultAsync();*/
var code = string.Format(App.Configuration["ApiUrlSetting:InviteShopReg"] ?? throw Oops.Bah("尚未配置门店注册邀请链接"), headid/*, ver?.Id*/);
return new InviteRegShopOutput()
{
Code = code,
Img = await code.ToQrCodeImageToBase64String(200, 200)
};
}
}
public class InviteRegShopOutput
{
public string Img { get; set; }
public string Code { get; set; }
}
public class ShopLoginInfoOutput
{
public long Id { get; set; }
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 门店名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 门店编号
/// </summary>
public string ShopCode { get; set; }
/// <summary>
/// 联系人
/// </summary>
public string Contact { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 省份
/// </summary>
public string Province { get; set; }
/// <summary>
/// 市
/// </summary>
public string City { get; set; }
/// <summary>
/// 区
/// </summary>
public string Area { get; set; }
/// <summary>
/// 详细地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 总部/代理商
/// </summary>
public long BusinessId { get; set; }
/// <summary>
/// 说明
/// </summary>
public string Desc { get; set; }
}
}

View File

@ -0,0 +1,121 @@
using JT.Shop.Application.Service.Shop;
using JT.Shop.Domain.FeatureDefinitions.Shop;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Features;
using Volo.Abp.Localization;
namespace JT.Shop.Application.Service.Mch.Body
{
/// <summary>
/// 身体部位管理
/// </summary>
[ApiDescriptionSettings("门店管理平台")]
[Route("/api/mch/[controller]")]
public class BodyService(
IRepository<PC_ShopBodyRel> shopBodyRelRep,
IRepository<PC_ShopBody> bodyRep,
IRepository<PC_ShopBodyType> bodyTypeRep,
UserManager userManager)
: ITransient, IDynamicApiController
{
/// <summary>
/// 获取身体部位列表
/// </summary>
/// <returns></returns>
[ShopSystemBusinessVersionAuthorize(ShopOfBodyPermissionDefinitionProvider.ViewName)]
public async Task<List<ShopBodyTypeListOutput>> ListAsync()
{
var CurrentUser = userManager.GetCurrentAdminShopInfo();
//获取身体部位类型列表
var typelist = await bodyTypeRep.DetachedEntities.Where(x => x.Status == CommonStatus.Enable).OrderBy(x => x.SortCode).ToListAsync();
//获取身体部位列表
var bodylist = await bodyRep.DetachedEntities.Where(x => x.Status == CommonStatus.Enable).ToListAsync();
//获取门店关联的身体部位
var shopBodyRelList = await shopBodyRelRep.DetachedEntities.Where(x => x.ShopId == CurrentUser.ShopId).ToListAsync();
var returnlist = new List<ShopBodyTypeListOutput>();
typelist.ForEach(x =>
{
var bodylistoutput = new ShopBodyTypeListOutput
{
TypeId = x.Id,
TypeName = x.Name,
List = new List<ShopBodyListOutput>()
};
var blist = bodylist.Where(y => y.TypeId == x.Id).ToList();
blist.ForEach(y =>
{
var rel = shopBodyRelList.FirstOrDefault(z => z.BodyId == y.Id);
var bodyoutput = new ShopBodyListOutput
{
Id = y.Id,
Name = y.Name,
TypeId = y.TypeId,
IsChecked = !rel.IsEmpty()
};
bodylistoutput.List.Add(bodyoutput);
});
returnlist.Add(bodylistoutput);
});
return returnlist;
}
/// <summary>
/// 身体部位信息绑定
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[OpAudit("编辑", "部位管理", OpAuditLogEventTarget.Shop)]
[ShopSystemBusinessVersionAuthorize(ShopOfBodyPermissionDefinitionProvider.EditName)]
[UnitOfWork(true)]
public async Task SubmitAsync(ShopBodySubmitInput input)
{
var CurrentUser = userManager.GetCurrentAdminShopInfo();
//先删除绑定的
await shopBodyRelRep.Where(x => x.ShopId == CurrentUser.ShopId).DeleteAsync();
if (input.ids.IsEmpty())
{
return;
}
//新增
var insertlist = new List<PC_ShopBodyRel>();
input.ids.ForEach(x =>
{
insertlist.Add(new PC_ShopBodyRel
{
Id = YitIdHelper.NextId(),
ShopId = CurrentUser.ShopId,
BodyId = x,
BusinessId = CurrentUser.BusinessId
});
});
await shopBodyRelRep.InsertAsync(insertlist);
}
}
public class ShopOfBodyPermissionDefinitionProvider : PermissionDefinitionProvider
{
public const string GroupName = $"{ShopPermissionDefinitionNames.Prefix}.bodymag";
public const string ViewName = $"{GroupName}.view";
public const string EditName = $"{GroupName}.edit";
public override void Define(IPermissionDefinitionContext context)
{
{
var groups = context.AddGroup($"{GroupName}", new FixedLocalizableString("部位配置"));
groups.AddPermission($"{ViewName}", new FixedLocalizableString("查看"));
groups.AddPermission($"{EditName}", new FixedLocalizableString("修改"))
.RequirePermissions(ViewName)
.RequireFeatures(ShopOfBodyFeatureDefinitionProvider.EditName);
}
}
}
}

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