Commit e97f24a6b626ceb8ad2c7d90633aa202d7bb9cab
1 parent
9825c841
feat: 新增开单品项明细记录列表查询接口
- 新增开单品项明细记录列表查询接口,支持多条件筛选和分页 - 优化查询性能,采用先分页后关联的查询方式 - 支持筛选条件:品项明细ID、开单ID、开单时间、营销活动、会员信息、品项信息等 - 返回字段:id、开单id、开单时间、营销活动名称、会员名、会员手机、品项名称、品项类型、实付金额、项目次数、来源类型、备注 - 更新接口文档,完善参数说明和返回字段说明
Showing
9 changed files
with
1304 additions
and
0 deletions
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqKdKdjlb | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 开单品项明细记录输出 | |
| 7 | + /// </summary> | |
| 8 | + public class BillingItemDetailListOutput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 品项明细ID | |
| 12 | + /// </summary> | |
| 13 | + public string id { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 开单ID | |
| 17 | + /// </summary> | |
| 18 | + public string billingId { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 开单时间 | |
| 22 | + /// </summary> | |
| 23 | + public DateTime? billingTime { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 营销活动名称 | |
| 27 | + /// </summary> | |
| 28 | + public string activityName { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 会员名称 | |
| 32 | + /// </summary> | |
| 33 | + public string memberName { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 会员手机 | |
| 37 | + /// </summary> | |
| 38 | + public string memberPhone { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 品项名称 | |
| 42 | + /// </summary> | |
| 43 | + public string itemName { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 品项类型(分类④-统计品项用) | |
| 47 | + /// </summary> | |
| 48 | + public string itemType { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 实付金额 | |
| 52 | + /// </summary> | |
| 53 | + public decimal actualPrice { get; set; } | |
| 54 | + | |
| 55 | + /// <summary> | |
| 56 | + /// 项目次数 | |
| 57 | + /// </summary> | |
| 58 | + public decimal projectNumber { get; set; } | |
| 59 | + | |
| 60 | + /// <summary> | |
| 61 | + /// 来源类型(购买/赠送/体验) | |
| 62 | + /// </summary> | |
| 63 | + public string sourceType { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 备注 | |
| 67 | + /// </summary> | |
| 68 | + public string remark { get; set; } | |
| 69 | + } | |
| 70 | +} | |
| 71 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs
0 → 100644
| 1 | +using NCC.Common.Filter; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqKdKdjlb | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 开单品项明细记录查询输入参数 | |
| 7 | + /// </summary> | |
| 8 | + public class BillingItemDetailListQueryInput : PageInputBase | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 品项明细ID | |
| 12 | + /// </summary> | |
| 13 | + public string Id { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 开单ID | |
| 17 | + /// </summary> | |
| 18 | + public string BillingId { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 开单时间(开始) | |
| 22 | + /// </summary> | |
| 23 | + public string StartBillingTime { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 开单时间(结束) | |
| 27 | + /// </summary> | |
| 28 | + public string EndBillingTime { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 营销活动ID | |
| 32 | + /// </summary> | |
| 33 | + public string ActivityId { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 会员ID | |
| 37 | + /// </summary> | |
| 38 | + public string MemberId { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 会员名称(模糊查询) | |
| 42 | + /// </summary> | |
| 43 | + public string MemberName { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 会员手机号 | |
| 47 | + /// </summary> | |
| 48 | + public string MemberPhone { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 品项ID | |
| 52 | + /// </summary> | |
| 53 | + public string ItemId { get; set; } | |
| 54 | + | |
| 55 | + /// <summary> | |
| 56 | + /// 品项名称(模糊查询) | |
| 57 | + /// </summary> | |
| 58 | + public string ItemName { get; set; } | |
| 59 | + | |
| 60 | + /// <summary> | |
| 61 | + /// 品项类型(分类④-统计品项用) | |
| 62 | + /// </summary> | |
| 63 | + public string ItemType { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 来源类型(购买/赠送/体验) | |
| 67 | + /// </summary> | |
| 68 | + public string SourceType { get; set; } | |
| 69 | + } | |
| 70 | +} | |
| 71 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/MemberItemInfoOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqKhxx | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 会员品项信息输出 | |
| 8 | + /// </summary> | |
| 9 | + public class MemberItemInfoOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 会员ID | |
| 13 | + /// </summary> | |
| 14 | + public string MemberId { get; set; } | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 会员编号(档案号) | |
| 18 | + /// </summary> | |
| 19 | + public string MemberCode { get; set; } | |
| 20 | + | |
| 21 | + /// <summary> | |
| 22 | + /// 会员名称 | |
| 23 | + /// </summary> | |
| 24 | + public string MemberName { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 会员电话 | |
| 28 | + /// </summary> | |
| 29 | + public string MemberPhone { get; set; } | |
| 30 | + | |
| 31 | + /// <summary> | |
| 32 | + /// 所属门店ID | |
| 33 | + /// </summary> | |
| 34 | + public string BelongStoreId { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 所属门店名称 | |
| 38 | + /// </summary> | |
| 39 | + public string BelongStoreName { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 开单信息列表 | |
| 43 | + /// </summary> | |
| 44 | + public List<BillingItemInfo> BillingItems { get; set; } = new List<BillingItemInfo>(); | |
| 45 | + } | |
| 46 | + | |
| 47 | + /// <summary> | |
| 48 | + /// 开单信息 | |
| 49 | + /// </summary> | |
| 50 | + public class BillingItemInfo | |
| 51 | + { | |
| 52 | + /// <summary> | |
| 53 | + /// 开单ID | |
| 54 | + /// </summary> | |
| 55 | + public string BillingId { get; set; } | |
| 56 | + | |
| 57 | + /// <summary> | |
| 58 | + /// 开单时间 | |
| 59 | + /// </summary> | |
| 60 | + public DateTime? BillingTime { get; set; } | |
| 61 | + | |
| 62 | + /// <summary> | |
| 63 | + /// 开单门店ID | |
| 64 | + /// </summary> | |
| 65 | + public string BillingStoreId { get; set; } | |
| 66 | + | |
| 67 | + /// <summary> | |
| 68 | + /// 开单门店名称 | |
| 69 | + /// </summary> | |
| 70 | + public string BillingStoreName { get; set; } | |
| 71 | + | |
| 72 | + /// <summary> | |
| 73 | + /// 开单人ID | |
| 74 | + /// </summary> | |
| 75 | + public string BillingUserId { get; set; } | |
| 76 | + | |
| 77 | + /// <summary> | |
| 78 | + /// 开单人名称 | |
| 79 | + /// </summary> | |
| 80 | + public string BillingUserName { get; set; } | |
| 81 | + | |
| 82 | + /// <summary> | |
| 83 | + /// 购买品项列表 | |
| 84 | + /// </summary> | |
| 85 | + public List<ItemDetail> PurchaseItems { get; set; } = new List<ItemDetail>(); | |
| 86 | + | |
| 87 | + /// <summary> | |
| 88 | + /// 购买品项总金额 | |
| 89 | + /// </summary> | |
| 90 | + public decimal PurchaseItemsTotalAmount { get; set; } | |
| 91 | + | |
| 92 | + /// <summary> | |
| 93 | + /// 赠送品项列表 | |
| 94 | + /// </summary> | |
| 95 | + public List<ItemDetail> GiftItems { get; set; } = new List<ItemDetail>(); | |
| 96 | + | |
| 97 | + /// <summary> | |
| 98 | + /// 体验品项列表 | |
| 99 | + /// </summary> | |
| 100 | + public List<ItemDetail> ExperienceItems { get; set; } = new List<ItemDetail>(); | |
| 101 | + | |
| 102 | + /// <summary> | |
| 103 | + /// 已消耗品项列表 | |
| 104 | + /// </summary> | |
| 105 | + public List<ItemDetail> ConsumedItems { get; set; } = new List<ItemDetail>(); | |
| 106 | + | |
| 107 | + /// <summary> | |
| 108 | + /// 已消耗品项总金额 | |
| 109 | + /// </summary> | |
| 110 | + public decimal ConsumedItemsTotalAmount { get; set; } | |
| 111 | + | |
| 112 | + /// <summary> | |
| 113 | + /// 已退卡品项列表 | |
| 114 | + /// </summary> | |
| 115 | + public List<ItemDetail> RefundedItems { get; set; } = new List<ItemDetail>(); | |
| 116 | + | |
| 117 | + /// <summary> | |
| 118 | + /// 已退卡品项总金额 | |
| 119 | + /// </summary> | |
| 120 | + public decimal RefundedItemsTotalAmount { get; set; } | |
| 121 | + | |
| 122 | + /// <summary> | |
| 123 | + /// 已储扣品项列表 | |
| 124 | + /// </summary> | |
| 125 | + public List<ItemDetail> DeductedItems { get; set; } = new List<ItemDetail>(); | |
| 126 | + | |
| 127 | + /// <summary> | |
| 128 | + /// 已储扣品项总金额 | |
| 129 | + /// </summary> | |
| 130 | + public decimal DeductedItemsTotalAmount { get; set; } | |
| 131 | + } | |
| 132 | + | |
| 133 | + /// <summary> | |
| 134 | + /// 品项明细 | |
| 135 | + /// </summary> | |
| 136 | + public class ItemDetail | |
| 137 | + { | |
| 138 | + /// <summary> | |
| 139 | + /// 品项ID | |
| 140 | + /// </summary> | |
| 141 | + public string ItemId { get; set; } | |
| 142 | + | |
| 143 | + /// <summary> | |
| 144 | + /// 品项名称 | |
| 145 | + /// </summary> | |
| 146 | + public string ItemName { get; set; } | |
| 147 | + | |
| 148 | + /// <summary> | |
| 149 | + /// 品项价格 | |
| 150 | + /// </summary> | |
| 151 | + public decimal ItemPrice { get; set; } | |
| 152 | + | |
| 153 | + /// <summary> | |
| 154 | + /// 项目次数 | |
| 155 | + /// </summary> | |
| 156 | + public decimal ProjectNumber { get; set; } | |
| 157 | + | |
| 158 | + /// <summary> | |
| 159 | + /// 总金额 | |
| 160 | + /// </summary> | |
| 161 | + public decimal TotalAmount { get; set; } | |
| 162 | + } | |
| 163 | +} | |
| 164 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/MemberItemInfoQueryInput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using NCC.Common.Filter; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqKhxx | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 会员品项信息查询输入参数 | |
| 8 | + /// </summary> | |
| 9 | + public class MemberItemInfoQueryInput : PageInputBase | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 会员ID | |
| 13 | + /// </summary> | |
| 14 | + public string MemberId { get; set; } | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 所属门店ID | |
| 18 | + /// </summary> | |
| 19 | + public string BelongStoreId { get; set; } | |
| 20 | + | |
| 21 | + /// <summary> | |
| 22 | + /// 开单门店ID | |
| 23 | + /// </summary> | |
| 24 | + public string BillingStoreId { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 开单人ID | |
| 28 | + /// </summary> | |
| 29 | + public string BillingUserId { get; set; } | |
| 30 | + | |
| 31 | + /// <summary> | |
| 32 | + /// 购买品项ID | |
| 33 | + /// </summary> | |
| 34 | + public string PurchaseItemId { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 赠送品项ID | |
| 38 | + /// </summary> | |
| 39 | + public string GiftItemId { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 体验品项ID | |
| 43 | + /// </summary> | |
| 44 | + public string ExperienceItemId { get; set; } | |
| 45 | + } | |
| 46 | +} | |
| 47 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
| ... | ... | @@ -3211,5 +3211,218 @@ namespace NCC.Extend.LqKdKdjlb |
| 3211 | 3211 | } |
| 3212 | 3212 | } |
| 3213 | 3213 | #endregion |
| 3214 | + | |
| 3215 | + #region 获取开单品项明细记录列表 | |
| 3216 | + /// <summary> | |
| 3217 | + /// 获取开单品项明细记录列表(分页) | |
| 3218 | + /// </summary> | |
| 3219 | + /// <remarks> | |
| 3220 | + /// 查询开单品项明细记录,支持多条件筛选和分页查询。采用先分页后关联的查询方式,确保分页准确性和查询性能。 | |
| 3221 | + /// | |
| 3222 | + /// 示例请求: | |
| 3223 | + /// ```json | |
| 3224 | + /// { | |
| 3225 | + /// "currentPage": 1, | |
| 3226 | + /// "pageSize": 10, | |
| 3227 | + /// "sidx": "yjsj", | |
| 3228 | + /// "sort": "DESC", | |
| 3229 | + /// "Id": "品项明细ID", | |
| 3230 | + /// "BillingId": "开单ID", | |
| 3231 | + /// "StartBillingTime": "2025-01-01", | |
| 3232 | + /// "EndBillingTime": "2025-12-31", | |
| 3233 | + /// "ActivityId": "营销活动ID", | |
| 3234 | + /// "MemberId": "会员ID", | |
| 3235 | + /// "MemberName": "会员名称", | |
| 3236 | + /// "MemberPhone": "会员手机号", | |
| 3237 | + /// "ItemId": "品项ID", | |
| 3238 | + /// "ItemName": "品项名称", | |
| 3239 | + /// "ItemType": "品项类型", | |
| 3240 | + /// "SourceType": "来源类型" | |
| 3241 | + /// } | |
| 3242 | + /// ``` | |
| 3243 | + /// | |
| 3244 | + /// 查询参数说明: | |
| 3245 | + /// - currentPage: 当前页码(必填,从1开始) | |
| 3246 | + /// - pageSize: 每页数量(必填) | |
| 3247 | + /// - sidx: 排序字段(可选,默认:yjsj,支持:id、billingId、billingTime、itemName、actualPrice、projectNumber等) | |
| 3248 | + /// - sort: 排序方式(可选,默认:DESC,支持:ASC、DESC) | |
| 3249 | + /// - Id: 品项明细ID(可选,精确匹配) | |
| 3250 | + /// - BillingId: 开单ID(可选,精确匹配) | |
| 3251 | + /// - StartBillingTime: 开单时间开始(可选,格式:yyyy-MM-dd,与EndBillingTime同时使用) | |
| 3252 | + /// - EndBillingTime: 开单时间结束(可选,格式:yyyy-MM-dd,与StartBillingTime同时使用) | |
| 3253 | + /// - ActivityId: 营销活动ID(可选,精确匹配) | |
| 3254 | + /// - MemberId: 会员ID(可选,精确匹配) | |
| 3255 | + /// - MemberName: 会员名称(可选,模糊查询) | |
| 3256 | + /// - MemberPhone: 会员手机号(可选,精确匹配) | |
| 3257 | + /// - ItemId: 品项ID(可选,精确匹配) | |
| 3258 | + /// - ItemName: 品项名称(可选,模糊查询) | |
| 3259 | + /// - ItemType: 品项类型(可选,精确匹配,对应项目资料表的qt2字段) | |
| 3260 | + /// - SourceType: 来源类型(可选,精确匹配,如:购买、赠送、体验) | |
| 3261 | + /// | |
| 3262 | + /// 返回数据结构: | |
| 3263 | + /// ```json | |
| 3264 | + /// { | |
| 3265 | + /// "pagination": { | |
| 3266 | + /// "pageIndex": 1, | |
| 3267 | + /// "pageSize": 10, | |
| 3268 | + /// "total": 100 | |
| 3269 | + /// }, | |
| 3270 | + /// "list": [ | |
| 3271 | + /// { | |
| 3272 | + /// "id": "品项明细ID", | |
| 3273 | + /// "billingId": "开单ID", | |
| 3274 | + /// "billingTime": "2025-11-15T10:00:00", | |
| 3275 | + /// "activityName": "营销活动名称", | |
| 3276 | + /// "memberName": "会员名称", | |
| 3277 | + /// "memberPhone": "会员手机号", | |
| 3278 | + /// "itemName": "品项名称", | |
| 3279 | + /// "itemType": "品项类型", | |
| 3280 | + /// "actualPrice": 500.00, | |
| 3281 | + /// "projectNumber": 5.0, | |
| 3282 | + /// "sourceType": "购买", | |
| 3283 | + /// "remark": "备注" | |
| 3284 | + /// } | |
| 3285 | + /// ] | |
| 3286 | + /// } | |
| 3287 | + /// ``` | |
| 3288 | + /// | |
| 3289 | + /// 返回字段说明: | |
| 3290 | + /// - id: 品项明细ID(主键) | |
| 3291 | + /// - billingId: 开单ID(关联开单记录表) | |
| 3292 | + /// - billingTime: 开单时间(业绩时间yjsj,DateTime格式) | |
| 3293 | + /// - activityName: 营销活动名称(关联营销活动表) | |
| 3294 | + /// - memberName: 会员名称(关联会员表) | |
| 3295 | + /// - memberPhone: 会员手机号(关联会员表) | |
| 3296 | + /// - itemName: 品项名称(品项明细表字段) | |
| 3297 | + /// - itemType: 品项类型(关联项目资料表的qt2字段) | |
| 3298 | + /// - actualPrice: 实付金额(decimal类型) | |
| 3299 | + /// - projectNumber: 项目次数(decimal类型,支持小数) | |
| 3300 | + /// - sourceType: 来源类型(字符串,如:购买、赠送、体验) | |
| 3301 | + /// - remark: 备注(字符串) | |
| 3302 | + /// </remarks> | |
| 3303 | + /// <param name="input">查询参数</param> | |
| 3304 | + /// <returns>开单品项明细记录列表(分页)</returns> | |
| 3305 | + /// <response code="200">查询成功,返回开单品项明细记录列表</response> | |
| 3306 | + /// <response code="400">参数错误,如页码或页大小无效</response> | |
| 3307 | + /// <response code="500">服务器错误,查询过程中发生异常</response> | |
| 3308 | + [HttpGet("billing-item-detail-list")] | |
| 3309 | + public async Task<dynamic> GetBillingItemDetailList([FromQuery] BillingItemDetailListQueryInput input) | |
| 3310 | + { | |
| 3311 | + try | |
| 3312 | + { | |
| 3313 | + var sidx = input.sidx == null ? "yjsj" : input.sidx; | |
| 3314 | + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; | |
| 3315 | + | |
| 3316 | + // 处理开单时间范围 | |
| 3317 | + List<string> queryBillingTime = null; | |
| 3318 | + DateTime? startBillingTime = null; | |
| 3319 | + DateTime? endBillingTime = null; | |
| 3320 | + if (!string.IsNullOrEmpty(input.StartBillingTime) && !string.IsNullOrEmpty(input.EndBillingTime)) | |
| 3321 | + { | |
| 3322 | + queryBillingTime = new List<string> { input.StartBillingTime, input.EndBillingTime }; | |
| 3323 | + startBillingTime = Ext.GetDateTime(queryBillingTime.First()); | |
| 3324 | + endBillingTime = Ext.GetDateTime(queryBillingTime.Last()); | |
| 3325 | + } | |
| 3326 | + | |
| 3327 | + // 优化查询:先分页查询主表,再批量查询关联数据,避免子查询性能问题 | |
| 3328 | + // 1. 先构建基础查询条件 | |
| 3329 | + var baseQuery = _db.Queryable<LqKdPxmxEntity>() | |
| 3330 | + .Where(pxmx => pxmx.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 3331 | + .WhereIF(!string.IsNullOrEmpty(input.Id), pxmx => pxmx.Id == input.Id) | |
| 3332 | + .WhereIF(!string.IsNullOrEmpty(input.BillingId), pxmx => pxmx.Glkdbh == input.BillingId) | |
| 3333 | + .WhereIF(queryBillingTime != null && startBillingTime.HasValue, pxmx => pxmx.Yjsj >= new DateTime(startBillingTime.Value.Year, startBillingTime.Value.Month, startBillingTime.Value.Day, 0, 0, 0)) | |
| 3334 | + .WhereIF(queryBillingTime != null && endBillingTime.HasValue, pxmx => pxmx.Yjsj <= new DateTime(endBillingTime.Value.Year, endBillingTime.Value.Month, endBillingTime.Value.Day, 23, 59, 59)) | |
| 3335 | + .WhereIF(!string.IsNullOrEmpty(input.ActivityId), pxmx => pxmx.ActivityId == input.ActivityId) | |
| 3336 | + .WhereIF(!string.IsNullOrEmpty(input.MemberId), pxmx => pxmx.MemberId == input.MemberId) | |
| 3337 | + .WhereIF(!string.IsNullOrEmpty(input.ItemId), pxmx => pxmx.Px == input.ItemId) | |
| 3338 | + .WhereIF(!string.IsNullOrEmpty(input.ItemName), pxmx => pxmx.Pxmc != null && pxmx.Pxmc.Contains(input.ItemName)) | |
| 3339 | + .WhereIF(!string.IsNullOrEmpty(input.SourceType), pxmx => pxmx.SourceType == input.SourceType); | |
| 3340 | + | |
| 3341 | + // 2. 通过 EXISTS 子查询筛选关联字段(在分页前筛选,确保分页准确) | |
| 3342 | + baseQuery = baseQuery | |
| 3343 | + .WhereIF(!string.IsNullOrEmpty(input.MemberName), pxmx => | |
| 3344 | + SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == pxmx.MemberId && x.Khmc != null && x.Khmc.Contains(input.MemberName)).Any()) | |
| 3345 | + .WhereIF(!string.IsNullOrEmpty(input.MemberPhone), pxmx => | |
| 3346 | + SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == pxmx.MemberId && x.Sjh == input.MemberPhone).Any()) | |
| 3347 | + .WhereIF(!string.IsNullOrEmpty(input.ItemType), pxmx => | |
| 3348 | + SqlFunc.Subqueryable<LqXmzlEntity>().Where(x => x.Id == pxmx.Px && x.Fl4 == input.ItemType).Any()); | |
| 3349 | + | |
| 3350 | + // 3. 先分页查询主表数据(查询实体类,提高性能) | |
| 3351 | + var pagedData = await baseQuery | |
| 3352 | + .OrderBy(sidx + " " + sort) | |
| 3353 | + .ToPagedListAsync(input.currentPage, input.pageSize); | |
| 3354 | + | |
| 3355 | + // 4. 批量查询关联数据 | |
| 3356 | + var itemIds = pagedData.list.Select(x => x.Id).ToList(); | |
| 3357 | + var memberIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.MemberId)).Select(x => x.MemberId).Distinct().ToList(); | |
| 3358 | + var activityIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.ActivityId)).Select(x => x.ActivityId).Distinct().ToList(); | |
| 3359 | + var projectIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.Px)).Select(x => x.Px).Distinct().ToList(); | |
| 3360 | + | |
| 3361 | + // 批量查询会员信息 | |
| 3362 | + var memberDict = new Dictionary<string, (string Name, string Phone)>(); | |
| 3363 | + if (memberIds.Any()) | |
| 3364 | + { | |
| 3365 | + var members = await _db.Queryable<LqKhxxEntity>() | |
| 3366 | + .Where(x => memberIds.Contains(x.Id)) | |
| 3367 | + .Select(x => new { x.Id, x.Khmc, x.Sjh }) | |
| 3368 | + .ToListAsync(); | |
| 3369 | + memberDict = members.ToDictionary(x => x.Id, x => (x.Khmc ?? "", x.Sjh ?? "")); | |
| 3370 | + } | |
| 3371 | + | |
| 3372 | + // 批量查询活动信息 | |
| 3373 | + var activityDict = new Dictionary<string, string>(); | |
| 3374 | + if (activityIds.Any()) | |
| 3375 | + { | |
| 3376 | + var activities = await _db.Queryable<LqPackageInfoEntity>() | |
| 3377 | + .Where(x => activityIds.Contains(x.Id)) | |
| 3378 | + .Select(x => new { x.Id, x.ActivityName }) | |
| 3379 | + .ToListAsync(); | |
| 3380 | + activityDict = activities.ToDictionary(x => x.Id, x => x.ActivityName ?? ""); | |
| 3381 | + } | |
| 3382 | + | |
| 3383 | + // 批量查询项目资料 | |
| 3384 | + var projectDict = new Dictionary<string, string>(); | |
| 3385 | + if (projectIds.Any()) | |
| 3386 | + { | |
| 3387 | + var projects = await _db.Queryable<LqXmzlEntity>() | |
| 3388 | + .Where(x => projectIds.Contains(x.Id)) | |
| 3389 | + .Select(x => new { x.Id, x.Qt2 }) | |
| 3390 | + .ToListAsync(); | |
| 3391 | + projectDict = projects.ToDictionary(x => x.Id, x => x.Qt2 ?? ""); | |
| 3392 | + } | |
| 3393 | + | |
| 3394 | + // 5. 组装返回数据 | |
| 3395 | + var resultList = pagedData.list.Select(pxmx => new BillingItemDetailListOutput | |
| 3396 | + { | |
| 3397 | + id = pxmx.Id, | |
| 3398 | + billingId = pxmx.Glkdbh, | |
| 3399 | + billingTime = pxmx.Yjsj, | |
| 3400 | + activityName = pxmx.ActivityId != null && activityDict.ContainsKey(pxmx.ActivityId) ? activityDict[pxmx.ActivityId] : "", | |
| 3401 | + memberName = pxmx.MemberId != null && memberDict.ContainsKey(pxmx.MemberId) ? memberDict[pxmx.MemberId].Name : "", | |
| 3402 | + memberPhone = pxmx.MemberId != null && memberDict.ContainsKey(pxmx.MemberId) ? memberDict[pxmx.MemberId].Phone : "", | |
| 3403 | + itemName = pxmx.Pxmc, | |
| 3404 | + itemType = pxmx.Px != null && projectDict.ContainsKey(pxmx.Px) ? projectDict[pxmx.Px] : "", | |
| 3405 | + actualPrice = pxmx.ActualPrice, | |
| 3406 | + projectNumber = pxmx.ProjectNumber, | |
| 3407 | + sourceType = pxmx.SourceType, | |
| 3408 | + remark = pxmx.Remark | |
| 3409 | + }).ToList(); | |
| 3410 | + | |
| 3411 | + // 6. 返回分页结果 | |
| 3412 | + var result = new SqlSugarPagedList<BillingItemDetailListOutput> | |
| 3413 | + { | |
| 3414 | + list = resultList, | |
| 3415 | + pagination = pagedData.pagination | |
| 3416 | + }; | |
| 3417 | + | |
| 3418 | + return PageResult<BillingItemDetailListOutput>.SqlSugarPageResult(result); | |
| 3419 | + } | |
| 3420 | + catch (Exception ex) | |
| 3421 | + { | |
| 3422 | + _logger.LogError(ex, $"获取开单品项明细记录列表失败: {ex.ToString()}"); | |
| 3423 | + throw NCCException.Oh(ErrorCode.COM1005, $"获取开单品项明细记录列表失败: {ex.Message}"); | |
| 3424 | + } | |
| 3425 | + } | |
| 3426 | + #endregion | |
| 3214 | 3427 | } |
| 3215 | 3428 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs
| ... | ... | @@ -776,5 +776,676 @@ namespace NCC.Extend.LqKhxx |
| 776 | 776 | } |
| 777 | 777 | #endregion |
| 778 | 778 | |
| 779 | + #region 获取会员品项信息 | |
| 780 | + /// <summary> | |
| 781 | + /// 获取所有会员的品项信息(分页) | |
| 782 | + /// </summary> | |
| 783 | + /// <remarks> | |
| 784 | + /// 查询所有会员的品项信息,包括购买品项、赠送品项、体验品项、已消耗品项、已退卡品项、已储扣品项 | |
| 785 | + /// | |
| 786 | + /// 示例请求: | |
| 787 | + /// ```json | |
| 788 | + /// { | |
| 789 | + /// "currentPage": 1, | |
| 790 | + /// "pageSize": 10, | |
| 791 | + /// "MemberId": "会员ID", | |
| 792 | + /// "BelongStoreId": "所属门店ID", | |
| 793 | + /// "BillingStoreId": "开单门店ID", | |
| 794 | + /// "BillingUserId": "开单人ID", | |
| 795 | + /// "PurchaseItemId": "购买品项ID", | |
| 796 | + /// "GiftItemId": "赠送品项ID", | |
| 797 | + /// "ExperienceItemId": "体验品项ID" | |
| 798 | + /// } | |
| 799 | + /// ``` | |
| 800 | + /// | |
| 801 | + /// 参数说明: | |
| 802 | + /// - currentPage: 当前页码(必填) | |
| 803 | + /// - pageSize: 每页数量(必填) | |
| 804 | + /// - MemberId: 会员ID(可选) | |
| 805 | + /// - BelongStoreId: 所属门店ID(可选) | |
| 806 | + /// - BillingStoreId: 开单门店ID(可选) | |
| 807 | + /// - BillingUserId: 开单人ID(可选) | |
| 808 | + /// - PurchaseItemId: 购买品项ID(可选) | |
| 809 | + /// - GiftItemId: 赠送品项ID(可选) | |
| 810 | + /// - ExperienceItemId: 体验品项ID(可选) | |
| 811 | + /// | |
| 812 | + /// 返回数据结构说明: | |
| 813 | + /// ```json | |
| 814 | + /// { | |
| 815 | + /// "pagination": { | |
| 816 | + /// "pageIndex": 1, | |
| 817 | + /// "pageSize": 10, | |
| 818 | + /// "total": 100 | |
| 819 | + /// }, | |
| 820 | + /// "list": [ | |
| 821 | + /// { | |
| 822 | + /// "memberId": "会员ID", | |
| 823 | + /// "memberCode": "会员编号(档案号)", | |
| 824 | + /// "memberName": "会员名称", | |
| 825 | + /// "memberPhone": "会员电话", | |
| 826 | + /// "belongStoreId": "所属门店ID", | |
| 827 | + /// "belongStoreName": "所属门店名称", | |
| 828 | + /// "billingItems": [ | |
| 829 | + /// { | |
| 830 | + /// "billingId": "开单ID", | |
| 831 | + /// "billingTime": "2025-11-15T10:00:00", | |
| 832 | + /// "billingStoreId": "开单门店ID", | |
| 833 | + /// "billingStoreName": "开单门店名称", | |
| 834 | + /// "billingUserId": "开单人ID", | |
| 835 | + /// "billingUserName": "开单人名称", | |
| 836 | + /// "purchaseItems": [ | |
| 837 | + /// { | |
| 838 | + /// "itemId": "品项ID", | |
| 839 | + /// "itemName": "品项名称", | |
| 840 | + /// "itemPrice": 100.00, | |
| 841 | + /// "projectNumber": 5.0, | |
| 842 | + /// "totalAmount": 500.00 | |
| 843 | + /// } | |
| 844 | + /// ], | |
| 845 | + /// "purchaseItemsTotalAmount": 500.00, | |
| 846 | + /// "giftItems": [ | |
| 847 | + /// { | |
| 848 | + /// "itemId": "品项ID", | |
| 849 | + /// "itemName": "品项名称", | |
| 850 | + /// "itemPrice": 50.00, | |
| 851 | + /// "projectNumber": 2.0, | |
| 852 | + /// "totalAmount": 100.00 | |
| 853 | + /// } | |
| 854 | + /// ], | |
| 855 | + /// "experienceItems": [ | |
| 856 | + /// { | |
| 857 | + /// "itemId": "品项ID", | |
| 858 | + /// "itemName": "品项名称", | |
| 859 | + /// "itemPrice": 30.00, | |
| 860 | + /// "projectNumber": 1.0, | |
| 861 | + /// "totalAmount": 30.00 | |
| 862 | + /// } | |
| 863 | + /// ], | |
| 864 | + /// "consumedItems": [ | |
| 865 | + /// { | |
| 866 | + /// "itemId": "品项ID", | |
| 867 | + /// "itemName": "品项名称", | |
| 868 | + /// "itemPrice": 100.00, | |
| 869 | + /// "projectNumber": 2.0, | |
| 870 | + /// "totalAmount": 200.00 | |
| 871 | + /// } | |
| 872 | + /// ], | |
| 873 | + /// "consumedItemsTotalAmount": 200.00, | |
| 874 | + /// "refundedItems": [ | |
| 875 | + /// { | |
| 876 | + /// "itemId": "品项ID", | |
| 877 | + /// "itemName": "品项名称", | |
| 878 | + /// "itemPrice": 100.00, | |
| 879 | + /// "projectNumber": 1.0, | |
| 880 | + /// "totalAmount": 100.00 | |
| 881 | + /// } | |
| 882 | + /// ], | |
| 883 | + /// "refundedItemsTotalAmount": 100.00, | |
| 884 | + /// "deductedItems": [ | |
| 885 | + /// { | |
| 886 | + /// "itemId": "品项ID", | |
| 887 | + /// "itemName": "品项名称", | |
| 888 | + /// "itemPrice": 100.00, | |
| 889 | + /// "projectNumber": 1.0, | |
| 890 | + /// "totalAmount": 100.00 | |
| 891 | + /// } | |
| 892 | + /// ], | |
| 893 | + /// "deductedItemsTotalAmount": 100.00 | |
| 894 | + /// } | |
| 895 | + /// ] | |
| 896 | + /// } | |
| 897 | + /// ] | |
| 898 | + /// } | |
| 899 | + /// ``` | |
| 900 | + /// | |
| 901 | + /// 返回字段说明: | |
| 902 | + /// | |
| 903 | + /// **分页信息 (pagination)**: | |
| 904 | + /// - pageIndex: 当前页码 | |
| 905 | + /// - pageSize: 每页数量 | |
| 906 | + /// - total: 总记录数 | |
| 907 | + /// | |
| 908 | + /// **会员信息 (list[].memberInfo)**: | |
| 909 | + /// - memberId: 会员ID | |
| 910 | + /// - memberCode: 会员编号(档案号) | |
| 911 | + /// - memberName: 会员名称 | |
| 912 | + /// - memberPhone: 会员电话 | |
| 913 | + /// - belongStoreId: 所属门店ID | |
| 914 | + /// - belongStoreName: 所属门店名称 | |
| 915 | + /// | |
| 916 | + /// **开单信息 (list[].billingItems[])**: | |
| 917 | + /// - billingId: 开单ID | |
| 918 | + /// - billingTime: 开单时间(DateTime格式) | |
| 919 | + /// - billingStoreId: 开单门店ID | |
| 920 | + /// - billingStoreName: 开单门店名称 | |
| 921 | + /// - billingUserId: 开单人ID | |
| 922 | + /// - billingUserName: 开单人名称 | |
| 923 | + /// | |
| 924 | + /// **品项信息 (list[].billingItems[].*Items[])**: | |
| 925 | + /// - purchaseItems: 购买品项列表 | |
| 926 | + /// - purchaseItemsTotalAmount: 购买品项总金额 | |
| 927 | + /// - giftItems: 赠送品项列表 | |
| 928 | + /// - experienceItems: 体验品项列表 | |
| 929 | + /// - consumedItems: 已消耗品项列表 | |
| 930 | + /// - consumedItemsTotalAmount: 已消耗品项总金额 | |
| 931 | + /// - refundedItems: 已退卡品项列表 | |
| 932 | + /// - refundedItemsTotalAmount: 已退卡品项总金额 | |
| 933 | + /// - deductedItems: 已储扣品项列表 | |
| 934 | + /// - deductedItemsTotalAmount: 已储扣品项总金额 | |
| 935 | + /// | |
| 936 | + /// **品项明细 (ItemDetail)**: | |
| 937 | + /// - itemId: 品项ID | |
| 938 | + /// - itemName: 品项名称 | |
| 939 | + /// - itemPrice: 品项单价 | |
| 940 | + /// - projectNumber: 项目次数(支持小数) | |
| 941 | + /// - totalAmount: 总金额(单价 × 次数) | |
| 942 | + /// </remarks> | |
| 943 | + /// <param name="input">查询参数</param> | |
| 944 | + /// <returns>会员品项信息列表(分页)</returns> | |
| 945 | + /// <response code="200">查询成功,返回会员品项信息列表</response> | |
| 946 | + /// <response code="400">参数错误,如页码或页大小无效</response> | |
| 947 | + /// <response code="500">服务器错误,查询过程中发生异常</response> | |
| 948 | + [HttpPost("get-member-item-info")] | |
| 949 | + public async Task<dynamic> GetMemberItemInfo([FromBody] MemberItemInfoQueryInput input) | |
| 950 | + { | |
| 951 | + try | |
| 952 | + { | |
| 953 | + // 1. 构建会员查询条件 | |
| 954 | + var memberQuery = _db.Queryable<LqKhxxEntity>(); | |
| 955 | + | |
| 956 | + // 筛选条件 | |
| 957 | + if (!string.IsNullOrEmpty(input.MemberId)) | |
| 958 | + { | |
| 959 | + memberQuery = memberQuery.Where(x => x.Id == input.MemberId); | |
| 960 | + } | |
| 961 | + | |
| 962 | + if (!string.IsNullOrEmpty(input.BelongStoreId)) | |
| 963 | + { | |
| 964 | + memberQuery = memberQuery.Where(x => x.Gsmd == input.BelongStoreId); | |
| 965 | + } | |
| 966 | + | |
| 967 | + // 如果指定了开单门店、开单人、品项ID等条件,需要通过开单表进行筛选 | |
| 968 | + if (!string.IsNullOrEmpty(input.BillingStoreId) || | |
| 969 | + !string.IsNullOrEmpty(input.BillingUserId) || | |
| 970 | + !string.IsNullOrEmpty(input.PurchaseItemId) || | |
| 971 | + !string.IsNullOrEmpty(input.GiftItemId) || | |
| 972 | + !string.IsNullOrEmpty(input.ExperienceItemId)) | |
| 973 | + { | |
| 974 | + // 先查询符合条件的开单记录,获取会员ID列表 | |
| 975 | + var billingQuery = _db.Queryable<LqKdKdjlbEntity>() | |
| 976 | + .Where(x => x.IsEffective == StatusEnum.有效.GetHashCode()); | |
| 977 | + | |
| 978 | + if (!string.IsNullOrEmpty(input.BillingStoreId)) | |
| 979 | + { | |
| 980 | + billingQuery = billingQuery.Where(x => x.Djmd == input.BillingStoreId); | |
| 981 | + } | |
| 982 | + | |
| 983 | + if (!string.IsNullOrEmpty(input.BillingUserId)) | |
| 984 | + { | |
| 985 | + billingQuery = billingQuery.Where(x => x.CreateUser == input.BillingUserId); | |
| 986 | + } | |
| 987 | + | |
| 988 | + // 如果指定了品项ID,需要通过品项明细表进行筛选 | |
| 989 | + if (!string.IsNullOrEmpty(input.PurchaseItemId) || | |
| 990 | + !string.IsNullOrEmpty(input.GiftItemId) || | |
| 991 | + !string.IsNullOrEmpty(input.ExperienceItemId)) | |
| 992 | + { | |
| 993 | + var itemQuery = _db.Queryable<LqKdPxmxEntity>() | |
| 994 | + .Where(x => x.IsEffective == StatusEnum.有效.GetHashCode()); | |
| 995 | + | |
| 996 | + if (!string.IsNullOrEmpty(input.PurchaseItemId)) | |
| 997 | + { | |
| 998 | + itemQuery = itemQuery.Where(x => x.Px == input.PurchaseItemId && x.SourceType == "购买"); | |
| 999 | + } | |
| 1000 | + | |
| 1001 | + if (!string.IsNullOrEmpty(input.GiftItemId)) | |
| 1002 | + { | |
| 1003 | + itemQuery = itemQuery.Where(x => x.Px == input.GiftItemId && x.SourceType == "赠送"); | |
| 1004 | + } | |
| 1005 | + | |
| 1006 | + if (!string.IsNullOrEmpty(input.ExperienceItemId)) | |
| 1007 | + { | |
| 1008 | + itemQuery = itemQuery.Where(x => x.Px == input.ExperienceItemId && x.SourceType == "体验"); | |
| 1009 | + } | |
| 1010 | + | |
| 1011 | + var itemBillingIds = await itemQuery.Select(x => x.Glkdbh).Distinct().ToListAsync(); | |
| 1012 | + if (itemBillingIds != null && itemBillingIds.Any()) | |
| 1013 | + { | |
| 1014 | + billingQuery = billingQuery.Where(x => itemBillingIds.Contains(x.Id)); | |
| 1015 | + } | |
| 1016 | + else | |
| 1017 | + { | |
| 1018 | + // 如果没有匹配的品项记录,返回空结果 | |
| 1019 | + return PageResult<MemberItemInfoOutput>.SqlSugarPageResult(new SqlSugarPagedList<MemberItemInfoOutput> | |
| 1020 | + { | |
| 1021 | + list = new List<MemberItemInfoOutput>(), | |
| 1022 | + pagination = new PagedModel | |
| 1023 | + { | |
| 1024 | + PageIndex = input.currentPage, | |
| 1025 | + PageSize = input.pageSize, | |
| 1026 | + Total = 0 | |
| 1027 | + } | |
| 1028 | + }); | |
| 1029 | + } | |
| 1030 | + } | |
| 1031 | + | |
| 1032 | + var memberIds = await billingQuery.Select(x => x.Kdhy).Distinct().ToListAsync(); | |
| 1033 | + if (memberIds != null && memberIds.Any()) | |
| 1034 | + { | |
| 1035 | + memberQuery = memberQuery.Where(x => memberIds.Contains(x.Id)); | |
| 1036 | + } | |
| 1037 | + else | |
| 1038 | + { | |
| 1039 | + // 如果没有匹配的开单记录,返回空结果 | |
| 1040 | + return PageResult<MemberItemInfoOutput>.SqlSugarPageResult(new SqlSugarPagedList<MemberItemInfoOutput> | |
| 1041 | + { | |
| 1042 | + list = new List<MemberItemInfoOutput>(), | |
| 1043 | + pagination = new PagedModel | |
| 1044 | + { | |
| 1045 | + PageIndex = input.currentPage, | |
| 1046 | + PageSize = input.pageSize, | |
| 1047 | + Total = 0 | |
| 1048 | + } | |
| 1049 | + }); | |
| 1050 | + } | |
| 1051 | + } | |
| 1052 | + | |
| 1053 | + // 2. 分页查询会员列表 | |
| 1054 | + var totalCount = await memberQuery.CountAsync(); | |
| 1055 | + var skipCount = (input.currentPage - 1) * input.pageSize; | |
| 1056 | + var memberList = await memberQuery | |
| 1057 | + .OrderBy(x => x.Id) | |
| 1058 | + .Skip(skipCount) | |
| 1059 | + .Take(input.pageSize) | |
| 1060 | + .Select(x => new | |
| 1061 | + { | |
| 1062 | + x.Id, | |
| 1063 | + x.Dah, | |
| 1064 | + x.Khmc, | |
| 1065 | + x.Sjh, | |
| 1066 | + x.Gsmd | |
| 1067 | + }) | |
| 1068 | + .ToListAsync(); | |
| 1069 | + | |
| 1070 | + var memberData = new SqlSugarPagedList<dynamic> | |
| 1071 | + { | |
| 1072 | + list = memberList.Cast<dynamic>().ToList(), | |
| 1073 | + pagination = new PagedModel | |
| 1074 | + { | |
| 1075 | + PageIndex = input.currentPage, | |
| 1076 | + PageSize = input.pageSize, | |
| 1077 | + Total = totalCount | |
| 1078 | + } | |
| 1079 | + }; | |
| 1080 | + | |
| 1081 | + if (memberList == null || !memberList.Any()) | |
| 1082 | + { | |
| 1083 | + return PageResult<MemberItemInfoOutput>.SqlSugarPageResult(new SqlSugarPagedList<MemberItemInfoOutput> | |
| 1084 | + { | |
| 1085 | + list = new List<MemberItemInfoOutput>(), | |
| 1086 | + pagination = new PagedModel | |
| 1087 | + { | |
| 1088 | + PageIndex = input.currentPage, | |
| 1089 | + PageSize = input.pageSize, | |
| 1090 | + Total = totalCount | |
| 1091 | + } | |
| 1092 | + }); | |
| 1093 | + } | |
| 1094 | + | |
| 1095 | + var memberIdsList = memberList.Select(x => x.Id).ToList(); | |
| 1096 | + | |
| 1097 | + // 3. 批量查询会员的开单记录 | |
| 1098 | + var billingRecords = await _db.Queryable<LqKdKdjlbEntity>() | |
| 1099 | + .Where(x => memberIdsList.Contains(x.Kdhy) && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 1100 | + .Select(x => new | |
| 1101 | + { | |
| 1102 | + x.Id, | |
| 1103 | + x.Kdhy, | |
| 1104 | + x.Kdrq, | |
| 1105 | + x.Djmd, | |
| 1106 | + x.CreateUser | |
| 1107 | + }) | |
| 1108 | + .ToListAsync(); | |
| 1109 | + | |
| 1110 | + var billingIds = billingRecords.Select(x => x.Id).ToList(); | |
| 1111 | + | |
| 1112 | + // 4. 批量查询开单的品项明细 | |
| 1113 | + var itemDetails = new List<dynamic>(); | |
| 1114 | + if (billingIds.Any()) | |
| 1115 | + { | |
| 1116 | + var itemDetailsData = await _db.Queryable<LqKdPxmxEntity>() | |
| 1117 | + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 1118 | + .Select(x => new | |
| 1119 | + { | |
| 1120 | + x.Id, | |
| 1121 | + x.Glkdbh, | |
| 1122 | + x.Px, | |
| 1123 | + x.Pxmc, | |
| 1124 | + x.Pxjg, | |
| 1125 | + x.SourceType, | |
| 1126 | + x.ProjectNumber, | |
| 1127 | + x.TotalPrice | |
| 1128 | + }) | |
| 1129 | + .ToListAsync(); | |
| 1130 | + itemDetails = itemDetailsData.Cast<dynamic>().ToList(); | |
| 1131 | + } | |
| 1132 | + | |
| 1133 | + var itemDetailIds = itemDetails.Select(x => (string)x.Id).ToList(); | |
| 1134 | + | |
| 1135 | + // 5. 批量查询消耗品项 | |
| 1136 | + var consumedItems = new List<dynamic>(); | |
| 1137 | + if (itemDetailIds.Any()) | |
| 1138 | + { | |
| 1139 | + var consumedItemsData = await _db.Queryable<LqXhPxmxEntity>() | |
| 1140 | + .Where(x => itemDetailIds.Contains(x.BillingItemId) && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 1141 | + .Select(x => new | |
| 1142 | + { | |
| 1143 | + x.BillingItemId, | |
| 1144 | + x.Px, | |
| 1145 | + x.Pxmc, | |
| 1146 | + x.Pxjg, | |
| 1147 | + x.ProjectNumber, | |
| 1148 | + x.TotalPrice | |
| 1149 | + }) | |
| 1150 | + .ToListAsync(); | |
| 1151 | + consumedItems = consumedItemsData.Cast<dynamic>().ToList(); | |
| 1152 | + } | |
| 1153 | + | |
| 1154 | + // 6. 批量查询退卡品项 | |
| 1155 | + var refundedItems = new List<dynamic>(); | |
| 1156 | + if (itemDetailIds.Any()) | |
| 1157 | + { | |
| 1158 | + var refundedItemsData = await _db.Queryable<LqHytkMxEntity>() | |
| 1159 | + .Where(x => itemDetailIds.Contains(x.BillingItemId) && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 1160 | + .Select(x => new | |
| 1161 | + { | |
| 1162 | + x.BillingItemId, | |
| 1163 | + x.Px, | |
| 1164 | + x.Pxmc, | |
| 1165 | + x.Pxjg, | |
| 1166 | + x.ProjectNumber, | |
| 1167 | + x.Tkje | |
| 1168 | + }) | |
| 1169 | + .ToListAsync(); | |
| 1170 | + refundedItems = refundedItemsData.Cast<dynamic>().ToList(); | |
| 1171 | + } | |
| 1172 | + | |
| 1173 | + // 7. 批量查询储扣品项 | |
| 1174 | + var deductedItems = new List<dynamic>(); | |
| 1175 | + if (billingIds.Any()) | |
| 1176 | + { | |
| 1177 | + var deductedItemsData = await _db.Queryable<LqKdDeductinfoEntity>() | |
| 1178 | + .Where(x => billingIds.Contains(x.BillingId) && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 1179 | + .Select(x => new | |
| 1180 | + { | |
| 1181 | + x.BillingId, | |
| 1182 | + x.ItemId, | |
| 1183 | + x.ItemName, | |
| 1184 | + x.UnitPrice, | |
| 1185 | + x.ProjectNumber, | |
| 1186 | + x.Amount | |
| 1187 | + }) | |
| 1188 | + .ToListAsync(); | |
| 1189 | + deductedItems = deductedItemsData.Cast<dynamic>().ToList(); | |
| 1190 | + } | |
| 1191 | + | |
| 1192 | + // 8. 批量查询门店信息 | |
| 1193 | + var storeIds = new List<string>(); | |
| 1194 | + if (memberList != null && memberList.Any()) | |
| 1195 | + { | |
| 1196 | + storeIds.AddRange(memberList.Select(x => x.Gsmd).Where(x => !string.IsNullOrEmpty(x))); | |
| 1197 | + } | |
| 1198 | + if (billingRecords != null && billingRecords.Any()) | |
| 1199 | + { | |
| 1200 | + storeIds.AddRange(billingRecords.Select(x => x.Djmd).Where(x => !string.IsNullOrEmpty(x))); | |
| 1201 | + } | |
| 1202 | + storeIds = storeIds.Distinct().ToList(); | |
| 1203 | + | |
| 1204 | + var stores = new Dictionary<string, string>(); | |
| 1205 | + if (storeIds.Any()) | |
| 1206 | + { | |
| 1207 | + var storeList = await _db.Queryable<LqMdxxEntity>() | |
| 1208 | + .Where(x => storeIds.Contains(x.Id)) | |
| 1209 | + .Select(x => new { x.Id, x.Dm }) | |
| 1210 | + .ToListAsync(); | |
| 1211 | + | |
| 1212 | + stores = storeList.ToDictionary(x => x.Id, x => x.Dm ?? ""); | |
| 1213 | + } | |
| 1214 | + | |
| 1215 | + // 9. 批量查询用户信息 | |
| 1216 | + var userIds = new List<string>(); | |
| 1217 | + if (billingRecords != null && billingRecords.Any()) | |
| 1218 | + { | |
| 1219 | + userIds = billingRecords.Select(x => x.CreateUser) | |
| 1220 | + .Where(x => !string.IsNullOrEmpty(x)) | |
| 1221 | + .Distinct() | |
| 1222 | + .ToList(); | |
| 1223 | + } | |
| 1224 | + | |
| 1225 | + var users = new Dictionary<string, string>(); | |
| 1226 | + if (userIds.Any()) | |
| 1227 | + { | |
| 1228 | + var userList = await _db.Queryable<UserEntity>() | |
| 1229 | + .Where(x => userIds.Contains(x.Id)) | |
| 1230 | + .Select(x => new { x.Id, x.RealName }) | |
| 1231 | + .ToListAsync(); | |
| 1232 | + | |
| 1233 | + users = userList.ToDictionary(x => x.Id, x => x.RealName ?? ""); | |
| 1234 | + } | |
| 1235 | + | |
| 1236 | + // 10. 组装数据 | |
| 1237 | + var result = new List<MemberItemInfoOutput>(); | |
| 1238 | + | |
| 1239 | + foreach (var member in memberList) | |
| 1240 | + { | |
| 1241 | + var memberOutput = new MemberItemInfoOutput | |
| 1242 | + { | |
| 1243 | + MemberId = member.Id, | |
| 1244 | + MemberCode = member.Dah ?? "", | |
| 1245 | + MemberName = member.Khmc ?? "", | |
| 1246 | + MemberPhone = member.Sjh ?? "", | |
| 1247 | + BelongStoreId = member.Gsmd ?? "", | |
| 1248 | + BelongStoreName = stores.ContainsKey(member.Gsmd ?? "") ? stores[member.Gsmd] : "" | |
| 1249 | + }; | |
| 1250 | + | |
| 1251 | + // 获取该会员的所有开单 | |
| 1252 | + var memberBillings = billingRecords.Where(x => x.Kdhy == member.Id).ToList(); | |
| 1253 | + | |
| 1254 | + foreach (var billing in memberBillings) | |
| 1255 | + { | |
| 1256 | + var billingItem = new BillingItemInfo | |
| 1257 | + { | |
| 1258 | + BillingId = billing.Id, | |
| 1259 | + BillingTime = billing.Kdrq, | |
| 1260 | + BillingStoreId = billing.Djmd ?? "", | |
| 1261 | + BillingStoreName = stores.ContainsKey(billing.Djmd ?? "") ? stores[billing.Djmd] : "", | |
| 1262 | + BillingUserId = billing.CreateUser ?? "", | |
| 1263 | + BillingUserName = users.ContainsKey(billing.CreateUser ?? "") ? users[billing.CreateUser] : "" | |
| 1264 | + }; | |
| 1265 | + | |
| 1266 | + // 获取该开单的所有品项明细 | |
| 1267 | + var billingItemDetails = itemDetails.Where(x => | |
| 1268 | + { | |
| 1269 | + try | |
| 1270 | + { | |
| 1271 | + return x.Glkdbh?.ToString() == billing.Id; | |
| 1272 | + } | |
| 1273 | + catch | |
| 1274 | + { | |
| 1275 | + return false; | |
| 1276 | + } | |
| 1277 | + }).ToList(); | |
| 1278 | + | |
| 1279 | + // 分类品项 | |
| 1280 | + foreach (var item in billingItemDetails) | |
| 1281 | + { | |
| 1282 | + try | |
| 1283 | + { | |
| 1284 | + var itemDetail = new ItemDetail | |
| 1285 | + { | |
| 1286 | + ItemId = item.Px?.ToString() ?? "", | |
| 1287 | + ItemName = item.Pxmc?.ToString() ?? "", | |
| 1288 | + ItemPrice = Convert.ToDecimal(item.Pxjg ?? 0), | |
| 1289 | + ProjectNumber = Convert.ToDecimal(item.ProjectNumber ?? 0), | |
| 1290 | + TotalAmount = Convert.ToDecimal(item.TotalPrice ?? 0) | |
| 1291 | + }; | |
| 1292 | + | |
| 1293 | + var sourceType = item.SourceType?.ToString() ?? ""; | |
| 1294 | + if (sourceType == "购买") | |
| 1295 | + { | |
| 1296 | + billingItem.PurchaseItems.Add(itemDetail); | |
| 1297 | + billingItem.PurchaseItemsTotalAmount += itemDetail.TotalAmount; | |
| 1298 | + } | |
| 1299 | + else if (sourceType == "赠送") | |
| 1300 | + { | |
| 1301 | + billingItem.GiftItems.Add(itemDetail); | |
| 1302 | + } | |
| 1303 | + else if (sourceType == "体验") | |
| 1304 | + { | |
| 1305 | + billingItem.ExperienceItems.Add(itemDetail); | |
| 1306 | + } | |
| 1307 | + } | |
| 1308 | + catch (Exception ex) | |
| 1309 | + { | |
| 1310 | + _logger.LogWarning(ex, "处理品项明细时出错,开单ID:{BillingId}", billing.Id); | |
| 1311 | + } | |
| 1312 | + } | |
| 1313 | + | |
| 1314 | + // 获取消耗品项 | |
| 1315 | + var billingItemIds = billingItemDetails.Select(x => | |
| 1316 | + { | |
| 1317 | + try | |
| 1318 | + { | |
| 1319 | + return x.Id?.ToString() ?? ""; | |
| 1320 | + } | |
| 1321 | + catch | |
| 1322 | + { | |
| 1323 | + return ""; | |
| 1324 | + } | |
| 1325 | + }).Where(x => !string.IsNullOrEmpty(x)).ToList(); | |
| 1326 | + | |
| 1327 | + var consumed = consumedItems.Where(x => | |
| 1328 | + { | |
| 1329 | + try | |
| 1330 | + { | |
| 1331 | + return billingItemIds.Contains(x.BillingItemId?.ToString() ?? ""); | |
| 1332 | + } | |
| 1333 | + catch | |
| 1334 | + { | |
| 1335 | + return false; | |
| 1336 | + } | |
| 1337 | + }).ToList(); | |
| 1338 | + | |
| 1339 | + foreach (var consumedItem in consumed) | |
| 1340 | + { | |
| 1341 | + try | |
| 1342 | + { | |
| 1343 | + billingItem.ConsumedItems.Add(new ItemDetail | |
| 1344 | + { | |
| 1345 | + ItemId = consumedItem.Px?.ToString() ?? "", | |
| 1346 | + ItemName = consumedItem.Pxmc?.ToString() ?? "", | |
| 1347 | + ItemPrice = Convert.ToDecimal(consumedItem.Pxjg ?? 0), | |
| 1348 | + ProjectNumber = Convert.ToDecimal(consumedItem.ProjectNumber ?? 0), | |
| 1349 | + TotalAmount = Convert.ToDecimal(consumedItem.TotalPrice ?? 0) | |
| 1350 | + }); | |
| 1351 | + billingItem.ConsumedItemsTotalAmount += Convert.ToDecimal(consumedItem.TotalPrice ?? 0); | |
| 1352 | + } | |
| 1353 | + catch (Exception ex) | |
| 1354 | + { | |
| 1355 | + _logger.LogWarning(ex, "处理消耗品项时出错"); | |
| 1356 | + } | |
| 1357 | + } | |
| 1358 | + | |
| 1359 | + // 获取退卡品项 | |
| 1360 | + var refunded = refundedItems.Where(x => | |
| 1361 | + { | |
| 1362 | + try | |
| 1363 | + { | |
| 1364 | + return billingItemIds.Contains(x.BillingItemId?.ToString() ?? ""); | |
| 1365 | + } | |
| 1366 | + catch | |
| 1367 | + { | |
| 1368 | + return false; | |
| 1369 | + } | |
| 1370 | + }).ToList(); | |
| 1371 | + | |
| 1372 | + foreach (var refundedItem in refunded) | |
| 1373 | + { | |
| 1374 | + try | |
| 1375 | + { | |
| 1376 | + billingItem.RefundedItems.Add(new ItemDetail | |
| 1377 | + { | |
| 1378 | + ItemId = refundedItem.Px?.ToString() ?? "", | |
| 1379 | + ItemName = refundedItem.Pxmc?.ToString() ?? "", | |
| 1380 | + ItemPrice = Convert.ToDecimal(refundedItem.Pxjg ?? 0), | |
| 1381 | + ProjectNumber = Convert.ToDecimal(refundedItem.ProjectNumber ?? 0), | |
| 1382 | + TotalAmount = Convert.ToDecimal(refundedItem.Tkje ?? 0) | |
| 1383 | + }); | |
| 1384 | + billingItem.RefundedItemsTotalAmount += Convert.ToDecimal(refundedItem.Tkje ?? 0); | |
| 1385 | + } | |
| 1386 | + catch (Exception ex) | |
| 1387 | + { | |
| 1388 | + _logger.LogWarning(ex, "处理退卡品项时出错"); | |
| 1389 | + } | |
| 1390 | + } | |
| 1391 | + | |
| 1392 | + // 获取储扣品项 | |
| 1393 | + var deducted = deductedItems.Where(x => | |
| 1394 | + { | |
| 1395 | + try | |
| 1396 | + { | |
| 1397 | + return x.BillingId?.ToString() == billing.Id; | |
| 1398 | + } | |
| 1399 | + catch | |
| 1400 | + { | |
| 1401 | + return false; | |
| 1402 | + } | |
| 1403 | + }).ToList(); | |
| 1404 | + | |
| 1405 | + foreach (var deductedItem in deducted) | |
| 1406 | + { | |
| 1407 | + try | |
| 1408 | + { | |
| 1409 | + billingItem.DeductedItems.Add(new ItemDetail | |
| 1410 | + { | |
| 1411 | + ItemId = deductedItem.ItemId?.ToString() ?? "", | |
| 1412 | + ItemName = deductedItem.ItemName?.ToString() ?? "", | |
| 1413 | + ItemPrice = Convert.ToDecimal(deductedItem.UnitPrice ?? 0), | |
| 1414 | + ProjectNumber = Convert.ToDecimal(deductedItem.ProjectNumber ?? 0), | |
| 1415 | + TotalAmount = Convert.ToDecimal(deductedItem.Amount ?? 0) | |
| 1416 | + }); | |
| 1417 | + billingItem.DeductedItemsTotalAmount += Convert.ToDecimal(deductedItem.Amount ?? 0); | |
| 1418 | + } | |
| 1419 | + catch (Exception ex) | |
| 1420 | + { | |
| 1421 | + _logger.LogWarning(ex, "处理储扣品项时出错"); | |
| 1422 | + } | |
| 1423 | + } | |
| 1424 | + | |
| 1425 | + memberOutput.BillingItems.Add(billingItem); | |
| 1426 | + } | |
| 1427 | + | |
| 1428 | + result.Add(memberOutput); | |
| 1429 | + } | |
| 1430 | + | |
| 1431 | + return PageResult<MemberItemInfoOutput>.SqlSugarPageResult(new SqlSugarPagedList<MemberItemInfoOutput> | |
| 1432 | + { | |
| 1433 | + list = result, | |
| 1434 | + pagination = new PagedModel | |
| 1435 | + { | |
| 1436 | + PageIndex = input.currentPage, | |
| 1437 | + PageSize = input.pageSize, | |
| 1438 | + Total = totalCount | |
| 1439 | + } | |
| 1440 | + }); | |
| 1441 | + } | |
| 1442 | + catch (Exception ex) | |
| 1443 | + { | |
| 1444 | + _logger.LogError(ex, "查询会员品项信息失败,异常详情:{ExceptionDetail}", ex.ToString()); | |
| 1445 | + throw NCCException.Oh(ErrorCode.COM1005, $"查询会员品项信息失败: {ex.Message}"); | |
| 1446 | + } | |
| 1447 | + } | |
| 1448 | + #endregion | |
| 1449 | + | |
| 779 | 1450 | } |
| 780 | 1451 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
| ... | ... | @@ -971,6 +971,8 @@ namespace NCC.Extend.LqXhHyhk |
| 971 | 971 | { |
| 972 | 972 | memberInfo.Khlx = MemberTypeEnum.新客.GetHashCode().ToString(); |
| 973 | 973 | } |
| 974 | + //保存会员信息 | |
| 975 | + await _db.Updateable(memberInfo).ExecuteCommandAsync(); | |
| 974 | 976 | // 新增会员耗卡记录 |
| 975 | 977 | var newEntity = await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteReturnEntityAsync(); |
| 976 | 978 | // 收集所有需要插入的实体,然后批量插入 |
| ... | ... | @@ -1265,6 +1267,15 @@ namespace NCC.Extend.LqXhHyhk |
| 1265 | 1267 | //更新会员耗卡记录 |
| 1266 | 1268 | await _db.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); |
| 1267 | 1269 | |
| 1270 | + var memberInfo = await _db.Queryable<LqKhxxEntity>().Where(w => w.Id == entity.Hy).FirstAsync(); | |
| 1271 | + //如果会员类型是线索,那么就更新为新客 | |
| 1272 | + if (memberInfo.Khlx == MemberTypeEnum.线索.GetHashCode().ToString()) | |
| 1273 | + { | |
| 1274 | + memberInfo.Khlx = MemberTypeEnum.新客.GetHashCode().ToString(); | |
| 1275 | + } | |
| 1276 | + //保存会员信息 | |
| 1277 | + await _db.Updateable(memberInfo).ExecuteCommandAsync(); | |
| 1278 | + | |
| 1268 | 1279 | //清空原有数据 |
| 1269 | 1280 | await _db.Deleteable<LqXhJksyjEntity>().Where(u => u.Glkdbh == id).ExecuteCommandAsync(); |
| 1270 | 1281 | await _db.Deleteable<LqXhKjbsyjEntity>().Where(u => u.Glkdbh == id).ExecuteCommandAsync(); | ... | ... |
sql/更新潜客为新客.sql
0 → 100644
| 1 | +-- ============================================ | |
| 2 | +-- 更新会员类型:将存在耗卡记录的潜客(0)更新为新客(1) | |
| 3 | +-- ============================================ | |
| 4 | +-- | |
| 5 | +-- 功能说明: | |
| 6 | +-- 1. 查找会员类型为 0(潜客/线索)的会员 | |
| 7 | +-- 2. 如果该会员存在有效的耗卡记录(lq_xh_hyhk 表中有记录且 F_IsEffective = 1) | |
| 8 | +-- 3. 将该会员的类型更新为 1(新客) | |
| 9 | +-- | |
| 10 | +-- 执行前建议: | |
| 11 | +-- 1. 先执行查询语句查看会更新多少条记录 | |
| 12 | +-- 2. 确认无误后再执行更新语句 | |
| 13 | +-- ============================================ | |
| 14 | + | |
| 15 | +-- 1. 查询语句:查看将要更新的会员数量和信息 | |
| 16 | +SELECT | |
| 17 | + kh.F_Id AS 会员ID, | |
| 18 | + kh.khmc AS 会员名称, | |
| 19 | + kh.sjh AS 手机号, | |
| 20 | + kh.khlx AS 当前类型, | |
| 21 | + COUNT(hyhk.F_Id) AS 耗卡记录数 | |
| 22 | +FROM lq_khxx kh | |
| 23 | +INNER JOIN lq_xh_hyhk hyhk ON kh.F_Id = hyhk.hy | |
| 24 | +WHERE kh.khlx = '0' -- 会员类型为 0(潜客/线索) | |
| 25 | + AND hyhk.F_IsEffective = 1 -- 耗卡记录有效 | |
| 26 | +GROUP BY kh.F_Id, kh.khmc, kh.sjh, kh.khlx; | |
| 27 | + | |
| 28 | +-- 2. 更新语句:将存在耗卡记录的潜客更新为新客 | |
| 29 | +UPDATE lq_khxx kh | |
| 30 | +SET kh.khlx = '1' -- 更新为新客(1) | |
| 31 | +WHERE kh.khlx = '0' -- 会员类型为 0(潜客/线索) | |
| 32 | + AND EXISTS ( | |
| 33 | + -- 确保至少有一条有效的耗卡记录 | |
| 34 | + SELECT 1 | |
| 35 | + FROM lq_xh_hyhk hyhk | |
| 36 | + WHERE hyhk.hy = kh.F_Id | |
| 37 | + AND hyhk.F_IsEffective = 1 | |
| 38 | + LIMIT 1 | |
| 39 | + ); | |
| 40 | + | |
| 41 | +-- 3. 验证语句:查看更新后的结果 | |
| 42 | +SELECT | |
| 43 | + kh.F_Id AS 会员ID, | |
| 44 | + kh.khmc AS 会员名称, | |
| 45 | + kh.sjh AS 手机号, | |
| 46 | + kh.khlx AS 更新后类型, | |
| 47 | + COUNT(hyhk.F_Id) AS 耗卡记录数 | |
| 48 | +FROM lq_khxx kh | |
| 49 | +INNER JOIN lq_xh_hyhk hyhk ON kh.F_Id = hyhk.hy | |
| 50 | +WHERE kh.khlx = '1' -- 会员类型为 1(新客) | |
| 51 | + AND hyhk.F_IsEffective = 1 -- 耗卡记录有效 | |
| 52 | +GROUP BY kh.F_Id, kh.khmc, kh.sjh, kh.khlx | |
| 53 | +HAVING COUNT(hyhk.F_Id) > 0; | |
| 54 | + | ... | ... |