Commit 28b8ebfb1de2cbf689c3ee9bd41ac7505da0ca97
1 parent
9ec80591
feat: 添加业绩表品项分类和品项ID字段,新增统计报表接口
- 为6个业绩表添加品项分类(F_ItemCategory)和品项ID(F_ItemId)字段 - 创建同步SQL脚本,从品项明细表同步数据到业绩表 - 新增线索池客户统计报表接口 - 新增门店统计报表接口 - 新增会员升单统计报表接口(前4单中是否有升医美、升科美、升生美)
Showing
18 changed files
with
1238 additions
and
7 deletions
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/LeadCustomerStatisticsListOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqStatistics | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 线索池客户统计报表输出 | |
| 7 | + /// </summary> | |
| 8 | + public class LeadCustomerStatisticsListOutput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 线索池客户(拓客编号) | |
| 12 | + /// </summary> | |
| 13 | + public string LeadCustomerId { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 客户姓名 | |
| 17 | + /// </summary> | |
| 18 | + public string CustomerName { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 拓客时间 | |
| 22 | + /// </summary> | |
| 23 | + public DateTime? ExpansionTime { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 是否邀约(是/否) | |
| 27 | + /// </summary> | |
| 28 | + public string HasInvite { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 是否预约(是/否) | |
| 32 | + /// </summary> | |
| 33 | + public string HasAppointment { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 是否有消耗(是/否) | |
| 37 | + /// </summary> | |
| 38 | + public string HasConsume { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 是否开单(是/否) | |
| 42 | + /// </summary> | |
| 43 | + public string HasBilling { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 未开单原因 | |
| 47 | + /// </summary> | |
| 48 | + public string NoBillingReason { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 开卡金额 | |
| 52 | + /// </summary> | |
| 53 | + public decimal BillingAmount { get; set; } | |
| 54 | + | |
| 55 | + /// <summary> | |
| 56 | + /// 开卡卡项(多个卡项用顿号分隔) | |
| 57 | + /// </summary> | |
| 58 | + public string BillingItems { get; set; } | |
| 59 | + | |
| 60 | + /// <summary> | |
| 61 | + /// 实际预约记录数(不管是否通过邀约产生) | |
| 62 | + /// </summary> | |
| 63 | + public int ActualAppointmentCount { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 实际消耗记录数(不管是否通过预约产生) | |
| 67 | + /// </summary> | |
| 68 | + public int ActualConsumeCount { get; set; } | |
| 69 | + | |
| 70 | + /// <summary> | |
| 71 | + /// 实际开单记录数(不管是否通过预约产生) | |
| 72 | + /// </summary> | |
| 73 | + public int ActualBillingCount { get; set; } | |
| 74 | + | |
| 75 | + /// <summary> | |
| 76 | + /// 问题分析说明 | |
| 77 | + /// </summary> | |
| 78 | + public string Analysis { get; set; } | |
| 79 | + } | |
| 80 | +} | |
| 81 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/LeadCustomerStatisticsListQueryInput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.ComponentModel.DataAnnotations; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Entitys.Dto.LqStatistics | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 线索池客户统计报表查询输入 | |
| 9 | + /// </summary> | |
| 10 | + public class LeadCustomerStatisticsListQueryInput | |
| 11 | + { | |
| 12 | + /// <summary> | |
| 13 | + /// 页码 | |
| 14 | + /// </summary> | |
| 15 | + [Required] | |
| 16 | + public int PageIndex { get; set; } = 1; | |
| 17 | + | |
| 18 | + /// <summary> | |
| 19 | + /// 页大小 | |
| 20 | + /// </summary> | |
| 21 | + [Required] | |
| 22 | + public int PageSize { get; set; } = 20; | |
| 23 | + | |
| 24 | + /// <summary> | |
| 25 | + /// 开始时间(拓客时间范围) | |
| 26 | + /// </summary> | |
| 27 | + public DateTime? StartTime { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 结束时间(拓客时间范围) | |
| 31 | + /// </summary> | |
| 32 | + public DateTime? EndTime { get; set; } | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 门店ID列表(可以多个门店) | |
| 36 | + /// </summary> | |
| 37 | + public List<string> StoreIds { get; set; } | |
| 38 | + | |
| 39 | + /// <summary> | |
| 40 | + /// 拓客活动ID | |
| 41 | + /// </summary> | |
| 42 | + public string EventId { get; set; } | |
| 43 | + } | |
| 44 | +} | |
| 45 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/MemberUpgradeStatisticsListOutput.cs
0 → 100644
| 1 | +namespace NCC.Extend.Entitys.Dto.LqStatistics | |
| 2 | +{ | |
| 3 | + /// <summary> | |
| 4 | + /// 会员升单统计输出 | |
| 5 | + /// </summary> | |
| 6 | + public class MemberUpgradeStatisticsListOutput | |
| 7 | + { | |
| 8 | + /// <summary> | |
| 9 | + /// 会员ID | |
| 10 | + /// </summary> | |
| 11 | + public string MemberId { get; set; } | |
| 12 | + | |
| 13 | + /// <summary> | |
| 14 | + /// 会员姓名 | |
| 15 | + /// </summary> | |
| 16 | + public string MemberName { get; set; } | |
| 17 | + | |
| 18 | + /// <summary> | |
| 19 | + /// 会员手机号 | |
| 20 | + /// </summary> | |
| 21 | + public string MemberPhone { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 前4单中是否有升医美(是/否) | |
| 25 | + /// </summary> | |
| 26 | + public string HasUpgradeMedicalBeauty { get; set; } | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 前4单中是否有升科美(是/否) | |
| 30 | + /// </summary> | |
| 31 | + public string HasUpgradeTechBeauty { get; set; } | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 前4单中是否有升生美(是/否) | |
| 35 | + /// </summary> | |
| 36 | + public string HasUpgradeLifeBeauty { get; set; } | |
| 37 | + } | |
| 38 | +} | |
| 39 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/MemberUpgradeStatisticsListQueryInput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqStatistics | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 会员升单统计查询输入 | |
| 8 | + /// </summary> | |
| 9 | + public class MemberUpgradeStatisticsListQueryInput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 页码 | |
| 13 | + /// </summary> | |
| 14 | + public int PageIndex { get; set; } = 1; | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 每页数量 | |
| 18 | + /// </summary> | |
| 19 | + public int PageSize { get; set; } = 20; | |
| 20 | + | |
| 21 | + /// <summary> | |
| 22 | + /// 会员ID列表(可选,不传则查询所有会员) | |
| 23 | + /// </summary> | |
| 24 | + public List<string> MemberIds { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 是否升医美(true-是,false-否,null-不筛选) | |
| 28 | + /// </summary> | |
| 29 | + public bool? HasUpgradeMedicalBeauty { get; set; } | |
| 30 | + | |
| 31 | + /// <summary> | |
| 32 | + /// 是否升科美(true-是,false-否,null-不筛选) | |
| 33 | + /// </summary> | |
| 34 | + public bool? HasUpgradeTechBeauty { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 是否升生美(true-是,false-否,null-不筛选) | |
| 38 | + /// </summary> | |
| 39 | + public bool? HasUpgradeLifeBeauty { get; set; } | |
| 40 | + } | |
| 41 | +} | |
| 42 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/StoreStatisticsListOutput.cs
0 → 100644
| 1 | +namespace NCC.Extend.Entitys.Dto.LqStatistics | |
| 2 | +{ | |
| 3 | + /// <summary> | |
| 4 | + /// 门店统计报表输出 | |
| 5 | + /// </summary> | |
| 6 | + public class StoreStatisticsListOutput | |
| 7 | + { | |
| 8 | + /// <summary> | |
| 9 | + /// 门店ID | |
| 10 | + /// </summary> | |
| 11 | + public string StoreId { get; set; } | |
| 12 | + | |
| 13 | + /// <summary> | |
| 14 | + /// 门店名称 | |
| 15 | + /// </summary> | |
| 16 | + public string StoreName { get; set; } | |
| 17 | + | |
| 18 | + /// <summary> | |
| 19 | + /// 总人数(拓客记录数) | |
| 20 | + /// </summary> | |
| 21 | + public int TotalCount { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 拓客人数(去重的会员数) | |
| 25 | + /// </summary> | |
| 26 | + public int TkMemberCount { get; set; } | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 邀约数(通过拓客编号关联的邀约记录数) | |
| 30 | + /// </summary> | |
| 31 | + public int InviteCount { get; set; } | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 预约数(通过邀约ID关联的预约记录数) | |
| 35 | + /// </summary> | |
| 36 | + public int AppointmentCount { get; set; } | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 耗卡数(通过预约ID关联的耗卡记录数) | |
| 40 | + /// </summary> | |
| 41 | + public int ConsumeCount { get; set; } | |
| 42 | + | |
| 43 | + /// <summary> | |
| 44 | + /// 开单数(通过预约ID关联的开单记录数) | |
| 45 | + /// </summary> | |
| 46 | + public int BillingCount { get; set; } | |
| 47 | + | |
| 48 | + /// <summary> | |
| 49 | + /// 开单金额(通过预约ID关联的开单记录金额汇总) | |
| 50 | + /// </summary> | |
| 51 | + public decimal BillingAmount { get; set; } | |
| 52 | + } | |
| 53 | +} | |
| 54 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/StoreStatisticsListQueryInput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.ComponentModel.DataAnnotations; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Entitys.Dto.LqStatistics | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 门店统计报表查询输入 | |
| 9 | + /// </summary> | |
| 10 | + public class StoreStatisticsListQueryInput | |
| 11 | + { | |
| 12 | + /// <summary> | |
| 13 | + /// 开始时间(拓客时间范围) | |
| 14 | + /// </summary> | |
| 15 | + public DateTime? StartTime { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 结束时间(拓客时间范围) | |
| 19 | + /// </summary> | |
| 20 | + public DateTime? EndTime { get; set; } | |
| 21 | + | |
| 22 | + /// <summary> | |
| 23 | + /// 门店ID列表(可以多个门店) | |
| 24 | + /// </summary> | |
| 25 | + public List<string> StoreIds { get; set; } | |
| 26 | + | |
| 27 | + /// <summary> | |
| 28 | + /// 拓客活动ID(可选,不传则查询所有活动) | |
| 29 | + /// </summary> | |
| 30 | + public string EventId { get; set; } | |
| 31 | + } | |
| 32 | +} | |
| 33 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_jksyj/LqHytkJksyjEntity.cs
| ... | ... | @@ -113,5 +113,17 @@ namespace NCC.Extend.Entitys.lq_hytk_jksyj |
| 113 | 113 | /// </summary> |
| 114 | 114 | [SugarColumn(ColumnName = "F_IsEffective")] |
| 115 | 115 | public int IsEffective { get; set; } = StatusEnum.有效.GetHashCode(); |
| 116 | + | |
| 117 | + /// <summary> | |
| 118 | + /// 品项分类 | |
| 119 | + /// </summary> | |
| 120 | + [SugarColumn(ColumnName = "F_ItemCategory")] | |
| 121 | + public string ItemCategory { get; set; } | |
| 122 | + | |
| 123 | + /// <summary> | |
| 124 | + /// 品项ID | |
| 125 | + /// </summary> | |
| 126 | + [SugarColumn(ColumnName = "F_ItemId")] | |
| 127 | + public string ItemId { get; set; } | |
| 116 | 128 | } |
| 117 | 129 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_kjbsyj/LqHytkKjbsyjEntity.cs
| ... | ... | @@ -108,5 +108,17 @@ namespace NCC.Extend.Entitys.lq_hytk_kjbsyj |
| 108 | 108 | /// </summary> |
| 109 | 109 | [SugarColumn(ColumnName = "F_IsEffective")] |
| 110 | 110 | public int IsEffective { get; set; } = StatusEnum.有效.GetHashCode(); |
| 111 | + | |
| 112 | + /// <summary> | |
| 113 | + /// 品项分类 | |
| 114 | + /// </summary> | |
| 115 | + [SugarColumn(ColumnName = "F_ItemCategory")] | |
| 116 | + public string ItemCategory { get; set; } | |
| 117 | + | |
| 118 | + /// <summary> | |
| 119 | + /// 品项ID | |
| 120 | + /// </summary> | |
| 121 | + [SugarColumn(ColumnName = "F_ItemId")] | |
| 122 | + public string ItemId { get; set; } | |
| 111 | 123 | } |
| 112 | 124 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs
| ... | ... | @@ -76,5 +76,17 @@ namespace NCC.Extend.Entitys.lq_kd_jksyj |
| 76 | 76 | /// </summary> |
| 77 | 77 | [SugarColumn(ColumnName = "F_ActivityId")] |
| 78 | 78 | public string ActivityId { get; set; } |
| 79 | + | |
| 80 | + /// <summary> | |
| 81 | + /// 品项分类 | |
| 82 | + /// </summary> | |
| 83 | + [SugarColumn(ColumnName = "F_ItemCategory")] | |
| 84 | + public string ItemCategory { get; set; } | |
| 85 | + | |
| 86 | + /// <summary> | |
| 87 | + /// 品项ID | |
| 88 | + /// </summary> | |
| 89 | + [SugarColumn(ColumnName = "F_ItemId")] | |
| 90 | + public string ItemId { get; set; } | |
| 79 | 91 | } |
| 80 | 92 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs
| ... | ... | @@ -76,5 +76,17 @@ namespace NCC.Extend.Entitys.lq_kd_kjbsyj |
| 76 | 76 | /// </summary> |
| 77 | 77 | [SugarColumn(ColumnName = "F_ActivityId")] |
| 78 | 78 | public string ActivityId { get; set; } |
| 79 | + | |
| 80 | + /// <summary> | |
| 81 | + /// 品项分类 | |
| 82 | + /// </summary> | |
| 83 | + [SugarColumn(ColumnName = "F_ItemCategory")] | |
| 84 | + public string ItemCategory { get; set; } | |
| 85 | + | |
| 86 | + /// <summary> | |
| 87 | + /// 品项ID | |
| 88 | + /// </summary> | |
| 89 | + [SugarColumn(ColumnName = "F_ItemId")] | |
| 90 | + public string ItemId { get; set; } | |
| 79 | 91 | } |
| 80 | 92 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_jksyj/LqXhJksyjEntity.cs
| ... | ... | @@ -124,5 +124,17 @@ namespace NCC.Extend.Entitys.lq_xh_jksyj |
| 124 | 124 | /// </summary> |
| 125 | 125 | [SugarColumn(ColumnName = "F_AccompaniedProjectNumber")] |
| 126 | 126 | public decimal? AccompaniedProjectNumber { get; set; } |
| 127 | + | |
| 128 | + /// <summary> | |
| 129 | + /// 品项分类 | |
| 130 | + /// </summary> | |
| 131 | + [SugarColumn(ColumnName = "F_ItemCategory")] | |
| 132 | + public string ItemCategory { get; set; } | |
| 133 | + | |
| 134 | + /// <summary> | |
| 135 | + /// 品项ID | |
| 136 | + /// </summary> | |
| 137 | + [SugarColumn(ColumnName = "F_ItemId")] | |
| 138 | + public string ItemId { get; set; } | |
| 127 | 139 | } |
| 128 | 140 | } |
| 129 | 141 | \ No newline at end of file | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_kjbsyj/LqXhKjbsyjEntity.cs
| ... | ... | @@ -106,5 +106,17 @@ namespace NCC.Extend.Entitys.lq_xh_kjbsyj |
| 106 | 106 | /// </summary> |
| 107 | 107 | [SugarColumn(ColumnName = "F_IsEffective")] |
| 108 | 108 | public int? IsEffective { get; set; } = 1; |
| 109 | + | |
| 110 | + /// <summary> | |
| 111 | + /// 品项分类 | |
| 112 | + /// </summary> | |
| 113 | + [SugarColumn(ColumnName = "F_ItemCategory")] | |
| 114 | + public string ItemCategory { get; set; } | |
| 115 | + | |
| 116 | + /// <summary> | |
| 117 | + /// 品项ID | |
| 118 | + /// </summary> | |
| 119 | + [SugarColumn(ColumnName = "F_ItemId")] | |
| 120 | + public string ItemId { get; set; } | |
| 109 | 121 | } |
| 110 | 122 | } |
| 111 | 123 | \ No newline at end of file | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
| ... | ... | @@ -446,11 +446,9 @@ namespace NCC.Extend |
| 446 | 446 | } |
| 447 | 447 | |
| 448 | 448 | // 查询该批次的所有使用记录 |
| 449 | - var usageRecords = await _db.Queryable<LqInventoryUsageEntity, LqProductEntity>( | |
| 450 | - (u, product) => u.ProductId == product.Id) | |
| 451 | - .LeftJoin<LqMdxxEntity>((u, product, store) => u.StoreId == store.Id) | |
| 452 | - .Where((u, product, store) => u.UsageBatchId == batchId) | |
| 453 | - .Select((u, product, store) => new LqInventoryUsageListOutput | |
| 449 | + var usageRecords = await _db.Queryable<LqInventoryUsageEntity, LqProductEntity>((u, product) => u.ProductId == product.Id) | |
| 450 | + .Where((u, product) => u.UsageBatchId == batchId) | |
| 451 | + .Select((u, product) => new LqInventoryUsageListOutput | |
| 454 | 452 | { |
| 455 | 453 | id = u.Id, |
| 456 | 454 | productId = u.ProductId, |
| ... | ... | @@ -458,7 +456,7 @@ namespace NCC.Extend |
| 458 | 456 | productCategory = product.ProductCategory, |
| 459 | 457 | productPrice = product.Price, |
| 460 | 458 | storeId = u.StoreId, |
| 461 | - storeName = store.Dm, | |
| 459 | + storeName = SqlFunc.Subqueryable<LqMdxxEntity>().Where(store => store.Id == u.StoreId).Select(store => store.Dm), | |
| 462 | 460 | usageTime = u.UsageTime, |
| 463 | 461 | usageQuantity = u.UsageQuantity, |
| 464 | 462 | relatedConsumeId = u.RelatedConsumeId, | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs
| ... | ... | @@ -1595,7 +1595,7 @@ namespace NCC.Extend.LqKhxx |
| 1595 | 1595 | } |
| 1596 | 1596 | |
| 1597 | 1597 | /// <summary> |
| 1598 | - /// 批量更新所有会员信息(高性能版:使用SQL批量更新) | |
| 1598 | + /// 批量更新所有会员信息(高性能版:使用SQL批量更新)【通过定时任务去执行,每天晚上执行一次】 | |
| 1599 | 1599 | /// </summary> |
| 1600 | 1600 | /// <returns></returns> |
| 1601 | 1601 | [HttpPost("BatchUpdateMemberInfo")] | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs
| ... | ... | @@ -53,6 +53,9 @@ using SqlSugar; |
| 53 | 53 | using Yitter.IdGenerator; |
| 54 | 54 | using NCC.Extend.Entitys.lq_kd_pxmx; |
| 55 | 55 | using NCC.Extend.Entitys.lq_khxx; |
| 56 | +using NCC.Extend.Entitys.lq_tkjlb; | |
| 57 | +using NCC.Extend.Entitys.lq_yaoyjl; | |
| 58 | +using NCC.Extend.Entitys.lq_yyjl; | |
| 56 | 59 | |
| 57 | 60 | namespace NCC.Extend.LqStatistics |
| 58 | 61 | { |
| ... | ... | @@ -3949,6 +3952,754 @@ namespace NCC.Extend.LqStatistics |
| 3949 | 3952 | } |
| 3950 | 3953 | #endregion |
| 3951 | 3954 | |
| 3955 | + #region 线索池客户统计报表 | |
| 3956 | + /// <summary> | |
| 3957 | + /// 获取线索池客户统计报表 | |
| 3958 | + /// </summary> | |
| 3959 | + /// <remarks> | |
| 3960 | + /// 根据拓客记录统计线索池客户的邀约、预约、消耗、开单等信息 | |
| 3961 | + /// | |
| 3962 | + /// 业务链路:拓客 -> 邀约 -> 预约 -> 开单/消耗 | |
| 3963 | + /// | |
| 3964 | + /// 示例请求: | |
| 3965 | + /// ```json | |
| 3966 | + /// { | |
| 3967 | + /// "pageIndex": 1, | |
| 3968 | + /// "pageSize": 20, | |
| 3969 | + /// "startTime": "2025-10-01T00:00:00", | |
| 3970 | + /// "endTime": "2025-10-31T23:59:59", | |
| 3971 | + /// "storeIds": ["store1", "store2"], | |
| 3972 | + /// "eventId": "event123" | |
| 3973 | + /// } | |
| 3974 | + /// ``` | |
| 3975 | + /// | |
| 3976 | + /// 参数说明: | |
| 3977 | + /// - pageIndex: 页码,从1开始 | |
| 3978 | + /// - pageSize: 每页数量 | |
| 3979 | + /// - startTime: 拓客时间范围开始时间 | |
| 3980 | + /// - endTime: 拓客时间范围结束时间 | |
| 3981 | + /// - storeIds: 门店ID列表,可传多个 | |
| 3982 | + /// - eventId: 拓客活动ID | |
| 3983 | + /// | |
| 3984 | + /// 返回数据说明: | |
| 3985 | + /// - LeadCustomerId: 线索池客户(拓客编号) | |
| 3986 | + /// - CustomerName: 客户姓名 | |
| 3987 | + /// - ExpansionTime: 拓客时间 | |
| 3988 | + /// - HasInvite: 是否邀约(是/否),通过拓客编号关联邀约表 | |
| 3989 | + /// - HasAppointment: 是否预约(是/否),只统计通过邀约产生的预约(预约表的F_InviteId关联邀约表) | |
| 3990 | + /// - HasConsume: 是否有消耗(是/否),只统计通过预约产生的耗卡(耗卡表的F_AppointmentId关联预约表) | |
| 3991 | + /// - HasBilling: 是否开单(是/否),只统计通过预约产生的开单(开单表的F_AppointmentId关联预约表) | |
| 3992 | + /// - NoBillingReason: 未开单原因,从预约记录的F_NoDealRemark字段获取 | |
| 3993 | + /// - BillingAmount: 开卡金额,汇总通过预约产生的开单记录的整单业绩(zdyj) | |
| 3994 | + /// - BillingItems: 开卡卡项,汇总通过预约产生的开单品项名称,多个用顿号分隔 | |
| 3995 | + /// - ActualAppointmentCount: 实际预约记录数(不管是否通过邀约产生),用于问题分析 | |
| 3996 | + /// - ActualConsumeCount: 实际消耗记录数(不管是否通过预约产生),用于问题分析 | |
| 3997 | + /// - ActualBillingCount: 实际开单记录数(不管是否通过预约产生),用于问题分析 | |
| 3998 | + /// - Analysis: 问题分析说明,自动分析数据异常情况,如:有预约记录但未通过邀约产生、有消耗记录但未通过预约产生等 | |
| 3999 | + /// | |
| 4000 | + /// 返回示例: | |
| 4001 | + /// ```json | |
| 4002 | + /// { | |
| 4003 | + /// "list": [ | |
| 4004 | + /// { | |
| 4005 | + /// "LeadCustomerId": "751248448816153862", | |
| 4006 | + /// "CustomerName": "王女士", | |
| 4007 | + /// "ExpansionTime": "2025-10-24T03:33:10.000Z", | |
| 4008 | + /// "HasInvite": "否", | |
| 4009 | + /// "HasAppointment": "否", | |
| 4010 | + /// "HasConsume": "否", | |
| 4011 | + /// "HasBilling": "否", | |
| 4012 | + /// "NoBillingReason": null, | |
| 4013 | + /// "BillingAmount": 0, | |
| 4014 | + /// "BillingItems": null, | |
| 4015 | + /// "ActualAppointmentCount": 3, | |
| 4016 | + /// "ActualConsumeCount": 4, | |
| 4017 | + /// "ActualBillingCount": 5, | |
| 4018 | + /// "Analysis": "有3条预约记录,但未通过邀约产生(F_InviteId为null);有4条消耗记录,但未通过预约产生(F_AppointmentId为null或预约未通过邀约产生);有5条开单记录,但未通过预约产生(F_AppointmentId为null或预约未通过邀约产生)" | |
| 4019 | + /// } | |
| 4020 | + /// ], | |
| 4021 | + /// "pagination": { | |
| 4022 | + /// "pageIndex": 1, | |
| 4023 | + /// "pageSize": 20, | |
| 4024 | + /// "total": 1511 | |
| 4025 | + /// } | |
| 4026 | + /// } | |
| 4027 | + /// ``` | |
| 4028 | + /// </remarks> | |
| 4029 | + /// <param name="input">查询条件</param> | |
| 4030 | + /// <returns>线索池客户统计报表列表,包含统计数据和问题分析</returns> | |
| 4031 | + /// <response code="200">查询成功,返回统计报表列表和分页信息</response> | |
| 4032 | + /// <response code="400">参数错误</response> | |
| 4033 | + /// <response code="500">服务器内部错误</response> | |
| 4034 | + [HttpPost("get-lead-customer-statistics-list")] | |
| 4035 | + public async Task<dynamic> GetLeadCustomerStatisticsList([FromBody] LeadCustomerStatisticsListQueryInput input) | |
| 4036 | + { | |
| 4037 | + try | |
| 4038 | + { | |
| 4039 | + // 构建WHERE条件 | |
| 4040 | + var whereConditions = new List<string>(); | |
| 4041 | + var parameters = new List<SugarParameter>(); | |
| 4042 | + | |
| 4043 | + if (input.StartTime.HasValue) | |
| 4044 | + { | |
| 4045 | + whereConditions.Add("tk.F_ExpansionTime >= @StartTime"); | |
| 4046 | + parameters.Add(new SugarParameter("@StartTime", input.StartTime.Value)); | |
| 4047 | + } | |
| 4048 | + | |
| 4049 | + if (input.EndTime.HasValue) | |
| 4050 | + { | |
| 4051 | + whereConditions.Add("tk.F_ExpansionTime <= @EndTime"); | |
| 4052 | + parameters.Add(new SugarParameter("@EndTime", input.EndTime.Value)); | |
| 4053 | + } | |
| 4054 | + | |
| 4055 | + if (input.StoreIds != null && input.StoreIds.Any()) | |
| 4056 | + { | |
| 4057 | + var storeIdParams = string.Join(",", input.StoreIds.Select((_, i) => $"@StoreId{i}")); | |
| 4058 | + whereConditions.Add($"tk.F_StoreId IN ({storeIdParams})"); | |
| 4059 | + for (int i = 0; i < input.StoreIds.Count; i++) | |
| 4060 | + { | |
| 4061 | + parameters.Add(new SugarParameter($"@StoreId{i}", input.StoreIds[i])); | |
| 4062 | + } | |
| 4063 | + } | |
| 4064 | + | |
| 4065 | + if (!string.IsNullOrEmpty(input.EventId)) | |
| 4066 | + { | |
| 4067 | + whereConditions.Add("tk.F_EventId = @EventId"); | |
| 4068 | + parameters.Add(new SugarParameter("@EventId", input.EventId)); | |
| 4069 | + } | |
| 4070 | + | |
| 4071 | + var whereClause = whereConditions.Any() ? "WHERE " + string.Join(" AND ", whereConditions) : ""; | |
| 4072 | + | |
| 4073 | + // 使用子查询优化性能,避免复杂的JOIN和GROUP BY | |
| 4074 | + var sql = $@" | |
| 4075 | + SELECT | |
| 4076 | + tk.F_Id as LeadCustomerId, | |
| 4077 | + tk.F_CustomerName as CustomerName, | |
| 4078 | + tk.F_ExpansionTime as ExpansionTime, | |
| 4079 | + -- 是否邀约:通过拓客编号关联 | |
| 4080 | + CASE WHEN yaoy_stats.has_invite = 1 THEN '是' ELSE '否' END as HasInvite, | |
| 4081 | + -- 是否预约:通过邀约ID关联(只统计通过邀约产生的预约) | |
| 4082 | + CASE WHEN yy_stats.has_appointment = 1 THEN '是' ELSE '否' END as HasAppointment, | |
| 4083 | + -- 是否有消耗:通过预约ID关联(只统计通过预约产生的耗卡) | |
| 4084 | + CASE WHEN xh_stats.has_consume = 1 THEN '是' ELSE '否' END as HasConsume, | |
| 4085 | + -- 是否开单:通过预约ID关联(只统计通过预约产生的开单) | |
| 4086 | + CASE WHEN kd_stats.has_billing = 1 THEN '是' ELSE '否' END as HasBilling, | |
| 4087 | + -- 未开单原因:从预约记录中获取(只取通过邀约产生的预约) | |
| 4088 | + yy_stats.no_billing_reason as NoBillingReason, | |
| 4089 | + -- 开卡金额:汇总通过预约产生的开单记录 | |
| 4090 | + COALESCE(kd_stats.billing_amount, 0) as BillingAmount, | |
| 4091 | + -- 开卡卡项:汇总通过预约产生的开单品项 | |
| 4092 | + kd_stats.billing_items as BillingItems, | |
| 4093 | + -- 实际预约记录数(不管是否通过邀约产生) | |
| 4094 | + COALESCE(yy_actual.count, 0) as ActualAppointmentCount, | |
| 4095 | + -- 实际消耗记录数(不管是否通过预约产生) | |
| 4096 | + COALESCE(xh_actual.count, 0) as ActualConsumeCount, | |
| 4097 | + -- 实际开单记录数(不管是否通过预约产生) | |
| 4098 | + COALESCE(kd_actual.count, 0) as ActualBillingCount | |
| 4099 | + FROM lq_tkjlb tk | |
| 4100 | + -- 邀约统计子查询 | |
| 4101 | + LEFT JOIN ( | |
| 4102 | + SELECT | |
| 4103 | + yaoy.tkbh as tk_id, | |
| 4104 | + 1 as has_invite | |
| 4105 | + FROM lq_yaoyjl yaoy | |
| 4106 | + GROUP BY yaoy.tkbh | |
| 4107 | + ) yaoy_stats ON yaoy_stats.tk_id = tk.F_Id | |
| 4108 | + -- 预约统计子查询(只统计通过邀约产生的预约) | |
| 4109 | + LEFT JOIN ( | |
| 4110 | + SELECT | |
| 4111 | + tk_inner.F_MemberId as member_id, | |
| 4112 | + 1 as has_appointment, | |
| 4113 | + MAX(yy.F_NoDealRemark) as no_billing_reason | |
| 4114 | + FROM lq_tkjlb tk_inner | |
| 4115 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk_inner.F_Id | |
| 4116 | + INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id | |
| 4117 | + GROUP BY tk_inner.F_MemberId | |
| 4118 | + ) yy_stats ON yy_stats.member_id = tk.F_MemberId | |
| 4119 | + -- 消耗统计子查询(只统计通过预约产生的耗卡) | |
| 4120 | + LEFT JOIN ( | |
| 4121 | + SELECT | |
| 4122 | + tk_inner.F_MemberId as member_id, | |
| 4123 | + 1 as has_consume | |
| 4124 | + FROM lq_tkjlb tk_inner | |
| 4125 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk_inner.F_Id | |
| 4126 | + INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id | |
| 4127 | + INNER JOIN lq_xh_hyhk xh ON xh.F_AppointmentId = yy.F_Id AND xh.F_IsEffective = 1 | |
| 4128 | + GROUP BY tk_inner.F_MemberId | |
| 4129 | + ) xh_stats ON xh_stats.member_id = tk.F_MemberId | |
| 4130 | + -- 开单统计子查询(只统计通过预约产生的开单,包含金额和品项) | |
| 4131 | + LEFT JOIN ( | |
| 4132 | + SELECT | |
| 4133 | + tk_inner.F_MemberId as member_id, | |
| 4134 | + 1 as has_billing, | |
| 4135 | + SUM(kd.zdyj) as billing_amount, | |
| 4136 | + GROUP_CONCAT(DISTINCT kdpx.pxmc SEPARATOR '、') as billing_items | |
| 4137 | + FROM lq_tkjlb tk_inner | |
| 4138 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk_inner.F_Id | |
| 4139 | + INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id | |
| 4140 | + INNER JOIN lq_kd_kdjlb kd ON kd.F_AppointmentId = yy.F_Id AND kd.F_IsEffective = 1 | |
| 4141 | + LEFT JOIN lq_kd_pxmx kdpx ON kdpx.glkdbh = kd.F_Id AND kdpx.F_IsEffective = 1 | |
| 4142 | + GROUP BY tk_inner.F_MemberId | |
| 4143 | + ) kd_stats ON kd_stats.member_id = tk.F_MemberId | |
| 4144 | + -- 实际预约记录数统计(不管是否通过邀约产生) | |
| 4145 | + LEFT JOIN ( | |
| 4146 | + SELECT | |
| 4147 | + yy.gk as member_id, | |
| 4148 | + COUNT(*) as count | |
| 4149 | + FROM lq_yyjl yy | |
| 4150 | + GROUP BY yy.gk | |
| 4151 | + ) yy_actual ON yy_actual.member_id = tk.F_MemberId | |
| 4152 | + -- 实际消耗记录数统计(不管是否通过预约产生) | |
| 4153 | + LEFT JOIN ( | |
| 4154 | + SELECT | |
| 4155 | + xh.hy as member_id, | |
| 4156 | + COUNT(*) as count | |
| 4157 | + FROM lq_xh_hyhk xh | |
| 4158 | + WHERE xh.F_IsEffective = 1 | |
| 4159 | + GROUP BY xh.hy | |
| 4160 | + ) xh_actual ON xh_actual.member_id = tk.F_MemberId | |
| 4161 | + -- 实际开单记录数统计(不管是否通过预约产生) | |
| 4162 | + LEFT JOIN ( | |
| 4163 | + SELECT | |
| 4164 | + kd.kdhy as member_id, | |
| 4165 | + COUNT(*) as count | |
| 4166 | + FROM lq_kd_kdjlb kd | |
| 4167 | + WHERE kd.F_IsEffective = 1 | |
| 4168 | + GROUP BY kd.kdhy | |
| 4169 | + ) kd_actual ON kd_actual.member_id = tk.F_MemberId | |
| 4170 | + {whereClause} | |
| 4171 | + ORDER BY tk.F_ExpansionTime DESC | |
| 4172 | + LIMIT @PageSize OFFSET @Offset"; | |
| 4173 | + | |
| 4174 | + parameters.Add(new SugarParameter("@PageSize", input.PageSize)); | |
| 4175 | + parameters.Add(new SugarParameter("@Offset", (input.PageIndex - 1) * input.PageSize)); | |
| 4176 | + | |
| 4177 | + // 查询总数 | |
| 4178 | + var countSql = $@" | |
| 4179 | + SELECT COUNT(*) | |
| 4180 | + FROM lq_tkjlb tk | |
| 4181 | + {whereClause}"; | |
| 4182 | + | |
| 4183 | + var countParameters = parameters.Where(p => p.ParameterName != "@PageSize" && p.ParameterName != "@Offset").ToList(); | |
| 4184 | + var totalCount = await _db.Ado.GetIntAsync(countSql, countParameters); | |
| 4185 | + | |
| 4186 | + // 执行查询 | |
| 4187 | + var result = await _db.Ado.SqlQueryAsync<LeadCustomerStatisticsListOutput>(sql, parameters); | |
| 4188 | + | |
| 4189 | + // 生成问题分析说明 | |
| 4190 | + foreach (var item in result) | |
| 4191 | + { | |
| 4192 | + var analysisList = new List<string>(); | |
| 4193 | + | |
| 4194 | + if (item.HasInvite == "否" && item.HasAppointment == "否" && item.ActualAppointmentCount > 0) | |
| 4195 | + { | |
| 4196 | + analysisList.Add($"有{item.ActualAppointmentCount}条预约记录,但未通过邀约产生(F_InviteId为null)"); | |
| 4197 | + } | |
| 4198 | + | |
| 4199 | + if (item.HasAppointment == "否" && item.HasConsume == "否" && item.ActualConsumeCount > 0) | |
| 4200 | + { | |
| 4201 | + analysisList.Add($"有{item.ActualConsumeCount}条消耗记录,但未通过预约产生(F_AppointmentId为null或预约未通过邀约产生)"); | |
| 4202 | + } | |
| 4203 | + | |
| 4204 | + if (item.HasAppointment == "否" && item.HasBilling == "否" && item.ActualBillingCount > 0) | |
| 4205 | + { | |
| 4206 | + analysisList.Add($"有{item.ActualBillingCount}条开单记录,但未通过预约产生(F_AppointmentId为null或预约未通过邀约产生)"); | |
| 4207 | + } | |
| 4208 | + | |
| 4209 | + if (item.HasInvite == "是" && item.HasAppointment == "否" && item.ActualAppointmentCount > 0) | |
| 4210 | + { | |
| 4211 | + analysisList.Add($"有邀约记录,有{item.ActualAppointmentCount}条预约记录,但预约记录的F_InviteId未关联到邀约记录"); | |
| 4212 | + } | |
| 4213 | + | |
| 4214 | + if (item.HasAppointment == "是" && item.HasConsume == "否" && item.ActualConsumeCount > 0) | |
| 4215 | + { | |
| 4216 | + analysisList.Add($"有预约记录,有{item.ActualConsumeCount}条消耗记录,但消耗记录的F_AppointmentId未关联到预约记录"); | |
| 4217 | + } | |
| 4218 | + | |
| 4219 | + if (item.HasAppointment == "是" && item.HasBilling == "否" && item.ActualBillingCount > 0) | |
| 4220 | + { | |
| 4221 | + analysisList.Add($"有预约记录,有{item.ActualBillingCount}条开单记录,但开单记录的F_AppointmentId未关联到预约记录"); | |
| 4222 | + } | |
| 4223 | + | |
| 4224 | + if (analysisList.Count == 0) | |
| 4225 | + { | |
| 4226 | + item.Analysis = "数据正常,符合业务链路:拓客 -> 邀约 -> 预约 -> 开单/消耗"; | |
| 4227 | + } | |
| 4228 | + else | |
| 4229 | + { | |
| 4230 | + item.Analysis = string.Join(";", analysisList); | |
| 4231 | + } | |
| 4232 | + } | |
| 4233 | + | |
| 4234 | + return new | |
| 4235 | + { | |
| 4236 | + list = result, | |
| 4237 | + pagination = new | |
| 4238 | + { | |
| 4239 | + pageIndex = input.PageIndex, | |
| 4240 | + pageSize = input.PageSize, | |
| 4241 | + total = totalCount | |
| 4242 | + } | |
| 4243 | + }; | |
| 4244 | + } | |
| 4245 | + catch (Exception ex) | |
| 4246 | + { | |
| 4247 | + _logger.LogError(ex, "获取线索池客户统计报表失败"); | |
| 4248 | + throw NCCException.Oh($"获取线索池客户统计报表失败:{ex.Message}"); | |
| 4249 | + } | |
| 4250 | + } | |
| 4251 | + #endregion | |
| 4252 | + | |
| 4253 | + #region 门店统计报表 | |
| 4254 | + /// <summary> | |
| 4255 | + /// 获取门店统计报表 | |
| 4256 | + /// </summary> | |
| 4257 | + /// <remarks> | |
| 4258 | + /// 按门店统计拓客、邀约、预约、消耗、开单等数据 | |
| 4259 | + /// | |
| 4260 | + /// 业务链路:拓客 -> 邀约 -> 预约 -> 开单/消耗 | |
| 4261 | + /// | |
| 4262 | + /// 示例请求: | |
| 4263 | + /// ```json | |
| 4264 | + /// { | |
| 4265 | + /// "startTime": "2025-10-01T00:00:00", | |
| 4266 | + /// "endTime": "2025-10-31T23:59:59", | |
| 4267 | + /// "storeIds": ["store1", "store2"], | |
| 4268 | + /// "eventId": "event123" | |
| 4269 | + /// } | |
| 4270 | + /// ``` | |
| 4271 | + /// | |
| 4272 | + /// 参数说明: | |
| 4273 | + /// - startTime: 拓客时间范围开始时间 | |
| 4274 | + /// - endTime: 拓客时间范围结束时间 | |
| 4275 | + /// - storeIds: 门店ID列表,可传多个 | |
| 4276 | + /// - eventId: 拓客活动ID | |
| 4277 | + /// | |
| 4278 | + /// 返回数据说明: | |
| 4279 | + /// - StoreId: 门店ID | |
| 4280 | + /// - StoreName: 门店名称 | |
| 4281 | + /// - TotalCount: 总人数(从客户信息表按归属门店统计) | |
| 4282 | + /// - TkMemberCount: 拓客人数(拓客记录数,不去重) | |
| 4283 | + /// - InviteCount: 邀约数(通过拓客编号关联的邀约记录数) | |
| 4284 | + /// - AppointmentCount: 预约数(通过邀约ID关联的预约记录数,只统计通过邀约产生的预约) | |
| 4285 | + /// - ConsumeCount: 耗卡数(通过预约ID关联的耗卡记录数,只统计通过预约产生的耗卡) | |
| 4286 | + /// - BillingCount: 开单数(通过预约ID关联的开单记录数,只统计通过预约产生的开单) | |
| 4287 | + /// - BillingAmount: 开单金额(通过预约ID关联的开单记录金额汇总) | |
| 4288 | + /// | |
| 4289 | + /// 返回示例: | |
| 4290 | + /// ```json | |
| 4291 | + /// { | |
| 4292 | + /// "list": [ | |
| 4293 | + /// { | |
| 4294 | + /// "StoreId": "1649328471923847169", | |
| 4295 | + /// "StoreName": "绿纤紫荆店", | |
| 4296 | + /// "TotalCount": 119, | |
| 4297 | + /// "TkMemberCount": 117, | |
| 4298 | + /// "InviteCount": 4, | |
| 4299 | + /// "AppointmentCount": 2, | |
| 4300 | + /// "ConsumeCount": 1, | |
| 4301 | + /// "BillingCount": 1, | |
| 4302 | + /// "BillingAmount": 199.00 | |
| 4303 | + /// } | |
| 4304 | + /// ] | |
| 4305 | + /// } | |
| 4306 | + /// ``` | |
| 4307 | + /// </remarks> | |
| 4308 | + /// <param name="input">查询条件</param> | |
| 4309 | + /// <returns>门店统计报表列表</returns> | |
| 4310 | + /// <response code="200">查询成功,返回门店统计报表列表</response> | |
| 4311 | + /// <response code="400">参数错误</response> | |
| 4312 | + /// <response code="500">服务器内部错误</response> | |
| 4313 | + [HttpPost("get-store-statistics-list")] | |
| 4314 | + public async Task<dynamic> GetStoreStatisticsList([FromBody] StoreStatisticsListQueryInput input) | |
| 4315 | + { | |
| 4316 | + try | |
| 4317 | + { | |
| 4318 | + // 构建WHERE条件(带表别名,用于子查询) | |
| 4319 | + var whereConditions = new List<string>(); | |
| 4320 | + // 构建WHERE条件(不带表别名,用于UNION的SELECT) | |
| 4321 | + var whereConditionsNoAlias = new List<string>(); | |
| 4322 | + var parameters = new List<SugarParameter>(); | |
| 4323 | + | |
| 4324 | + if (input.StartTime.HasValue) | |
| 4325 | + { | |
| 4326 | + whereConditions.Add("tk.F_ExpansionTime >= @StartTime"); | |
| 4327 | + whereConditionsNoAlias.Add("F_ExpansionTime >= @StartTime"); | |
| 4328 | + parameters.Add(new SugarParameter("@StartTime", input.StartTime.Value)); | |
| 4329 | + } | |
| 4330 | + | |
| 4331 | + if (input.EndTime.HasValue) | |
| 4332 | + { | |
| 4333 | + whereConditions.Add("tk.F_ExpansionTime <= @EndTime"); | |
| 4334 | + whereConditionsNoAlias.Add("F_ExpansionTime <= @EndTime"); | |
| 4335 | + parameters.Add(new SugarParameter("@EndTime", input.EndTime.Value)); | |
| 4336 | + } | |
| 4337 | + | |
| 4338 | + if (input.StoreIds != null && input.StoreIds.Any()) | |
| 4339 | + { | |
| 4340 | + var storeIdParams = string.Join(",", input.StoreIds.Select((_, i) => $"@StoreId{i}")); | |
| 4341 | + whereConditions.Add($"tk.F_StoreId IN ({storeIdParams})"); | |
| 4342 | + whereConditionsNoAlias.Add($"F_StoreId IN ({storeIdParams})"); | |
| 4343 | + for (int i = 0; i < input.StoreIds.Count; i++) | |
| 4344 | + { | |
| 4345 | + parameters.Add(new SugarParameter($"@StoreId{i}", input.StoreIds[i])); | |
| 4346 | + } | |
| 4347 | + } | |
| 4348 | + | |
| 4349 | + if (!string.IsNullOrEmpty(input.EventId)) | |
| 4350 | + { | |
| 4351 | + whereConditions.Add("tk.F_EventId = @EventId"); | |
| 4352 | + whereConditionsNoAlias.Add("F_EventId = @EventId"); | |
| 4353 | + parameters.Add(new SugarParameter("@EventId", input.EventId)); | |
| 4354 | + } | |
| 4355 | + | |
| 4356 | + var whereClause = whereConditions.Any() ? "WHERE " + string.Join(" AND ", whereConditions) : ""; | |
| 4357 | + var whereClauseNoAlias = whereConditionsNoAlias.Any() ? "WHERE " + string.Join(" AND ", whereConditionsNoAlias) : ""; | |
| 4358 | + | |
| 4359 | + // 构建门店筛选条件(用于客户信息表查询) | |
| 4360 | + var khWhereConditions = new List<string>(); | |
| 4361 | + var khWhereConditionsNoAlias = new List<string>(); | |
| 4362 | + if (input.StoreIds != null && input.StoreIds.Any()) | |
| 4363 | + { | |
| 4364 | + var storeIdParams = string.Join(",", input.StoreIds.Select((_, i) => $"@StoreId{i}")); | |
| 4365 | + khWhereConditions.Add($"kh.gsmd IN ({storeIdParams})"); | |
| 4366 | + khWhereConditionsNoAlias.Add($"gsmd IN ({storeIdParams})"); | |
| 4367 | + } | |
| 4368 | + | |
| 4369 | + var khWhereClause = khWhereConditions.Any() ? "WHERE " + string.Join(" AND ", khWhereConditions) : "WHERE kh.gsmd IS NOT NULL"; | |
| 4370 | + var khWhereClauseNoAlias = khWhereConditionsNoAlias.Any() ? "WHERE " + string.Join(" AND ", khWhereConditionsNoAlias) : "WHERE gsmd IS NOT NULL"; | |
| 4371 | + | |
| 4372 | + // 使用子查询优化性能,避免复杂的JOIN | |
| 4373 | + var sql = $@" | |
| 4374 | + SELECT | |
| 4375 | + COALESCE(total_stats.StoreId, tk_stats.StoreId, yaoy_stats.StoreId, yy_stats.StoreId, xh_stats.StoreId, kd_stats.StoreId) as StoreId, | |
| 4376 | + COALESCE(md.dm, '') as StoreName, | |
| 4377 | + COALESCE(total_stats.TotalCount, 0) as TotalCount, | |
| 4378 | + COALESCE(tk_stats.TkMemberCount, 0) as TkMemberCount, | |
| 4379 | + COALESCE(yaoy_stats.InviteCount, 0) as InviteCount, | |
| 4380 | + COALESCE(yy_stats.AppointmentCount, 0) as AppointmentCount, | |
| 4381 | + COALESCE(xh_stats.ConsumeCount, 0) as ConsumeCount, | |
| 4382 | + COALESCE(kd_stats.BillingCount, 0) as BillingCount, | |
| 4383 | + COALESCE(kd_stats.BillingAmount, 0) as BillingAmount | |
| 4384 | + FROM ( | |
| 4385 | + SELECT DISTINCT StoreId FROM ( | |
| 4386 | + SELECT gsmd as StoreId FROM lq_khxx {khWhereClauseNoAlias} | |
| 4387 | + UNION | |
| 4388 | + SELECT F_StoreId as StoreId FROM lq_tkjlb {whereClauseNoAlias} | |
| 4389 | + ) as all_stores | |
| 4390 | + ) as stores | |
| 4391 | + LEFT JOIN lq_mdxx md ON md.F_Id = stores.StoreId | |
| 4392 | + -- 总人数统计(从客户信息表按归属门店统计) | |
| 4393 | + LEFT JOIN ( | |
| 4394 | + SELECT | |
| 4395 | + kh.gsmd as StoreId, | |
| 4396 | + COUNT(*) as TotalCount | |
| 4397 | + FROM lq_khxx kh | |
| 4398 | + {khWhereClause} | |
| 4399 | + GROUP BY kh.gsmd | |
| 4400 | + ) total_stats ON total_stats.StoreId = stores.StoreId | |
| 4401 | + -- 拓客人数统计(不用去重) | |
| 4402 | + LEFT JOIN ( | |
| 4403 | + SELECT | |
| 4404 | + tk.F_StoreId as StoreId, | |
| 4405 | + COUNT(tk.F_MemberId) as TkMemberCount | |
| 4406 | + FROM lq_tkjlb tk | |
| 4407 | + {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} | |
| 4408 | + GROUP BY tk.F_StoreId | |
| 4409 | + ) tk_stats ON tk_stats.StoreId = stores.StoreId | |
| 4410 | + -- 邀约数统计 | |
| 4411 | + LEFT JOIN ( | |
| 4412 | + SELECT | |
| 4413 | + tk.F_StoreId as StoreId, | |
| 4414 | + COUNT(DISTINCT yaoy.F_Id) as InviteCount | |
| 4415 | + FROM lq_tkjlb tk | |
| 4416 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk.F_Id | |
| 4417 | + {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} | |
| 4418 | + GROUP BY tk.F_StoreId | |
| 4419 | + ) yaoy_stats ON yaoy_stats.StoreId = stores.StoreId | |
| 4420 | + -- 预约数统计(通过邀约ID关联) | |
| 4421 | + LEFT JOIN ( | |
| 4422 | + SELECT | |
| 4423 | + tk.F_StoreId as StoreId, | |
| 4424 | + COUNT(DISTINCT yy.F_Id) as AppointmentCount | |
| 4425 | + FROM lq_tkjlb tk | |
| 4426 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk.F_Id | |
| 4427 | + INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id | |
| 4428 | + {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} | |
| 4429 | + GROUP BY tk.F_StoreId | |
| 4430 | + ) yy_stats ON yy_stats.StoreId = stores.StoreId | |
| 4431 | + -- 耗卡数统计(通过预约ID关联) | |
| 4432 | + LEFT JOIN ( | |
| 4433 | + SELECT | |
| 4434 | + tk.F_StoreId as StoreId, | |
| 4435 | + COUNT(DISTINCT xh.F_Id) as ConsumeCount | |
| 4436 | + FROM lq_tkjlb tk | |
| 4437 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk.F_Id | |
| 4438 | + INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id | |
| 4439 | + INNER JOIN lq_xh_hyhk xh ON xh.F_AppointmentId = yy.F_Id AND xh.F_IsEffective = 1 | |
| 4440 | + {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} | |
| 4441 | + GROUP BY tk.F_StoreId | |
| 4442 | + ) xh_stats ON xh_stats.StoreId = stores.StoreId | |
| 4443 | + -- 开单数和开单金额统计(通过预约ID关联) | |
| 4444 | + LEFT JOIN ( | |
| 4445 | + SELECT | |
| 4446 | + tk.F_StoreId as StoreId, | |
| 4447 | + COUNT(DISTINCT kd.F_Id) as BillingCount, | |
| 4448 | + SUM(kd.zdyj) as BillingAmount | |
| 4449 | + FROM lq_tkjlb tk | |
| 4450 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk.F_Id | |
| 4451 | + INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id | |
| 4452 | + INNER JOIN lq_kd_kdjlb kd ON kd.F_AppointmentId = yy.F_Id AND kd.F_IsEffective = 1 | |
| 4453 | + {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} | |
| 4454 | + GROUP BY tk.F_StoreId | |
| 4455 | + ) kd_stats ON kd_stats.StoreId = stores.StoreId | |
| 4456 | + WHERE stores.StoreId IS NOT NULL | |
| 4457 | + ORDER BY stores.StoreId"; | |
| 4458 | + | |
| 4459 | + // 执行查询 | |
| 4460 | + var result = await _db.Ado.SqlQueryAsync<StoreStatisticsListOutput>(sql, parameters); | |
| 4461 | + | |
| 4462 | + return new | |
| 4463 | + { | |
| 4464 | + list = result | |
| 4465 | + }; | |
| 4466 | + } | |
| 4467 | + catch (Exception ex) | |
| 4468 | + { | |
| 4469 | + _logger.LogError(ex, "获取门店统计报表失败"); | |
| 4470 | + throw NCCException.Oh($"获取门店统计报表失败:{ex.Message}"); | |
| 4471 | + } | |
| 4472 | + } | |
| 4473 | + #endregion | |
| 4474 | + | |
| 4475 | + #region 会员升单统计 | |
| 4476 | + /// <summary> | |
| 4477 | + /// 获取会员升单统计(前4单中是否有升医美、升科美、升生美) | |
| 4478 | + /// </summary> | |
| 4479 | + /// <remarks> | |
| 4480 | + /// 统计每个会员的前4单开单记录中是否有升医美、升科美、升生美 | |
| 4481 | + /// | |
| 4482 | + /// 示例请求: | |
| 4483 | + /// ```json | |
| 4484 | + /// { | |
| 4485 | + /// "pageIndex": 1, | |
| 4486 | + /// "pageSize": 20, | |
| 4487 | + /// "memberIds": ["member1", "member2"], | |
| 4488 | + /// "hasUpgradeMedicalBeauty": true, | |
| 4489 | + /// "hasUpgradeTechBeauty": false, | |
| 4490 | + /// "hasUpgradeLifeBeauty": null | |
| 4491 | + /// } | |
| 4492 | + /// ``` | |
| 4493 | + /// | |
| 4494 | + /// 参数说明: | |
| 4495 | + /// - pageIndex: 页码,从1开始 | |
| 4496 | + /// - pageSize: 每页数量 | |
| 4497 | + /// - memberIds: 会员ID列表(可选,不传则查询所有会员) | |
| 4498 | + /// - hasUpgradeMedicalBeauty: 是否升医美(true-是,false-否,null-不筛选) | |
| 4499 | + /// - hasUpgradeTechBeauty: 是否升科美(true-是,false-否,null-不筛选) | |
| 4500 | + /// - hasUpgradeLifeBeauty: 是否升生美(true-是,false-否,null-不筛选) | |
| 4501 | + /// | |
| 4502 | + /// 返回数据说明: | |
| 4503 | + /// - MemberId: 会员ID | |
| 4504 | + /// - MemberName: 会员姓名 | |
| 4505 | + /// - MemberPhone: 会员手机号 | |
| 4506 | + /// - HasUpgradeMedicalBeauty: 前4单中是否有升医美(是/否) | |
| 4507 | + /// - HasUpgradeTechBeauty: 前4单中是否有升科美(是/否) | |
| 4508 | + /// - HasUpgradeLifeBeauty: 前4单中是否有升生美(是/否) | |
| 4509 | + /// | |
| 4510 | + /// 返回示例: | |
| 4511 | + /// ```json | |
| 4512 | + /// { | |
| 4513 | + /// "list": [ | |
| 4514 | + /// { | |
| 4515 | + /// "MemberId": "744326092097062149", | |
| 4516 | + /// "MemberName": "张女士", | |
| 4517 | + /// "MemberPhone": "13800138000", | |
| 4518 | + /// "HasUpgradeMedicalBeauty": "否", | |
| 4519 | + /// "HasUpgradeTechBeauty": "否", | |
| 4520 | + /// "HasUpgradeLifeBeauty": "否" | |
| 4521 | + /// } | |
| 4522 | + /// ], | |
| 4523 | + /// "pagination": { | |
| 4524 | + /// "pageIndex": 1, | |
| 4525 | + /// "pageSize": 20, | |
| 4526 | + /// "total": 100 | |
| 4527 | + /// } | |
| 4528 | + /// } | |
| 4529 | + /// ``` | |
| 4530 | + /// </remarks> | |
| 4531 | + /// <param name="input">查询条件</param> | |
| 4532 | + /// <returns>会员升单统计列表</returns> | |
| 4533 | + /// <response code="200">查询成功,返回会员升单统计列表</response> | |
| 4534 | + /// <response code="400">参数错误</response> | |
| 4535 | + /// <response code="500">服务器内部错误</response> | |
| 4536 | + [HttpPost("get-member-upgrade-statistics-list")] | |
| 4537 | + public async Task<dynamic> GetMemberUpgradeStatisticsList([FromBody] MemberUpgradeStatisticsListQueryInput input) | |
| 4538 | + { | |
| 4539 | + try | |
| 4540 | + { | |
| 4541 | + // 构建WHERE条件 | |
| 4542 | + var whereConditions = new List<string>(); | |
| 4543 | + var parameters = new List<SugarParameter>(); | |
| 4544 | + | |
| 4545 | + if (input.MemberIds != null && input.MemberIds.Any()) | |
| 4546 | + { | |
| 4547 | + var memberIdParams = string.Join(",", input.MemberIds.Select((_, i) => $"@MemberId{i}")); | |
| 4548 | + whereConditions.Add($"kd.kdhy IN ({memberIdParams})"); | |
| 4549 | + for (int i = 0; i < input.MemberIds.Count; i++) | |
| 4550 | + { | |
| 4551 | + parameters.Add(new SugarParameter($"@MemberId{i}", input.MemberIds[i])); | |
| 4552 | + } | |
| 4553 | + } | |
| 4554 | + | |
| 4555 | + var whereClause = whereConditions.Any() ? "AND " + string.Join(" AND ", whereConditions) : ""; | |
| 4556 | + | |
| 4557 | + // 构建HAVING条件(用于筛选升单条件) | |
| 4558 | + var havingConditions = new List<string>(); | |
| 4559 | + if (input.HasUpgradeMedicalBeauty.HasValue) | |
| 4560 | + { | |
| 4561 | + if (input.HasUpgradeMedicalBeauty.Value) | |
| 4562 | + { | |
| 4563 | + havingConditions.Add("MAX(CASE WHEN kd.F_UpgradeMedicalBeauty = '是' THEN 1 ELSE 0 END) = 1"); | |
| 4564 | + } | |
| 4565 | + else | |
| 4566 | + { | |
| 4567 | + havingConditions.Add("MAX(CASE WHEN kd.F_UpgradeMedicalBeauty = '是' THEN 1 ELSE 0 END) = 0"); | |
| 4568 | + } | |
| 4569 | + } | |
| 4570 | + if (input.HasUpgradeTechBeauty.HasValue) | |
| 4571 | + { | |
| 4572 | + if (input.HasUpgradeTechBeauty.Value) | |
| 4573 | + { | |
| 4574 | + havingConditions.Add("MAX(CASE WHEN kd.F_UpgradeTechBeauty = '是' THEN 1 ELSE 0 END) = 1"); | |
| 4575 | + } | |
| 4576 | + else | |
| 4577 | + { | |
| 4578 | + havingConditions.Add("MAX(CASE WHEN kd.F_UpgradeTechBeauty = '是' THEN 1 ELSE 0 END) = 0"); | |
| 4579 | + } | |
| 4580 | + } | |
| 4581 | + if (input.HasUpgradeLifeBeauty.HasValue) | |
| 4582 | + { | |
| 4583 | + if (input.HasUpgradeLifeBeauty.Value) | |
| 4584 | + { | |
| 4585 | + havingConditions.Add("MAX(CASE WHEN kd.F_UpgradeLifeBeauty = '是' THEN 1 ELSE 0 END) = 1"); | |
| 4586 | + } | |
| 4587 | + else | |
| 4588 | + { | |
| 4589 | + havingConditions.Add("MAX(CASE WHEN kd.F_UpgradeLifeBeauty = '是' THEN 1 ELSE 0 END) = 0"); | |
| 4590 | + } | |
| 4591 | + } | |
| 4592 | + | |
| 4593 | + var havingClause = havingConditions.Any() ? "HAVING " + string.Join(" AND ", havingConditions) : ""; | |
| 4594 | + | |
| 4595 | + // 分页参数 | |
| 4596 | + var offset = (input.PageIndex - 1) * input.PageSize; | |
| 4597 | + parameters.Add(new SugarParameter("@PageSize", input.PageSize)); | |
| 4598 | + parameters.Add(new SugarParameter("@Offset", offset)); | |
| 4599 | + | |
| 4600 | + // 查询每个会员的前4单中是否有升医美、升科美、升生美 | |
| 4601 | + var sql = $@" | |
| 4602 | + SELECT | |
| 4603 | + kd.kdhy as MemberId, | |
| 4604 | + kh.khmc as MemberName, | |
| 4605 | + kh.sjh as MemberPhone, | |
| 4606 | + CASE WHEN MAX(CASE WHEN kd.F_UpgradeMedicalBeauty = '是' THEN 1 ELSE 0 END) = 1 THEN '是' ELSE '否' END as HasUpgradeMedicalBeauty, | |
| 4607 | + CASE WHEN MAX(CASE WHEN kd.F_UpgradeTechBeauty = '是' THEN 1 ELSE 0 END) = 1 THEN '是' ELSE '否' END as HasUpgradeTechBeauty, | |
| 4608 | + CASE WHEN MAX(CASE WHEN kd.F_UpgradeLifeBeauty = '是' THEN 1 ELSE 0 END) = 1 THEN '是' ELSE '否' END as HasUpgradeLifeBeauty | |
| 4609 | + FROM ( | |
| 4610 | + SELECT | |
| 4611 | + kd.kdhy, | |
| 4612 | + kd.F_Id, | |
| 4613 | + kd.kdrq, | |
| 4614 | + kd.F_CreateTime, | |
| 4615 | + kd.F_UpgradeMedicalBeauty, | |
| 4616 | + kd.F_UpgradeTechBeauty, | |
| 4617 | + kd.F_UpgradeLifeBeauty | |
| 4618 | + FROM lq_kd_kdjlb kd | |
| 4619 | + WHERE kd.F_IsEffective = 1 | |
| 4620 | + AND kd.kdhy IS NOT NULL | |
| 4621 | + {whereClause} | |
| 4622 | + AND ( | |
| 4623 | + SELECT COUNT(*) | |
| 4624 | + FROM lq_kd_kdjlb kd2 | |
| 4625 | + WHERE kd2.kdhy = kd.kdhy | |
| 4626 | + AND kd2.F_IsEffective = 1 | |
| 4627 | + AND ( | |
| 4628 | + kd2.kdrq > kd.kdrq | |
| 4629 | + OR (kd2.kdrq = kd.kdrq AND kd2.F_CreateTime > kd.F_CreateTime) | |
| 4630 | + OR (kd2.kdrq = kd.kdrq AND kd2.F_CreateTime = kd.F_CreateTime AND kd2.F_Id > kd.F_Id) | |
| 4631 | + ) | |
| 4632 | + ) < 4 | |
| 4633 | + ) kd | |
| 4634 | + LEFT JOIN lq_khxx kh ON kh.F_Id = kd.kdhy | |
| 4635 | + GROUP BY kd.kdhy, kh.khmc, kh.sjh | |
| 4636 | + {havingClause} | |
| 4637 | + ORDER BY kd.kdhy | |
| 4638 | + LIMIT @PageSize OFFSET @Offset"; | |
| 4639 | + | |
| 4640 | + // 查询总数(需要应用相同的HAVING条件) | |
| 4641 | + var countSql = $@" | |
| 4642 | + SELECT COUNT(*) | |
| 4643 | + FROM ( | |
| 4644 | + SELECT | |
| 4645 | + kd.kdhy, | |
| 4646 | + CASE WHEN MAX(CASE WHEN kd.F_UpgradeMedicalBeauty = '是' THEN 1 ELSE 0 END) = 1 THEN '是' ELSE '否' END as HasUpgradeMedicalBeauty, | |
| 4647 | + CASE WHEN MAX(CASE WHEN kd.F_UpgradeTechBeauty = '是' THEN 1 ELSE 0 END) = 1 THEN '是' ELSE '否' END as HasUpgradeTechBeauty, | |
| 4648 | + CASE WHEN MAX(CASE WHEN kd.F_UpgradeLifeBeauty = '是' THEN 1 ELSE 0 END) = 1 THEN '是' ELSE '否' END as HasUpgradeLifeBeauty | |
| 4649 | + FROM ( | |
| 4650 | + SELECT | |
| 4651 | + kd.kdhy, | |
| 4652 | + kd.F_Id, | |
| 4653 | + kd.kdrq, | |
| 4654 | + kd.F_CreateTime, | |
| 4655 | + kd.F_UpgradeMedicalBeauty, | |
| 4656 | + kd.F_UpgradeTechBeauty, | |
| 4657 | + kd.F_UpgradeLifeBeauty | |
| 4658 | + FROM lq_kd_kdjlb kd | |
| 4659 | + WHERE kd.F_IsEffective = 1 | |
| 4660 | + AND kd.kdhy IS NOT NULL | |
| 4661 | + {whereClause} | |
| 4662 | + AND ( | |
| 4663 | + SELECT COUNT(*) | |
| 4664 | + FROM lq_kd_kdjlb kd2 | |
| 4665 | + WHERE kd2.kdhy = kd.kdhy | |
| 4666 | + AND kd2.F_IsEffective = 1 | |
| 4667 | + AND ( | |
| 4668 | + kd2.kdrq > kd.kdrq | |
| 4669 | + OR (kd2.kdrq = kd.kdrq AND kd2.F_CreateTime > kd.F_CreateTime) | |
| 4670 | + OR (kd2.kdrq = kd.kdrq AND kd2.F_CreateTime = kd.F_CreateTime AND kd2.F_Id > kd.F_Id) | |
| 4671 | + ) | |
| 4672 | + ) < 4 | |
| 4673 | + ) kd | |
| 4674 | + GROUP BY kd.kdhy | |
| 4675 | + {havingClause} | |
| 4676 | + ) as filtered_results"; | |
| 4677 | + | |
| 4678 | + var countParameters = parameters.Where(p => p.ParameterName != "@PageSize" && p.ParameterName != "@Offset").ToList(); | |
| 4679 | + var totalCount = await _db.Ado.GetIntAsync(countSql, countParameters); | |
| 4680 | + | |
| 4681 | + // 执行查询 | |
| 4682 | + var result = await _db.Ado.SqlQueryAsync<MemberUpgradeStatisticsListOutput>(sql, parameters); | |
| 4683 | + | |
| 4684 | + return new | |
| 4685 | + { | |
| 4686 | + list = result, | |
| 4687 | + pagination = new | |
| 4688 | + { | |
| 4689 | + pageIndex = input.PageIndex, | |
| 4690 | + pageSize = input.PageSize, | |
| 4691 | + total = totalCount | |
| 4692 | + } | |
| 4693 | + }; | |
| 4694 | + } | |
| 4695 | + catch (Exception ex) | |
| 4696 | + { | |
| 4697 | + _logger.LogError(ex, "获取会员升单统计失败"); | |
| 4698 | + throw NCCException.Oh($"获取会员升单统计失败:{ex.Message}"); | |
| 4699 | + } | |
| 4700 | + } | |
| 4701 | + #endregion | |
| 4702 | + | |
| 3952 | 4703 | |
| 3953 | 4704 | |
| 3954 | 4705 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqStoreConsumableInventoryService.cs
| 1 | 1 | using System; |
| 2 | +using System.Collections.Generic; | |
| 2 | 3 | using System.Linq; |
| 3 | 4 | using System.Threading.Tasks; |
| 4 | 5 | using Microsoft.AspNetCore.Mvc; |
| 5 | 6 | using Microsoft.Extensions.Logging; |
| 6 | 7 | using NCC.Common.Core.Manager; |
| 7 | 8 | using NCC.Common.Enum; |
| 9 | +using NCC.Common.Extension; | |
| 8 | 10 | using NCC.Common.Filter; |
| 9 | 11 | using NCC.Dependency; |
| 10 | 12 | using NCC.DynamicApiController; |
| 13 | +using NCC.Extend.Entitys.Dto.Common; | |
| 11 | 14 | using NCC.Extend.Entitys.Dto.LqStoreConsumableInventory; |
| 12 | 15 | using NCC.Extend.Entitys.Enum; |
| 13 | 16 | using NCC.Extend.Entitys.lq_mdxx; |
| ... | ... | @@ -367,6 +370,26 @@ namespace NCC.Extend |
| 367 | 370 | } |
| 368 | 371 | } |
| 369 | 372 | #endregion |
| 373 | + | |
| 374 | + | |
| 375 | + #region 获取消耗品产品类型枚举内容 | |
| 376 | + /// <summary> | |
| 377 | + /// 获取消耗品产品类型枚举内容 | |
| 378 | + /// </summary> | |
| 379 | + /// <returns>消耗品产品类型枚举列表</returns> | |
| 380 | + [HttpGet("consumable-product-type")] | |
| 381 | + public List<EnumOutput> GetConsumableProductTypeSelector() | |
| 382 | + { | |
| 383 | + return Enum.GetValues<ConsumableProductTypeEnum>() | |
| 384 | + .Select(e => new EnumOutput | |
| 385 | + { | |
| 386 | + Value = (int)e, | |
| 387 | + Name = e.ToString(), | |
| 388 | + Description = e.GetDescription(), | |
| 389 | + }) | |
| 390 | + .ToList(); | |
| 391 | + } | |
| 392 | + #endregion | |
| 370 | 393 | } |
| 371 | 394 | } |
| 372 | 395 | ... | ... |
sql/同步健康师业绩表品项分类和品项ID.sql
0 → 100644
| 1 | +-- 同步健康师业绩表和科技老师业绩表中的品项分类和品项ID字段 | |
| 2 | +-- 数据来源:通过关联的品项明细表获取 | |
| 3 | + | |
| 4 | +-- ============================================ | |
| 5 | +-- 健康师业绩表同步 | |
| 6 | +-- ============================================ | |
| 7 | + | |
| 8 | +-- 1. 开单健康师业绩表:从开单品项明细表(lq_kd_pxmx)同步 | |
| 9 | +UPDATE lq_kd_jksyj kd | |
| 10 | +INNER JOIN lq_kd_pxmx px ON px.F_Id = kd.F_kdpxid | |
| 11 | +SET | |
| 12 | + kd.F_ItemCategory = px.F_ItemCategory, | |
| 13 | + kd.F_ItemId = px.px | |
| 14 | +WHERE kd.F_kdpxid IS NOT NULL; | |
| 15 | + | |
| 16 | +-- 2. 耗卡健康师业绩表:从耗卡品项明细表(lq_xh_pxmx)同步 | |
| 17 | +UPDATE lq_xh_jksyj xh | |
| 18 | +INNER JOIN lq_xh_pxmx px ON px.F_Id = xh.F_kdpxid | |
| 19 | +SET | |
| 20 | + xh.F_ItemCategory = px.F_ItemCategory, | |
| 21 | + xh.F_ItemId = px.px | |
| 22 | +WHERE xh.F_kdpxid IS NOT NULL; | |
| 23 | + | |
| 24 | +-- 3. 退卡健康师业绩表:从退卡品项明细表(lq_hytk_mx)同步 | |
| 25 | +-- 注意:F_CardReturn 关联到 lq_hytk_mx.F_Id,F_tkpxid 是项目资料表ID(品项ID) | |
| 26 | +UPDATE lq_hytk_jksyj tk | |
| 27 | +INNER JOIN lq_hytk_mx mx ON mx.F_Id = tk.F_CardReturn | |
| 28 | +SET | |
| 29 | + tk.F_ItemCategory = mx.F_ItemCategory, | |
| 30 | + tk.F_ItemId = mx.px | |
| 31 | +WHERE tk.F_CardReturn IS NOT NULL; | |
| 32 | + | |
| 33 | +-- ============================================ | |
| 34 | +-- 科技老师业绩表同步 | |
| 35 | +-- ============================================ | |
| 36 | + | |
| 37 | +-- 4. 开单科技老师业绩表:从开单品项明细表(lq_kd_pxmx)同步 | |
| 38 | +UPDATE lq_kd_kjbsyj kd | |
| 39 | +INNER JOIN lq_kd_pxmx px ON px.F_Id = kd.F_kdpxid | |
| 40 | +SET | |
| 41 | + kd.F_ItemCategory = px.F_ItemCategory, | |
| 42 | + kd.F_ItemId = px.px | |
| 43 | +WHERE kd.F_kdpxid IS NOT NULL; | |
| 44 | + | |
| 45 | +-- 5. 耗卡科技老师业绩表:从耗卡品项明细表(lq_xh_pxmx)同步 | |
| 46 | +UPDATE lq_xh_kjbsyj xh | |
| 47 | +INNER JOIN lq_xh_pxmx px ON px.F_Id = xh.F_hkpxid | |
| 48 | +SET | |
| 49 | + xh.F_ItemCategory = px.F_ItemCategory, | |
| 50 | + xh.F_ItemId = px.px | |
| 51 | +WHERE xh.F_hkpxid IS NOT NULL; | |
| 52 | + | |
| 53 | +-- 6. 退卡科技老师业绩表:从退卡品项明细表(lq_hytk_mx)同步 | |
| 54 | +-- 注意:F_CardReturn 关联到 lq_hytk_mx.F_Id,F_tkpxid 是项目资料表ID(品项ID) | |
| 55 | +UPDATE lq_hytk_kjbsyj tk | |
| 56 | +INNER JOIN lq_hytk_mx mx ON mx.F_Id = tk.F_CardReturn | |
| 57 | +SET | |
| 58 | + tk.F_ItemCategory = mx.F_ItemCategory, | |
| 59 | + tk.F_ItemId = mx.px | |
| 60 | +WHERE tk.F_CardReturn IS NOT NULL; | |
| 61 | + | ... | ... |
sql/添加业绩表品项分类字段.sql
0 → 100644
| 1 | +-- 为6个业绩表添加品项分类字段和品项ID字段 | |
| 2 | + | |
| 3 | +-- 1. 开单健康师业绩表 | |
| 4 | +ALTER TABLE `lq_kd_jksyj` | |
| 5 | +ADD COLUMN `F_ItemCategory` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项分类' AFTER `F_ActivityId`, | |
| 6 | +ADD COLUMN `F_ItemId` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项ID' AFTER `F_ItemCategory`; | |
| 7 | + | |
| 8 | +-- 2. 开单科技老师业绩表 | |
| 9 | +ALTER TABLE `lq_kd_kjbsyj` | |
| 10 | +ADD COLUMN `F_ItemCategory` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项分类' AFTER `F_ActivityId`, | |
| 11 | +ADD COLUMN `F_ItemId` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项ID' AFTER `F_ItemCategory`; | |
| 12 | + | |
| 13 | +-- 3. 耗卡健康师业绩表 | |
| 14 | +ALTER TABLE `lq_xh_jksyj` | |
| 15 | +ADD COLUMN `F_ItemCategory` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项分类' AFTER `F_AccompaniedProjectNumber`, | |
| 16 | +ADD COLUMN `F_ItemId` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项ID' AFTER `F_ItemCategory`; | |
| 17 | + | |
| 18 | +-- 4. 耗卡科技老师业绩表 | |
| 19 | +ALTER TABLE `lq_xh_kjbsyj` | |
| 20 | +ADD COLUMN `F_ItemCategory` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项分类' AFTER `F_IsEffective`, | |
| 21 | +ADD COLUMN `F_ItemId` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项ID' AFTER `F_ItemCategory`; | |
| 22 | + | |
| 23 | +-- 5. 退卡健康师业绩表 | |
| 24 | +ALTER TABLE `lq_hytk_jksyj` | |
| 25 | +ADD COLUMN `F_ItemCategory` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项分类' AFTER `F_IsEffective`, | |
| 26 | +ADD COLUMN `F_ItemId` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项ID' AFTER `F_ItemCategory`; | |
| 27 | + | |
| 28 | +-- 6. 退卡科技老师业绩表 | |
| 29 | +ALTER TABLE `lq_hytk_kjbsyj` | |
| 30 | +ADD COLUMN `F_ItemCategory` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项分类' AFTER `F_IsEffective`, | |
| 31 | +ADD COLUMN `F_ItemId` VARCHAR(50) NULL DEFAULT NULL COMMENT '品项ID' AFTER `F_ItemCategory`; | |
| 32 | + | ... | ... |