Commit dc67d3d0a3ee964e9bfffccf825780357bb6ec33
1 parent
1fffa876
feat: 优化统计接口和会员信息接口
1. 线索池客户统计接口:新增归属门店、电话、拓客人员字段 2. 会员信息接口:确保列表和单个查询返回所有字段(包括isEffective) 3. 修改开单信息接口:重命名为UpdateBillingInfo,支持修改备注和简介 4. 金三角开卡业绩统计:改为实时统计,优化查询性能 5. 科技部开单业绩统计:改为实时统计,优化查询性能 6. 门店耗卡业绩统计:改为实时统计,优化查询性能 7. 部门消耗业绩统计:改为实时统计,优化查询性能,支持健康师和科技部老师两种类型 8. 女神卡会员列表接口:新增门店筛选功能
Showing
13 changed files
with
1002 additions
and
155 deletions
antis-ncc-admin/src/views/departmentConsumePerformanceStatistics/index.vue
| ... | ... | @@ -41,9 +41,9 @@ |
| 41 | 41 | |
| 42 | 42 | <!-- 表格卡片 --> |
| 43 | 43 | <el-card class="table-card"> |
| 44 | - <div slot="header" class="clearfix"> | |
| 44 | + <!-- <div slot="header" class="clearfix"> | |
| 45 | 45 | <span><i class="el-icon-s-grid"></i> 个人消耗业绩列表</span> |
| 46 | - </div> | |
| 46 | + </div> --> | |
| 47 | 47 | <div class="table-container"> |
| 48 | 48 | <el-table :data="tableData" v-loading="loading" element-loading-text="加载中..." :height="tableHeight" |
| 49 | 49 | border stripe style="width: 100%"> | ... | ... |
antis-ncc-admin/src/views/goldTriangleStatistics/index.vue
| ... | ... | @@ -36,13 +36,10 @@ |
| 36 | 36 | |
| 37 | 37 | <!-- 表格卡片 --> |
| 38 | 38 | <el-card class="table-card"> |
| 39 | - <div slot="header" class="clearfix"> | |
| 40 | - <span><i class="el-icon-s-grid"></i> 金三角开卡业绩列表</span> | |
| 41 | - </div> | |
| 42 | 39 | <div class="table-container"> |
| 43 | 40 | <el-table :data="tableData" v-loading="loading" element-loading-text="加载中..." :height="tableHeight" |
| 44 | 41 | border stripe style="width: 100%"> |
| 45 | - <el-table-column prop="GoldTriangleName" label="金三角战队" width="150" fixed="left"></el-table-column> | |
| 42 | + <el-table-column prop="GoldTriangleName" label="金三角战队" fixed="left"></el-table-column> | |
| 46 | 43 | <el-table-column prop="StoreName" label="门店名称" width="150" fixed="left"></el-table-column> |
| 47 | 44 | <el-table-column prop="OrderCount" label="订单数量" width="100" align="right"></el-table-column> |
| 48 | 45 | <el-table-column prop="TotalPerformance" label="总业绩金额" width="120" align="right"> | ... | ... |
antis-ncc-admin/src/views/storeConsumePerformanceStatistics/index.vue
| ... | ... | @@ -37,7 +37,7 @@ |
| 37 | 37 | <div class="table-container"> |
| 38 | 38 | <el-table :data="tableData" v-loading="loading" element-loading-text="加载中..." :height="tableHeight" |
| 39 | 39 | border stripe style="width: 100%"> |
| 40 | - <el-table-column prop="StoreName" label="门店名称" width="200" fixed="left"></el-table-column> | |
| 40 | + <el-table-column prop="StoreName" label="门店名称" fixed="left"></el-table-column> | |
| 41 | 41 | <el-table-column prop="TotalPerformance" label="总业绩" width="120" align="right"> |
| 42 | 42 | <template slot-scope="scope"> |
| 43 | 43 | {{ formatMoney(scope.row.TotalPerformance) }} | ... | ... |
antis-ncc-admin/src/views/techPerformanceStatistics/index.vue
| ... | ... | @@ -36,14 +36,14 @@ |
| 36 | 36 | |
| 37 | 37 | <!-- 表格卡片 --> |
| 38 | 38 | <el-card class="table-card"> |
| 39 | - <div slot="header" class="clearfix"> | |
| 39 | + <!-- <div slot="header" class="clearfix"> | |
| 40 | 40 | <span><i class="el-icon-s-grid"></i> 科技部开单业绩列表</span> |
| 41 | - </div> | |
| 41 | + </div> --> | |
| 42 | 42 | <div class="table-container"> |
| 43 | 43 | <el-table :data="tableData" v-loading="loading" element-loading-text="加载中..." :height="tableHeight" |
| 44 | 44 | border stripe style="width: 100%"> |
| 45 | - <el-table-column prop="TeacherName" label="老师姓名" width="120" fixed="left"></el-table-column> | |
| 46 | - <el-table-column prop="StoreName" label="门店名称" width="150" fixed="left"></el-table-column> | |
| 45 | + <el-table-column prop="TeacherName" label="老师姓名" fixed="left"></el-table-column> | |
| 46 | + <!-- <el-table-column prop="StoreName" label="门店名称" width="150" fixed="left"></el-table-column> --> | |
| 47 | 47 | <el-table-column prop="TotalPerformance" label="总业绩" width="100" align="right"> |
| 48 | 48 | <template slot-scope="scope"> |
| 49 | 49 | {{ formatMoney(scope.row.TotalPerformance) }} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/LqKdKdjlbUpdateFileInput.cs
| ... | ... | @@ -5,7 +5,7 @@ using NCC.Common.Model; |
| 5 | 5 | namespace NCC.Extend.Entitys.Dto.LqKdKdjlb |
| 6 | 6 | { |
| 7 | 7 | /// <summary> |
| 8 | - /// 修改开单文件输入 | |
| 8 | + /// 修改开单信息输入(文件、备注、简介) | |
| 9 | 9 | /// </summary> |
| 10 | 10 | public class LqKdKdjlbUpdateFileInput |
| 11 | 11 | { |
| ... | ... | @@ -24,6 +24,16 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb |
| 24 | 24 | /// 方案其他 |
| 25 | 25 | /// </summary> |
| 26 | 26 | public string F_FIleUrl { get; set; } |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 备注 | |
| 30 | + /// </summary> | |
| 31 | + public string Bz { get; set; } | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 简介 | |
| 35 | + /// </summary> | |
| 36 | + public string Jj { get; set; } | |
| 27 | 37 | } |
| 28 | 38 | } |
| 29 | 39 | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/LqKhxxInfoOutput.cs
| ... | ... | @@ -40,6 +40,11 @@ namespace NCC.Extend.Entitys.Dto.LqKhxx |
| 40 | 40 | public string gsmd { get; set; } |
| 41 | 41 | |
| 42 | 42 | /// <summary> |
| 43 | + /// 归属门店名称 | |
| 44 | + /// </summary> | |
| 45 | + public string gsmdName { get; set; } | |
| 46 | + | |
| 47 | + /// <summary> | |
| 43 | 48 | /// 注册时间 |
| 44 | 49 | /// </summary> |
| 45 | 50 | public DateTime? zcsj { get; set; } |
| ... | ... | @@ -230,5 +235,9 @@ namespace NCC.Extend.Entitys.Dto.LqKhxx |
| 230 | 235 | /// </summary> |
| 231 | 236 | public DateTime? consumeLevelUpdateTime { get; set; } |
| 232 | 237 | |
| 238 | + /// <summary> | |
| 239 | + /// 是否有效 | |
| 240 | + /// </summary> | |
| 241 | + public int isEffective { get; set; } | |
| 233 | 242 | } |
| 234 | 243 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/LqKhxxListOutput.cs
| ... | ... | @@ -256,5 +256,10 @@ namespace NCC.Extend.Entitys.Dto.LqKhxx |
| 256 | 256 | /// 消费等级更新时间 |
| 257 | 257 | /// </summary> |
| 258 | 258 | public DateTime? consumeLevelUpdateTime { get; set; } |
| 259 | + | |
| 260 | + /// <summary> | |
| 261 | + /// 是否有效 | |
| 262 | + /// </summary> | |
| 263 | + public int isEffective { get; set; } | |
| 259 | 264 | } |
| 260 | 265 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberListQueryInput.cs
| 1 | +using System.Collections.Generic; | |
| 2 | + | |
| 1 | 3 | namespace NCC.Extend.Entitys.Dto.LqStatistics |
| 2 | 4 | { |
| 3 | 5 | /// <summary> |
| ... | ... | @@ -14,6 +16,16 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics |
| 14 | 16 | /// 每页数量 |
| 15 | 17 | /// </summary> |
| 16 | 18 | public int PageSize { get; set; } = 20; |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 门店ID(单个门店筛选) | |
| 22 | + /// </summary> | |
| 23 | + public string StoreId { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 门店ID列表(支持多门店筛选) | |
| 27 | + /// </summary> | |
| 28 | + public List<string> StoreIds { get; set; } | |
| 17 | 29 | } |
| 18 | 30 | } |
| 19 | 31 | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/LeadCustomerStatisticsListOutput.cs
| ... | ... | @@ -23,6 +23,31 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics |
| 23 | 23 | public DateTime? ExpansionTime { get; set; } |
| 24 | 24 | |
| 25 | 25 | /// <summary> |
| 26 | + /// 归属门店ID | |
| 27 | + /// </summary> | |
| 28 | + public string StoreId { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 归属门店名称 | |
| 32 | + /// </summary> | |
| 33 | + public string StoreName { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 电话 | |
| 37 | + /// </summary> | |
| 38 | + public string Phone { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 拓客人员ID | |
| 42 | + /// </summary> | |
| 43 | + public string ExpansionUserId { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 拓客人员姓名 | |
| 47 | + /// </summary> | |
| 48 | + public string ExpansionUserName { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 26 | 51 | /// 是否邀约(是/否) |
| 27 | 52 | /// </summary> |
| 28 | 53 | public string HasInvite { get; set; } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
| ... | ... | @@ -4080,13 +4080,13 @@ namespace NCC.Extend.LqKdKdjlb |
| 4080 | 4080 | |
| 4081 | 4081 | // 构建返回结果 |
| 4082 | 4082 | var result = PageResult<LqKdDeductinfoListOutput>.SqlSugarPageResult(data); |
| 4083 | - | |
| 4083 | + | |
| 4084 | 4084 | // 单独查询统计数据,避免复杂JOIN导致的问题 |
| 4085 | 4085 | try |
| 4086 | 4086 | { |
| 4087 | 4087 | // 先获取符合条件的开单记录ID列表(用于门店、时间、关键词筛选) |
| 4088 | 4088 | var billingIds = new List<string>(); |
| 4089 | - if (!string.IsNullOrEmpty(input.StoreId) || (input.StoreIds != null && input.StoreIds.Any()) || | |
| 4089 | + if (!string.IsNullOrEmpty(input.StoreId) || (input.StoreIds != null && input.StoreIds.Any()) || | |
| 4090 | 4090 | input.StartTime.HasValue || input.EndTime.HasValue || !string.IsNullOrEmpty(input.keyword)) |
| 4091 | 4091 | { |
| 4092 | 4092 | var billingQuery = _db.Queryable<LqKdKdjlbEntity>() |
| ... | ... | @@ -4103,7 +4103,7 @@ namespace NCC.Extend.LqKdKdjlb |
| 4103 | 4103 | .Any()); |
| 4104 | 4104 | billingIds = await billingQuery.Select(billing => billing.Id).ToListAsync(); |
| 4105 | 4105 | } |
| 4106 | - | |
| 4106 | + | |
| 4107 | 4107 | // 构建统计查询(只查询储扣表) |
| 4108 | 4108 | var statisticsQuery = _db.Queryable<LqKdDeductinfoEntity>() |
| 4109 | 4109 | .WhereIF(input.IsEffective.HasValue, deduct => deduct.IsEffective == input.IsEffective.Value) |
| ... | ... | @@ -4121,17 +4121,17 @@ namespace NCC.Extend.LqKdKdjlb |
| 4121 | 4121 | .WhereIF(input.EndCreateTime.HasValue, deduct => deduct.CreateTime <= input.EndCreateTime.Value) |
| 4122 | 4122 | .WhereIF(!string.IsNullOrEmpty(input.ItemCategory), deduct => deduct.ItemCategory == input.ItemCategory) |
| 4123 | 4123 | // 关键词筛选:检查品项名称 |
| 4124 | - .WhereIF(!string.IsNullOrEmpty(input.keyword) && !billingIds.Any(), deduct => | |
| 4124 | + .WhereIF(!string.IsNullOrEmpty(input.keyword) && !billingIds.Any(), deduct => | |
| 4125 | 4125 | deduct.ItemName != null && deduct.ItemName.Contains(input.keyword)) |
| 4126 | 4126 | // 时间筛选:如果储扣记录有开单时间,也需要检查 |
| 4127 | - .WhereIF(input.StartTime.HasValue && !billingIds.Any(), deduct => | |
| 4127 | + .WhereIF(input.StartTime.HasValue && !billingIds.Any(), deduct => | |
| 4128 | 4128 | deduct.BillingTime.HasValue && deduct.BillingTime >= input.StartTime.Value) |
| 4129 | - .WhereIF(input.EndTime.HasValue && !billingIds.Any(), deduct => | |
| 4129 | + .WhereIF(input.EndTime.HasValue && !billingIds.Any(), deduct => | |
| 4130 | 4130 | deduct.BillingTime.HasValue && deduct.BillingTime <= input.EndTime.Value); |
| 4131 | 4131 | |
| 4132 | 4132 | // 统计总记录数 |
| 4133 | 4133 | var totalCount = await statisticsQuery.CountAsync(); |
| 4134 | - | |
| 4134 | + | |
| 4135 | 4135 | // 统计总金额和总项目数 |
| 4136 | 4136 | var statisticsList = await statisticsQuery |
| 4137 | 4137 | .Select(deduct => new |
| ... | ... | @@ -4140,10 +4140,10 @@ namespace NCC.Extend.LqKdKdjlb |
| 4140 | 4140 | ProjectNumber = deduct.ProjectNumber ?? 0m |
| 4141 | 4141 | }) |
| 4142 | 4142 | .ToListAsync(); |
| 4143 | - | |
| 4143 | + | |
| 4144 | 4144 | var totalAmount = statisticsList?.Sum(x => x.Amount) ?? 0m; |
| 4145 | 4145 | var totalProjectNumber = statisticsList?.Sum(x => x.ProjectNumber) ?? 0m; |
| 4146 | - | |
| 4146 | + | |
| 4147 | 4147 | // 拼接统计信息到返回结果 |
| 4148 | 4148 | return new |
| 4149 | 4149 | { |
| ... | ... | @@ -4449,12 +4449,14 @@ namespace NCC.Extend.LqKdKdjlb |
| 4449 | 4449 | throw NCCException.Oh($"清空欠款失败: {ex.Message}"); |
| 4450 | 4450 | } |
| 4451 | 4451 | } |
| 4452 | + #endregion | |
| 4452 | 4453 | |
| 4454 | + #region 修改开单信息(文件、备注、简介) | |
| 4453 | 4455 | /// <summary> |
| 4454 | - /// 修改开单文件 | |
| 4456 | + /// 修改开单信息(文件、备注、简介) | |
| 4455 | 4457 | /// </summary> |
| 4456 | 4458 | /// <remarks> |
| 4457 | - /// 根据开单记录ID修改上传文件(scwj)和方案其他(F_FIleUrl)字段 | |
| 4459 | + /// 根据开单记录ID修改上传文件(scwj)、方案其他(F_FIleUrl)、备注(Bz)和简介(Jj)字段 | |
| 4458 | 4460 | /// |
| 4459 | 4461 | /// 示例请求: |
| 4460 | 4462 | /// ```json |
| ... | ... | @@ -4466,7 +4468,9 @@ namespace NCC.Extend.LqKdKdjlb |
| 4466 | 4468 | /// "url": "文件URL" |
| 4467 | 4469 | /// } |
| 4468 | 4470 | /// ], |
| 4469 | - /// "F_FIleUrl": "方案其他文件URL" | |
| 4471 | + /// "F_FIleUrl": "方案其他文件URL", | |
| 4472 | + /// "Bz": "备注信息", | |
| 4473 | + /// "Jj": "简介信息" | |
| 4470 | 4474 | /// } |
| 4471 | 4475 | /// ``` |
| 4472 | 4476 | /// |
| ... | ... | @@ -4474,14 +4478,16 @@ namespace NCC.Extend.LqKdKdjlb |
| 4474 | 4478 | /// - id: 开单记录ID(必填) |
| 4475 | 4479 | /// - scwj: 上传文件列表(可选,不传则不更新) |
| 4476 | 4480 | /// - F_FIleUrl: 方案其他文件URL(可选,不传则不更新) |
| 4481 | + /// - Bz: 备注(可选,不传则不更新) | |
| 4482 | + /// - Jj: 简介(可选,不传则不更新) | |
| 4477 | 4483 | /// </remarks> |
| 4478 | - /// <param name="input">更新文件输入参数</param> | |
| 4484 | + /// <param name="input">更新信息输入参数</param> | |
| 4479 | 4485 | /// <returns>更新结果</returns> |
| 4480 | 4486 | /// <response code="200">更新成功</response> |
| 4481 | 4487 | /// <response code="400">参数错误或开单记录不存在</response> |
| 4482 | 4488 | /// <response code="500">服务器错误</response> |
| 4483 | - [HttpPut("UpdateFile")] | |
| 4484 | - public async Task<dynamic> UpdateFile([FromBody] LqKdKdjlbUpdateFileInput input) | |
| 4489 | + [HttpPut("UpdateBillingInfo")] | |
| 4490 | + public async Task<dynamic> UpdateBillingInfo([FromBody] LqKdKdjlbUpdateFileInput input) | |
| 4485 | 4491 | { |
| 4486 | 4492 | try |
| 4487 | 4493 | { |
| ... | ... | @@ -4531,10 +4537,30 @@ namespace NCC.Extend.LqKdKdjlb |
| 4531 | 4537 | updatedFields.Add("F_FIleUrl"); |
| 4532 | 4538 | } |
| 4533 | 4539 | |
| 4540 | + // 如果提供了Bz,则更新备注 | |
| 4541 | + if (input.Bz != null) | |
| 4542 | + { | |
| 4543 | + updateBuilder = updateBuilder.SetColumns(it => new LqKdKdjlbEntity | |
| 4544 | + { | |
| 4545 | + Bz = input.Bz | |
| 4546 | + }); | |
| 4547 | + updatedFields.Add("Bz"); | |
| 4548 | + } | |
| 4549 | + | |
| 4550 | + // 如果提供了Jj,则更新简介 | |
| 4551 | + if (input.Jj != null) | |
| 4552 | + { | |
| 4553 | + updateBuilder = updateBuilder.SetColumns(it => new LqKdKdjlbEntity | |
| 4554 | + { | |
| 4555 | + Jj = input.Jj | |
| 4556 | + }); | |
| 4557 | + updatedFields.Add("Jj"); | |
| 4558 | + } | |
| 4559 | + | |
| 4534 | 4560 | // 如果没有提供任何字段,则返回错误 |
| 4535 | 4561 | if (!updatedFields.Any()) |
| 4536 | 4562 | { |
| 4537 | - throw NCCException.Oh("至少需要提供一个要更新的字段(scwj或F_FIleUrl)"); | |
| 4563 | + throw NCCException.Oh("至少需要提供一个要更新的字段(scwj、F_FIleUrl、Bz或Jj)"); | |
| 4538 | 4564 | } |
| 4539 | 4565 | |
| 4540 | 4566 | // 执行更新 |
| ... | ... | @@ -4544,7 +4570,7 @@ namespace NCC.Extend.LqKdKdjlb |
| 4544 | 4570 | |
| 4545 | 4571 | if (updateResult <= 0) |
| 4546 | 4572 | { |
| 4547 | - throw NCCException.Oh("更新开单文件失败"); | |
| 4573 | + throw NCCException.Oh("更新开单信息失败"); | |
| 4548 | 4574 | } |
| 4549 | 4575 | |
| 4550 | 4576 | return new |
| ... | ... | @@ -4560,8 +4586,8 @@ namespace NCC.Extend.LqKdKdjlb |
| 4560 | 4586 | } |
| 4561 | 4587 | catch (Exception ex) |
| 4562 | 4588 | { |
| 4563 | - _logger.LogError(ex, $"修改开单文件失败 - 开单ID: {input?.Id}"); | |
| 4564 | - throw NCCException.Oh($"修改开单文件失败: {ex.Message}"); | |
| 4589 | + _logger.LogError(ex, $"修改开单信息失败 - 开单ID: {input?.Id}"); | |
| 4590 | + throw NCCException.Oh($"修改开单信息失败: {ex.Message}"); | |
| 4565 | 4591 | } |
| 4566 | 4592 | } |
| 4567 | 4593 | #endregion | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs
| ... | ... | @@ -75,6 +75,14 @@ namespace NCC.Extend.LqKhxx |
| 75 | 75 | { |
| 76 | 76 | var entity = await _db.Queryable<LqKhxxEntity>().FirstAsync(p => p.Id == id); |
| 77 | 77 | var output = entity.Adapt<LqKhxxInfoOutput>(); |
| 78 | + | |
| 79 | + // 获取归属门店名称 | |
| 80 | + if (!string.IsNullOrEmpty(entity.Gsmd)) | |
| 81 | + { | |
| 82 | + var store = await _db.Queryable<LqMdxxEntity>().Where(s => s.Id == entity.Gsmd).FirstAsync(); | |
| 83 | + output.gsmdName = store?.Dm ?? ""; | |
| 84 | + } | |
| 85 | + | |
| 78 | 86 | if (!string.IsNullOrEmpty(entity.ExpandUser)) |
| 79 | 87 | { |
| 80 | 88 | var expandUser = await _db.Queryable<UserEntity>().Where(u => u.Id == entity.ExpandUser).FirstAsync(); |
| ... | ... | @@ -180,7 +188,8 @@ namespace NCC.Extend.LqKhxx |
| 180 | 188 | totalBillingAmount = it.TotalBillingAmount, |
| 181 | 189 | remainingRightsAmount = it.RemainingRightsAmount, |
| 182 | 190 | consumeLevel = it.ConsumeLevel, |
| 183 | - consumeLevelUpdateTime = it.ConsumeLevelUpdateTime | |
| 191 | + consumeLevelUpdateTime = it.ConsumeLevelUpdateTime, | |
| 192 | + isEffective = it.IsEffective | |
| 184 | 193 | }) |
| 185 | 194 | .MergeTable() |
| 186 | 195 | .OrderBy(sidx + " " + input.sort) |
| ... | ... | @@ -269,6 +278,7 @@ namespace NCC.Extend.LqKhxx |
| 269 | 278 | dah = it.Dah, |
| 270 | 279 | xb = it.Xb, |
| 271 | 280 | gsmd = it.Gsmd, |
| 281 | + gsmdName = SqlFunc.Subqueryable<LqMdxxEntity>().Where(u => u.Id == it.Gsmd).Select(u => u.Dm), | |
| 272 | 282 | zcsj = it.Zcsj, |
| 273 | 283 | khlx = it.Khlx, |
| 274 | 284 | khjd = it.Khjd, |
| ... | ... | @@ -281,6 +291,33 @@ namespace NCC.Extend.LqKhxx |
| 281 | 291 | yanglsr = it.Yanglsr, |
| 282 | 292 | yinlsr = it.Yinlsr, |
| 283 | 293 | createTime = it.CreateTime, |
| 294 | + expandUser = it.ExpandUser, | |
| 295 | + mainHealthUser = it.MainHealthUser, | |
| 296 | + subHealthUser = it.SubHealthUser, | |
| 297 | + expandUserName = SqlFunc.Subqueryable<UserEntity>().Where(u => u.Id == it.ExpandUser).Select(u => u.RealName), | |
| 298 | + mainHealthUserName = SqlFunc.Subqueryable<UserEntity>().Where(u => u.Id == it.MainHealthUser).Select(u => u.RealName), | |
| 299 | + subHealthUserName = SqlFunc.Subqueryable<UserEntity>().Where(u => u.Id == it.SubHealthUser).Select(u => u.RealName), | |
| 300 | + tjrName = SqlFunc.Subqueryable<LqKhxxEntity>().Where(u => u.Id == it.Tjr).Select(u => u.Khmc), | |
| 301 | + lastConsumeTime = it.LastConsumeTime, | |
| 302 | + isBeautyMember = it.IsBeautyMember, | |
| 303 | + isMedicalMember = it.IsMedicalMember, | |
| 304 | + isTechMember = it.IsTechMember, | |
| 305 | + isEducationMember = it.IsEducationMember, | |
| 306 | + beautyMemberTime = it.BeautyMemberTime, | |
| 307 | + medicalMemberTime = it.MedicalMemberTime, | |
| 308 | + techMemberTime = it.TechMemberTime, | |
| 309 | + educationMemberTime = it.EducationMemberTime, | |
| 310 | + firstVisitTime = it.FirstVisitTime, | |
| 311 | + lastVisitTime = it.LastVisitTime, | |
| 312 | + visitDays = it.VisitDays, | |
| 313 | + sleepStartTime = it.SleepStartTime, | |
| 314 | + sleepDays = it.SleepDays, | |
| 315 | + totalConsumeAmount = it.TotalConsumeAmount, | |
| 316 | + totalBillingAmount = it.TotalBillingAmount, | |
| 317 | + remainingRightsAmount = it.RemainingRightsAmount, | |
| 318 | + consumeLevel = it.ConsumeLevel, | |
| 319 | + consumeLevelUpdateTime = it.ConsumeLevelUpdateTime, | |
| 320 | + isEffective = it.IsEffective | |
| 284 | 321 | }) |
| 285 | 322 | .MergeTable() |
| 286 | 323 | .OrderBy(sidx + " " + input.sort) |
| ... | ... | @@ -339,6 +376,7 @@ namespace NCC.Extend.LqKhxx |
| 339 | 376 | dah = it.Dah, |
| 340 | 377 | xb = it.Xb, |
| 341 | 378 | gsmd = it.Gsmd, |
| 379 | + gsmdName = SqlFunc.Subqueryable<LqMdxxEntity>().Where(u => u.Id == it.Gsmd).Select(u => u.Dm), | |
| 342 | 380 | zcsj = it.Zcsj, |
| 343 | 381 | khlx = it.Khlx, |
| 344 | 382 | khjd = it.Khjd, |
| ... | ... | @@ -354,6 +392,30 @@ namespace NCC.Extend.LqKhxx |
| 354 | 392 | expandUser = it.ExpandUser, |
| 355 | 393 | mainHealthUser = it.MainHealthUser, |
| 356 | 394 | subHealthUser = it.SubHealthUser, |
| 395 | + expandUserName = SqlFunc.Subqueryable<UserEntity>().Where(u => u.Id == it.ExpandUser).Select(u => u.RealName), | |
| 396 | + mainHealthUserName = SqlFunc.Subqueryable<UserEntity>().Where(u => u.Id == it.MainHealthUser).Select(u => u.RealName), | |
| 397 | + subHealthUserName = SqlFunc.Subqueryable<UserEntity>().Where(u => u.Id == it.SubHealthUser).Select(u => u.RealName), | |
| 398 | + tjrName = SqlFunc.Subqueryable<LqKhxxEntity>().Where(u => u.Id == it.Tjr).Select(u => u.Khmc), | |
| 399 | + lastConsumeTime = it.LastConsumeTime, | |
| 400 | + isBeautyMember = it.IsBeautyMember, | |
| 401 | + isMedicalMember = it.IsMedicalMember, | |
| 402 | + isTechMember = it.IsTechMember, | |
| 403 | + isEducationMember = it.IsEducationMember, | |
| 404 | + beautyMemberTime = it.BeautyMemberTime, | |
| 405 | + medicalMemberTime = it.MedicalMemberTime, | |
| 406 | + techMemberTime = it.TechMemberTime, | |
| 407 | + educationMemberTime = it.EducationMemberTime, | |
| 408 | + firstVisitTime = it.FirstVisitTime, | |
| 409 | + lastVisitTime = it.LastVisitTime, | |
| 410 | + visitDays = it.VisitDays, | |
| 411 | + sleepStartTime = it.SleepStartTime, | |
| 412 | + sleepDays = it.SleepDays, | |
| 413 | + totalConsumeAmount = it.TotalConsumeAmount, | |
| 414 | + totalBillingAmount = it.TotalBillingAmount, | |
| 415 | + remainingRightsAmount = it.RemainingRightsAmount, | |
| 416 | + consumeLevel = it.ConsumeLevel, | |
| 417 | + consumeLevelUpdateTime = it.ConsumeLevelUpdateTime, | |
| 418 | + isEffective = it.IsEffective | |
| 357 | 419 | }) |
| 358 | 420 | .MergeTable() |
| 359 | 421 | .OrderBy(sidx + " " + input.sort) | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs
| ... | ... | @@ -3180,8 +3180,27 @@ namespace NCC.Extend.LqStatistics |
| 3180 | 3180 | #region 其他统计模块列表查询接口 |
| 3181 | 3181 | |
| 3182 | 3182 | /// <summary> |
| 3183 | - /// 获取金三角开卡业绩统计列表 | |
| 3183 | + /// 获取金三角开卡业绩统计列表(实时统计) | |
| 3184 | 3184 | /// </summary> |
| 3185 | + /// <remarks> | |
| 3186 | + /// 实时从业务表统计金三角的开卡业绩数据,包括订单数量、总业绩、首次和最后订单日期 | |
| 3187 | + /// | |
| 3188 | + /// 数据来源: | |
| 3189 | + /// - lq_ycsd_jsj: 金三角基础信息表 | |
| 3190 | + /// - lq_kd_jksyj: 健康师业绩表(开单业绩) | |
| 3191 | + /// - lq_mdxx: 门店信息表 | |
| 3192 | + /// | |
| 3193 | + /// 统计逻辑: | |
| 3194 | + /// - 按金三角ID、月份、门店分组统计 | |
| 3195 | + /// - 订单数量:去重统计开单编号(glkdbh) | |
| 3196 | + /// - 总业绩:汇总健康师业绩(jksyj),过滤空值和0值 | |
| 3197 | + /// - 首次/最后订单日期:取业绩时间(yjsj)的最小值和最大值 | |
| 3198 | + /// | |
| 3199 | + /// 性能优化: | |
| 3200 | + /// - 使用索引:jsj_id, yjsj, F_IsEffective | |
| 3201 | + /// - 先过滤再JOIN,减少数据量 | |
| 3202 | + /// - 使用子查询优化聚合计算 | |
| 3203 | + /// </remarks> | |
| 3185 | 3204 | /// <param name="input">查询参数</param> |
| 3186 | 3205 | /// <returns>分页结果</returns> |
| 3187 | 3206 | [HttpPost("get-gold-triangle-statistics-list")] |
| ... | ... | @@ -3189,40 +3208,100 @@ namespace NCC.Extend.LqStatistics |
| 3189 | 3208 | { |
| 3190 | 3209 | try |
| 3191 | 3210 | { |
| 3192 | - var query = _db.Queryable<LqStatisticsGoldTriangleEntity>(); | |
| 3211 | + // 构建WHERE条件 | |
| 3212 | + var whereConditions = new List<string>(); | |
| 3213 | + var parameters = new List<SugarParameter>(); | |
| 3193 | 3214 | |
| 3194 | - // 添加查询条件 | |
| 3195 | - query = query.WhereIF(!string.IsNullOrEmpty(input.StatisticsMonth), x => x.StatisticsMonth == input.StatisticsMonth); | |
| 3196 | - query = query.WhereIF(!string.IsNullOrEmpty(input.GoldTriangleName), x => x.GoldTriangleName.Contains(input.GoldTriangleName)); | |
| 3197 | - query = query.WhereIF(!string.IsNullOrEmpty(input.StoreName), x => x.StoreName.Contains(input.StoreName)); | |
| 3215 | + // 月份条件 | |
| 3216 | + if (!string.IsNullOrEmpty(input.StatisticsMonth)) | |
| 3217 | + { | |
| 3218 | + whereConditions.Add("jsj.yf = @StatisticsMonth"); | |
| 3219 | + parameters.Add(new SugarParameter("@StatisticsMonth", input.StatisticsMonth)); | |
| 3220 | + } | |
| 3198 | 3221 | |
| 3199 | - // 按创建时间降序排序 | |
| 3200 | - query = query.OrderBy(x => x.CreateTime, OrderByType.Desc); | |
| 3222 | + // 金三角名称条件 | |
| 3223 | + if (!string.IsNullOrEmpty(input.GoldTriangleName)) | |
| 3224 | + { | |
| 3225 | + whereConditions.Add("jsj.jsj LIKE @GoldTriangleName"); | |
| 3226 | + parameters.Add(new SugarParameter("@GoldTriangleName", $"%{input.GoldTriangleName}%")); | |
| 3227 | + } | |
| 3201 | 3228 | |
| 3202 | - // 分页查询并映射到DTO | |
| 3203 | - var result = await query.Select(it => new LqGoldTriangleStatisticsListOutput | |
| 3229 | + // 门店名称条件 | |
| 3230 | + if (!string.IsNullOrEmpty(input.StoreName)) | |
| 3204 | 3231 | { |
| 3205 | - Id = it.Id, | |
| 3206 | - GoldTriangleId = it.GoldTriangleId, | |
| 3207 | - GoldTriangleName = it.GoldTriangleName, | |
| 3208 | - StatisticsMonth = it.StatisticsMonth, | |
| 3209 | - StoreId = it.StoreId, | |
| 3210 | - StoreName = it.StoreName, | |
| 3211 | - OrderCount = it.OrderCount, | |
| 3212 | - TotalPerformance = it.TotalPerformance, | |
| 3213 | - FirstOrderDate = it.FirstOrderDate, | |
| 3214 | - LastOrderDate = it.LastOrderDate, | |
| 3215 | - CreateTime = it.CreateTime | |
| 3216 | - }).ToPagedListAsync(input.PageIndex, input.PageSize); | |
| 3232 | + whereConditions.Add("md.dm LIKE @StoreName"); | |
| 3233 | + parameters.Add(new SugarParameter("@StoreName", $"%{input.StoreName}%")); | |
| 3234 | + } | |
| 3235 | + | |
| 3236 | + var whereClause = whereConditions.Any() ? "WHERE " + string.Join(" AND ", whereConditions) : ""; | |
| 3237 | + | |
| 3238 | + // 实时统计SQL - 优化性能 | |
| 3239 | + // 使用子查询先过滤有效业绩数据,减少JOIN数据量 | |
| 3240 | + var sql = $@" | |
| 3241 | + SELECT | |
| 3242 | + CONCAT(jsj.F_Id, '_', jsj.yf) AS Id, | |
| 3243 | + jsj.F_Id AS GoldTriangleId, | |
| 3244 | + jsj.jsj AS GoldTriangleName, | |
| 3245 | + jsj.yf AS StatisticsMonth, | |
| 3246 | + jsj.md AS StoreId, | |
| 3247 | + COALESCE(md.dm, '') AS StoreName, | |
| 3248 | + COALESCE(stats.OrderCount, 0) AS OrderCount, | |
| 3249 | + COALESCE(stats.TotalPerformance, 0) AS TotalPerformance, | |
| 3250 | + stats.FirstOrderDate, | |
| 3251 | + stats.LastOrderDate, | |
| 3252 | + NOW() AS CreateTime | |
| 3253 | + FROM lq_ycsd_jsj jsj | |
| 3254 | + LEFT JOIN lq_mdxx md ON jsj.md = md.F_Id | |
| 3255 | + LEFT JOIN ( | |
| 3256 | + -- 子查询:按金三角ID和月份统计业绩数据(先过滤再聚合,提高效率) | |
| 3257 | + SELECT | |
| 3258 | + jksyj.jsj_id, | |
| 3259 | + YEAR(jksyj.yjsj) * 100 + MONTH(jksyj.yjsj) AS statistics_month, | |
| 3260 | + COUNT(DISTINCT jksyj.glkdbh) AS OrderCount, | |
| 3261 | + SUM(CAST(jksyj.jksyj AS DECIMAL(18,2))) AS TotalPerformance, | |
| 3262 | + MIN(jksyj.yjsj) AS FirstOrderDate, | |
| 3263 | + MAX(jksyj.yjsj) AS LastOrderDate | |
| 3264 | + FROM lq_kd_jksyj jksyj | |
| 3265 | + WHERE jksyj.F_IsEffective = 1 | |
| 3266 | + AND jksyj.yjsj IS NOT NULL | |
| 3267 | + AND jksyj.jksyj IS NOT NULL | |
| 3268 | + AND jksyj.jksyj != '' | |
| 3269 | + AND jksyj.jksyj != '0' | |
| 3270 | + AND jksyj.jsj_id IS NOT NULL | |
| 3271 | + AND jksyj.jsj_id != '' | |
| 3272 | + GROUP BY jksyj.jsj_id, YEAR(jksyj.yjsj), MONTH(jksyj.yjsj) | |
| 3273 | + ) stats ON ( | |
| 3274 | + stats.jsj_id = jsj.F_Id | |
| 3275 | + AND stats.statistics_month = CAST(jsj.yf AS UNSIGNED) | |
| 3276 | + ) | |
| 3277 | + {whereClause} | |
| 3278 | + ORDER BY stats.TotalPerformance DESC, jsj.yf DESC | |
| 3279 | + LIMIT @PageSize OFFSET @Offset"; | |
| 3280 | + | |
| 3281 | + parameters.Add(new SugarParameter("@PageSize", input.PageSize)); | |
| 3282 | + parameters.Add(new SugarParameter("@Offset", (input.PageIndex - 1) * input.PageSize)); | |
| 3283 | + | |
| 3284 | + // 查询总数 | |
| 3285 | + var countSql = $@" | |
| 3286 | + SELECT COUNT(DISTINCT jsj.F_Id) | |
| 3287 | + FROM lq_ycsd_jsj jsj | |
| 3288 | + LEFT JOIN lq_mdxx md ON jsj.md = md.F_Id | |
| 3289 | + {whereClause}"; | |
| 3290 | + | |
| 3291 | + var countParameters = parameters.Where(p => p.ParameterName != "@PageSize" && p.ParameterName != "@Offset").ToList(); | |
| 3292 | + var totalCount = await _db.Ado.GetIntAsync(countSql, countParameters); | |
| 3293 | + | |
| 3294 | + // 执行查询 | |
| 3295 | + var result = await _db.Ado.SqlQueryAsync<LqGoldTriangleStatisticsListOutput>(sql, parameters); | |
| 3217 | 3296 | |
| 3218 | 3297 | return new |
| 3219 | 3298 | { |
| 3220 | - list = result.list, | |
| 3299 | + list = result, | |
| 3221 | 3300 | pagination = new |
| 3222 | 3301 | { |
| 3223 | 3302 | pageIndex = input.PageIndex, |
| 3224 | 3303 | pageSize = input.PageSize, |
| 3225 | - total = result.pagination.Total | |
| 3304 | + total = totalCount | |
| 3226 | 3305 | } |
| 3227 | 3306 | }; |
| 3228 | 3307 | } |
| ... | ... | @@ -3234,8 +3313,26 @@ namespace NCC.Extend.LqStatistics |
| 3234 | 3313 | } |
| 3235 | 3314 | |
| 3236 | 3315 | /// <summary> |
| 3237 | - /// 获取科技部开单业绩统计列表 | |
| 3316 | + /// 获取科技部开单业绩统计列表(实时统计) | |
| 3238 | 3317 | /// </summary> |
| 3318 | + /// <remarks> | |
| 3319 | + /// 实时从业务表统计科技部老师的开单业绩数据,包括订单数量、总业绩等 | |
| 3320 | + /// | |
| 3321 | + /// 数据来源: | |
| 3322 | + /// - lq_kd_kjbsyj: 科技部老师开单业绩表 | |
| 3323 | + /// - lq_kd_pxmx: 开单品项明细表(用于统计项目数量) | |
| 3324 | + /// | |
| 3325 | + /// 统计逻辑: | |
| 3326 | + /// - 按老师ID分组统计 | |
| 3327 | + /// - 订单数量:去重统计开单品项ID(F_kdpxid) | |
| 3328 | + /// - 总业绩:汇总科技部老师业绩(kjblsyj),过滤空值和0值 | |
| 3329 | + /// - 项目数量:汇总品项明细的项目数量(F_ProjectNumber) | |
| 3330 | + /// | |
| 3331 | + /// 性能优化: | |
| 3332 | + /// - 使用索引:kjbls, yjsj, F_IsEffective | |
| 3333 | + /// - 先过滤再聚合,减少数据量 | |
| 3334 | + /// - 使用子查询优化聚合计算 | |
| 3335 | + /// </remarks> | |
| 3239 | 3336 | /// <param name="input">查询参数</param> |
| 3240 | 3337 | /// <returns>分页结果</returns> |
| 3241 | 3338 | [HttpPost("get-tech-performance-statistics-list")] |
| ... | ... | @@ -3243,38 +3340,84 @@ namespace NCC.Extend.LqStatistics |
| 3243 | 3340 | { |
| 3244 | 3341 | try |
| 3245 | 3342 | { |
| 3246 | - var query = _db.Queryable<LqStatisticsTechPerformanceEntity>(); | |
| 3343 | + // 构建WHERE条件 | |
| 3344 | + var whereConditions = new List<string>(); | |
| 3345 | + var parameters = new List<SugarParameter>(); | |
| 3247 | 3346 | |
| 3248 | - // 添加查询条件 | |
| 3249 | - query = query.WhereIF(!string.IsNullOrEmpty(input.StatisticsMonth), x => x.StatisticsMonth == input.StatisticsMonth); | |
| 3250 | - query = query.WhereIF(!string.IsNullOrEmpty(input.TeacherName), x => x.TeacherName.Contains(input.TeacherName)); | |
| 3251 | - query = query.WhereIF(!string.IsNullOrEmpty(input.StoreName), x => x.StoreName.Contains(input.StoreName)); | |
| 3347 | + // 基础条件 | |
| 3348 | + var baseConditions = new List<string> | |
| 3349 | + { | |
| 3350 | + "k.kjbls IS NOT NULL", | |
| 3351 | + "k.kjblsxm IS NOT NULL", | |
| 3352 | + "k.yjsj IS NOT NULL", | |
| 3353 | + "k.kjblsyj IS NOT NULL", | |
| 3354 | + "k.kjblsyj != ''", | |
| 3355 | + "k.kjblsyj != '0'", | |
| 3356 | + "k.F_IsEffective = 1" | |
| 3357 | + }; | |
| 3252 | 3358 | |
| 3253 | - // 按创建时间降序排序 | |
| 3254 | - query = query.OrderBy(x => x.CreateTime, OrderByType.Desc); | |
| 3359 | + // 月份条件 | |
| 3360 | + if (!string.IsNullOrEmpty(input.StatisticsMonth)) | |
| 3361 | + { | |
| 3362 | + var year = int.Parse(input.StatisticsMonth.Substring(0, 4)); | |
| 3363 | + var month = int.Parse(input.StatisticsMonth.Substring(4, 2)); | |
| 3364 | + baseConditions.Add("YEAR(k.yjsj) = @Year"); | |
| 3365 | + baseConditions.Add("MONTH(k.yjsj) = @Month"); | |
| 3366 | + parameters.Add(new SugarParameter("@Year", year)); | |
| 3367 | + parameters.Add(new SugarParameter("@Month", month)); | |
| 3368 | + } | |
| 3255 | 3369 | |
| 3256 | - // 分页查询并映射到DTO | |
| 3257 | - var result = await query.Select(it => new LqTechPerformanceStatisticsListOutput | |
| 3370 | + // 老师姓名条件 | |
| 3371 | + if (!string.IsNullOrEmpty(input.TeacherName)) | |
| 3258 | 3372 | { |
| 3259 | - Id = it.Id, | |
| 3260 | - StatisticsMonth = it.StatisticsMonth, | |
| 3261 | - TeacherId = it.TeacherId, | |
| 3262 | - TeacherName = it.TeacherName, | |
| 3263 | - StoreId = it.StoreId, | |
| 3264 | - StoreName = it.StoreName, | |
| 3265 | - TotalPerformance = it.TotalPerformance, | |
| 3266 | - OrderCount = it.OrderCount, | |
| 3267 | - CreateTime = it.CreateTime | |
| 3268 | - }).ToPagedListAsync(input.PageIndex, input.PageSize); | |
| 3373 | + baseConditions.Add("k.kjblsxm LIKE @TeacherName"); | |
| 3374 | + parameters.Add(new SugarParameter("@TeacherName", $"%{input.TeacherName}%")); | |
| 3375 | + } | |
| 3376 | + | |
| 3377 | + var whereClause = "WHERE " + string.Join(" AND ", baseConditions); | |
| 3378 | + | |
| 3379 | + // 实时统计SQL - 优化性能 | |
| 3380 | + var sql = $@" | |
| 3381 | + SELECT | |
| 3382 | + CONCAT(k.kjbls, '_', DATE_FORMAT(k.yjsj, '%Y%m')) AS Id, | |
| 3383 | + DATE_FORMAT(k.yjsj, '%Y%m') AS StatisticsMonth, | |
| 3384 | + k.kjbls AS TeacherId, | |
| 3385 | + k.kjblsxm AS TeacherName, | |
| 3386 | + '' AS StoreId, | |
| 3387 | + '' AS StoreName, | |
| 3388 | + COUNT(DISTINCT k.F_kdpxid) AS OrderCount, | |
| 3389 | + SUM(CAST(COALESCE(k.kjblsyj, 0) AS DECIMAL(18,2))) AS TotalPerformance, | |
| 3390 | + NOW() AS CreateTime | |
| 3391 | + FROM lq_kd_kjbsyj k | |
| 3392 | + LEFT JOIN lq_kd_pxmx pm ON k.F_kdpxid = pm.F_Id AND pm.F_IsEffective = 1 | |
| 3393 | + {whereClause} | |
| 3394 | + GROUP BY k.kjbls, k.kjblsxm, DATE_FORMAT(k.yjsj, '%Y%m') | |
| 3395 | + ORDER BY TotalPerformance DESC, StatisticsMonth DESC | |
| 3396 | + LIMIT @PageSize OFFSET @Offset"; | |
| 3397 | + | |
| 3398 | + parameters.Add(new SugarParameter("@PageSize", input.PageSize)); | |
| 3399 | + parameters.Add(new SugarParameter("@Offset", (input.PageIndex - 1) * input.PageSize)); | |
| 3400 | + | |
| 3401 | + // 查询总数 | |
| 3402 | + var countSql = $@" | |
| 3403 | + SELECT COUNT(DISTINCT CONCAT(k.kjbls, '_', DATE_FORMAT(k.yjsj, '%Y%m'))) | |
| 3404 | + FROM lq_kd_kjbsyj k | |
| 3405 | + {whereClause}"; | |
| 3406 | + | |
| 3407 | + var countParameters = parameters.Where(p => p.ParameterName != "@PageSize" && p.ParameterName != "@Offset").ToList(); | |
| 3408 | + var totalCount = await _db.Ado.GetIntAsync(countSql, countParameters); | |
| 3409 | + | |
| 3410 | + // 执行查询 | |
| 3411 | + var result = await _db.Ado.SqlQueryAsync<LqTechPerformanceStatisticsListOutput>(sql, parameters); | |
| 3269 | 3412 | |
| 3270 | 3413 | return new |
| 3271 | 3414 | { |
| 3272 | - list = result.list, | |
| 3415 | + list = result, | |
| 3273 | 3416 | pagination = new |
| 3274 | 3417 | { |
| 3275 | 3418 | pageIndex = input.PageIndex, |
| 3276 | 3419 | pageSize = input.PageSize, |
| 3277 | - total = result.pagination.Total | |
| 3420 | + total = totalCount | |
| 3278 | 3421 | } |
| 3279 | 3422 | }; |
| 3280 | 3423 | } |
| ... | ... | @@ -3286,8 +3429,27 @@ namespace NCC.Extend.LqStatistics |
| 3286 | 3429 | } |
| 3287 | 3430 | |
| 3288 | 3431 | /// <summary> |
| 3289 | - /// 获取门店耗卡业绩统计列表 | |
| 3432 | + /// 获取门店耗卡业绩统计列表(实时统计) | |
| 3290 | 3433 | /// </summary> |
| 3434 | + /// <remarks> | |
| 3435 | + /// 实时从业务表统计门店的耗卡业绩数据,包括耗卡业绩、项目数量、手工费等 | |
| 3436 | + /// | |
| 3437 | + /// 数据来源: | |
| 3438 | + /// - lq_xh_hyhk: 耗卡表 | |
| 3439 | + /// - lq_xh_pxmx: 耗卡品项明细表 | |
| 3440 | + /// - lq_mdxx: 门店信息表 | |
| 3441 | + /// | |
| 3442 | + /// 统计逻辑: | |
| 3443 | + /// - 按门店分组统计 | |
| 3444 | + /// - 耗卡业绩:汇总品项明细的总价(F_TotalPrice) | |
| 3445 | + /// - 项目数量:汇总品项明细的项目数量(F_ProjectNumber) | |
| 3446 | + /// - 手工费:汇总耗卡表的手工费(sgfy) | |
| 3447 | + /// | |
| 3448 | + /// 性能优化: | |
| 3449 | + /// - 使用索引:md, hksj, F_IsEffective | |
| 3450 | + /// - 先过滤再聚合,减少数据量 | |
| 3451 | + /// - 使用子查询优化聚合计算 | |
| 3452 | + /// </remarks> | |
| 3291 | 3453 | /// <param name="input">查询参数</param> |
| 3292 | 3454 | /// <returns>分页结果</returns> |
| 3293 | 3455 | [HttpPost("get-store-consume-performance-statistics-list")] |
| ... | ... | @@ -3295,39 +3457,92 @@ namespace NCC.Extend.LqStatistics |
| 3295 | 3457 | { |
| 3296 | 3458 | try |
| 3297 | 3459 | { |
| 3298 | - var query = _db.Queryable<LqStatisticsStoreConsumePerformanceEntity>(); | |
| 3460 | + // 构建WHERE条件 | |
| 3461 | + var whereConditions = new List<string>(); | |
| 3462 | + var parameters = new List<SugarParameter>(); | |
| 3299 | 3463 | |
| 3300 | - // 添加查询条件 | |
| 3301 | - query = query.WhereIF(!string.IsNullOrEmpty(input.StatisticsMonth), x => x.StatisticsMonth == input.StatisticsMonth); | |
| 3302 | - query = query.WhereIF(!string.IsNullOrEmpty(input.StoreName), x => x.StoreName.Contains(input.StoreName)); | |
| 3464 | + // 月份条件 | |
| 3465 | + if (!string.IsNullOrEmpty(input.StatisticsMonth)) | |
| 3466 | + { | |
| 3467 | + whereConditions.Add("DATE_FORMAT(hyhk.hksj, '%Y%m') = @StatisticsMonth"); | |
| 3468 | + parameters.Add(new SugarParameter("@StatisticsMonth", input.StatisticsMonth)); | |
| 3469 | + } | |
| 3303 | 3470 | |
| 3304 | - // 按创建时间降序排序 | |
| 3305 | - query = query.OrderBy(x => x.CreateTime, OrderByType.Desc); | |
| 3471 | + // 门店名称条件 | |
| 3472 | + if (!string.IsNullOrEmpty(input.StoreName)) | |
| 3473 | + { | |
| 3474 | + whereConditions.Add("(hyhk.mdmc LIKE @StoreName OR mdxx.dm LIKE @StoreName)"); | |
| 3475 | + parameters.Add(new SugarParameter("@StoreName", $"%{input.StoreName}%")); | |
| 3476 | + } | |
| 3306 | 3477 | |
| 3307 | - // 分页查询并映射到DTO | |
| 3308 | - var pagedResult = await query.ToPagedListAsync(input.PageIndex, input.PageSize); | |
| 3478 | + // 基础条件 | |
| 3479 | + whereConditions.Add("hyhk.F_IsEffective = 1"); | |
| 3309 | 3480 | |
| 3310 | - var outputList = pagedResult.list.Select(it => new LqStoreConsumePerformanceStatisticsListOutput | |
| 3311 | - { | |
| 3312 | - Id = it.Id, | |
| 3313 | - StatisticsMonth = it.StatisticsMonth, | |
| 3314 | - StoreId = it.StoreId, | |
| 3315 | - StoreName = it.StoreName, | |
| 3316 | - TotalPerformance = it.ConsumePerformance, // 使用ConsumePerformance作为总业绩 | |
| 3317 | - ConsumePerformance = it.ConsumePerformance, | |
| 3318 | - OrderCount = (int)it.ConsumeQuantity, // 使用ConsumeQuantity作为订单数量 | |
| 3319 | - IsNewStore = false, // 暂时设为false,因为Entity中没有这个字段 | |
| 3320 | - CreateTime = it.CreateTime.HasValue ? it.CreateTime.Value : DateTime.Now | |
| 3321 | - }).ToList(); | |
| 3481 | + var whereClause = "WHERE " + string.Join(" AND ", whereConditions); | |
| 3482 | + | |
| 3483 | + // 实时统计SQL - 优化性能 | |
| 3484 | + var sql = $@" | |
| 3485 | + SELECT | |
| 3486 | + CONCAT(hyhk.md, '_', DATE_FORMAT(hyhk.hksj, '%Y%m')) AS Id, | |
| 3487 | + DATE_FORMAT(hyhk.hksj, '%Y%m') AS StatisticsMonth, | |
| 3488 | + hyhk.md AS StoreId, | |
| 3489 | + COALESCE(hyhk.mdmc, mdxx.dm, '') AS StoreName, | |
| 3490 | + COALESCE(SUM(pxmx.F_TotalPrice), 0) AS ConsumePerformance, | |
| 3491 | + COALESCE(SUM(pxmx.F_TotalPrice), 0) AS TotalPerformance, | |
| 3492 | + CAST(COALESCE(SUM(pxmx.F_ProjectNumber), 0) AS UNSIGNED) AS OrderCount, | |
| 3493 | + CASE | |
| 3494 | + WHEN EXISTS ( | |
| 3495 | + SELECT 1 FROM lq_md_xdbhsj xdbh | |
| 3496 | + WHERE xdbh.mdid = hyhk.md | |
| 3497 | + AND xdbh.sfqy = 1 | |
| 3498 | + AND xdbh.bhkssj <= DATE_FORMAT(hyhk.hksj, '%Y-%m-%d') | |
| 3499 | + AND xdbh.bhjssj >= DATE_FORMAT(hyhk.hksj, '%Y-%m-%d') | |
| 3500 | + LIMIT 1 | |
| 3501 | + ) THEN 1 | |
| 3502 | + ELSE 0 | |
| 3503 | + END AS IsNewStore, | |
| 3504 | + NOW() AS CreateTime | |
| 3505 | + FROM lq_xh_hyhk hyhk | |
| 3506 | + LEFT JOIN lq_xh_pxmx pxmx ON hyhk.F_Id = pxmx.F_ConsumeInfoId AND pxmx.F_IsEffective = 1 | |
| 3507 | + LEFT JOIN lq_mdxx mdxx ON hyhk.md = mdxx.F_Id | |
| 3508 | + {whereClause} | |
| 3509 | + GROUP BY hyhk.md, hyhk.mdmc, mdxx.dm, DATE_FORMAT(hyhk.hksj, '%Y%m') | |
| 3510 | + HAVING ConsumePerformance > 0 OR OrderCount > 0 | |
| 3511 | + ORDER BY ConsumePerformance DESC, StatisticsMonth DESC | |
| 3512 | + LIMIT @PageSize OFFSET @Offset"; | |
| 3513 | + | |
| 3514 | + parameters.Add(new SugarParameter("@PageSize", input.PageSize)); | |
| 3515 | + parameters.Add(new SugarParameter("@Offset", (input.PageIndex - 1) * input.PageSize)); | |
| 3516 | + | |
| 3517 | + // 查询总数(使用子查询统计满足条件的分组数) | |
| 3518 | + var countSql = $@" | |
| 3519 | + SELECT COUNT(*) | |
| 3520 | + FROM ( | |
| 3521 | + SELECT | |
| 3522 | + hyhk.md, | |
| 3523 | + DATE_FORMAT(hyhk.hksj, '%Y%m') AS month_key | |
| 3524 | + FROM lq_xh_hyhk hyhk | |
| 3525 | + LEFT JOIN lq_xh_pxmx pxmx ON hyhk.F_Id = pxmx.F_ConsumeInfoId AND pxmx.F_IsEffective = 1 | |
| 3526 | + LEFT JOIN lq_mdxx mdxx ON hyhk.md = mdxx.F_Id | |
| 3527 | + {whereClause} | |
| 3528 | + GROUP BY hyhk.md, DATE_FORMAT(hyhk.hksj, '%Y%m') | |
| 3529 | + HAVING COALESCE(SUM(pxmx.F_TotalPrice), 0) > 0 OR COALESCE(SUM(pxmx.F_ProjectNumber), 0) > 0 | |
| 3530 | + ) AS grouped_data"; | |
| 3531 | + | |
| 3532 | + var countParameters = parameters.Where(p => p.ParameterName != "@PageSize" && p.ParameterName != "@Offset").ToList(); | |
| 3533 | + var totalCount = await _db.Ado.GetIntAsync(countSql, countParameters); | |
| 3534 | + | |
| 3535 | + // 执行查询 | |
| 3536 | + var result = await _db.Ado.SqlQueryAsync<LqStoreConsumePerformanceStatisticsListOutput>(sql, parameters); | |
| 3322 | 3537 | |
| 3323 | 3538 | return new |
| 3324 | 3539 | { |
| 3325 | - list = outputList, | |
| 3540 | + list = result, | |
| 3326 | 3541 | pagination = new |
| 3327 | 3542 | { |
| 3328 | 3543 | pageIndex = input.PageIndex, |
| 3329 | 3544 | pageSize = input.PageSize, |
| 3330 | - total = pagedResult.pagination.Total | |
| 3545 | + total = totalCount | |
| 3331 | 3546 | } |
| 3332 | 3547 | }; |
| 3333 | 3548 | } |
| ... | ... | @@ -3339,8 +3554,28 @@ namespace NCC.Extend.LqStatistics |
| 3339 | 3554 | } |
| 3340 | 3555 | |
| 3341 | 3556 | /// <summary> |
| 3342 | - /// 获取个人消耗业绩统计列表 | |
| 3557 | + /// 获取部门消耗业绩统计列表(实时统计) | |
| 3343 | 3558 | /// </summary> |
| 3559 | + /// <remarks> | |
| 3560 | + /// 实时从业务表统计部门员工的消耗业绩数据,包括健康师和科技部老师两种类型 | |
| 3561 | + /// | |
| 3562 | + /// 数据来源: | |
| 3563 | + /// - lq_xh_jksyj: 健康师消耗业绩表 | |
| 3564 | + /// - lq_xh_kjbsyj: 科技部老师消耗业绩表 | |
| 3565 | + /// - lq_xh_hyhk: 耗卡表(用于获取时间和门店信息) | |
| 3566 | + /// - lq_mdxx: 门店信息表 | |
| 3567 | + /// | |
| 3568 | + /// 统计逻辑: | |
| 3569 | + /// - 健康师:按健康师ID、门店分组,统计消耗业绩、项目数量、人头、人次 | |
| 3570 | + /// - 科技部老师:按老师ID、门店分组,统计消耗业绩、项目数量(人头、人次为0) | |
| 3571 | + /// - 人头:月度去重客户数 | |
| 3572 | + /// - 人次:日度去重到店数(每天同一个客户只算一次) | |
| 3573 | + /// | |
| 3574 | + /// 性能优化: | |
| 3575 | + /// - 使用UNION ALL合并健康师和科技部老师数据 | |
| 3576 | + /// - 使用子查询优化人头和人次统计 | |
| 3577 | + /// - 使用索引:jkszh/kjblszh, md, hksj, F_IsEffective | |
| 3578 | + /// </remarks> | |
| 3344 | 3579 | /// <param name="input">查询参数</param> |
| 3345 | 3580 | /// <returns>分页结果</returns> |
| 3346 | 3581 | [HttpPost("get-department-consume-performance-statistics-list")] |
| ... | ... | @@ -3348,45 +3583,196 @@ namespace NCC.Extend.LqStatistics |
| 3348 | 3583 | { |
| 3349 | 3584 | try |
| 3350 | 3585 | { |
| 3351 | - var query = _db.Queryable<LqStatisticsDepartmentConsumePerformanceEntity>(); | |
| 3586 | + // 构建WHERE条件 | |
| 3587 | + var whereConditions = new List<string>(); | |
| 3588 | + var parameters = new List<SugarParameter>(); | |
| 3352 | 3589 | |
| 3353 | - // 添加查询条件 | |
| 3354 | - query = query.WhereIF(!string.IsNullOrEmpty(input.StatisticsMonth), x => x.StatisticsMonth == input.StatisticsMonth); | |
| 3355 | - query = query.WhereIF(!string.IsNullOrEmpty(input.EmployeeName), x => x.UserName.Contains(input.EmployeeName)); | |
| 3356 | - query = query.WhereIF(!string.IsNullOrEmpty(input.StoreName), x => x.StoreName.Contains(input.StoreName)); | |
| 3357 | - query = query.WhereIF(!string.IsNullOrEmpty(input.Position), x => x.DepartmentType.Contains(input.Position)); | |
| 3590 | + // 月份条件(用于子查询) | |
| 3591 | + var monthCondition = ""; | |
| 3592 | + if (!string.IsNullOrEmpty(input.StatisticsMonth)) | |
| 3593 | + { | |
| 3594 | + monthCondition = "AND DATE_FORMAT(hyhk_inner.hksj, '%Y%m') = @StatisticsMonth"; | |
| 3595 | + whereConditions.Add("DATE_FORMAT(hyhk.hksj, '%Y%m') = @StatisticsMonth"); | |
| 3596 | + parameters.Add(new SugarParameter("@StatisticsMonth", input.StatisticsMonth)); | |
| 3597 | + } | |
| 3358 | 3598 | |
| 3359 | - // 按创建时间降序排序 | |
| 3360 | - query = query.OrderBy(x => x.CreateTime, OrderByType.Desc); | |
| 3599 | + // 员工姓名条件(需要在UNION的两个查询中都添加) | |
| 3600 | + var employeeNameConditionJks = ""; | |
| 3601 | + var employeeNameConditionKjbs = ""; | |
| 3602 | + if (!string.IsNullOrEmpty(input.EmployeeName)) | |
| 3603 | + { | |
| 3604 | + employeeNameConditionJks = "AND jksyj.jksxm LIKE @EmployeeName"; | |
| 3605 | + employeeNameConditionKjbs = "AND kjbsyj.kjblsxm LIKE @EmployeeName"; | |
| 3606 | + parameters.Add(new SugarParameter("@EmployeeName", $"%{input.EmployeeName}%")); | |
| 3607 | + } | |
| 3361 | 3608 | |
| 3362 | - // 分页查询并映射到DTO | |
| 3363 | - var pagedResult = await query.ToPagedListAsync(input.PageIndex, input.PageSize); | |
| 3609 | + // 门店名称条件 | |
| 3610 | + var storeNameCondition = ""; | |
| 3611 | + if (!string.IsNullOrEmpty(input.StoreName)) | |
| 3612 | + { | |
| 3613 | + storeNameCondition = "AND (hyhk.mdmc LIKE @StoreName OR md.dm LIKE @StoreName)"; | |
| 3614 | + parameters.Add(new SugarParameter("@StoreName", $"%{input.StoreName}%")); | |
| 3615 | + } | |
| 3364 | 3616 | |
| 3365 | - var outputList = pagedResult.list.Select(it => new LqDepartmentConsumePerformanceStatisticsListOutput | |
| 3617 | + // 岗位条件 | |
| 3618 | + var positionCondition = ""; | |
| 3619 | + if (!string.IsNullOrEmpty(input.Position)) | |
| 3366 | 3620 | { |
| 3367 | - Id = it.Id, | |
| 3368 | - StatisticsMonth = it.StatisticsMonth, | |
| 3369 | - EmployeeId = it.UserId, | |
| 3370 | - EmployeeName = it.UserName, | |
| 3371 | - StoreId = it.StoreId, | |
| 3372 | - StoreName = it.StoreName, | |
| 3373 | - Position = it.DepartmentType, | |
| 3374 | - TotalPerformance = it.ConsumePerformance, // 使用ConsumePerformance作为总业绩 | |
| 3375 | - ConsumePerformance = it.ConsumePerformance, | |
| 3376 | - OrderCount = it.ConsumeQuantity, // 使用ConsumeQuantity作为订单数量 | |
| 3377 | - HeadCount = it.HeadCount, // 人头数 | |
| 3378 | - PersonCount = it.PersonCount, // 人次 | |
| 3379 | - CreateTime = it.CreateTime.HasValue ? it.CreateTime.Value : DateTime.Now | |
| 3380 | - }).ToList(); | |
| 3621 | + positionCondition = "AND dept_type LIKE @Position"; | |
| 3622 | + parameters.Add(new SugarParameter("@Position", $"%{input.Position}%")); | |
| 3623 | + } | |
| 3624 | + | |
| 3625 | + var baseWhere = whereConditions.Any() ? string.Join(" AND ", whereConditions) : ""; | |
| 3626 | + var baseWhereClause = !string.IsNullOrEmpty(baseWhere) ? "WHERE " + baseWhere : ""; | |
| 3627 | + | |
| 3628 | + // 实时统计SQL - 使用UNION ALL合并健康师和科技部老师数据 | |
| 3629 | + var sql = $@" | |
| 3630 | + SELECT | |
| 3631 | + CONCAT(dept_type, '_', user_id, '_', store_id, '_', statistics_month) AS Id, | |
| 3632 | + statistics_month AS StatisticsMonth, | |
| 3633 | + user_id AS EmployeeId, | |
| 3634 | + user_name AS EmployeeName, | |
| 3635 | + store_id AS StoreId, | |
| 3636 | + store_name AS StoreName, | |
| 3637 | + dept_type AS Position, | |
| 3638 | + consume_performance AS ConsumePerformance, | |
| 3639 | + consume_performance AS TotalPerformance, | |
| 3640 | + consume_quantity AS OrderCount, | |
| 3641 | + head_count AS HeadCount, | |
| 3642 | + person_count AS PersonCount, | |
| 3643 | + 0 AS RefundAmount, | |
| 3644 | + 0 AS RefundCount, | |
| 3645 | + NOW() AS CreateTime | |
| 3646 | + FROM ( | |
| 3647 | + -- 健康师消耗业绩统计 | |
| 3648 | + SELECT | |
| 3649 | + '健康师' AS dept_type, | |
| 3650 | + jksyj.jkszh AS user_id, | |
| 3651 | + jksyj.jksxm AS user_name, | |
| 3652 | + hyhk.md AS store_id, | |
| 3653 | + COALESCE(hyhk.mdmc, md.dm, '') AS store_name, | |
| 3654 | + DATE_FORMAT(hyhk.hksj, '%Y%m') AS statistics_month, | |
| 3655 | + COALESCE(SUM(jksyj.jksyj), 0) AS consume_performance, | |
| 3656 | + COALESCE(SUM(jksyj.F_kdpxNumber), 0) AS consume_quantity, | |
| 3657 | + COALESCE(headcount_stats.head_count, 0) AS head_count, | |
| 3658 | + COALESCE(personcount_stats.person_count, 0) AS person_count | |
| 3659 | + FROM lq_xh_jksyj jksyj | |
| 3660 | + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id AND hyhk.F_IsEffective = 1 | |
| 3661 | + LEFT JOIN lq_mdxx md ON hyhk.md = md.F_Id | |
| 3662 | + LEFT JOIN ( | |
| 3663 | + -- 人头统计:月度去重客户数 | |
| 3664 | + SELECT | |
| 3665 | + jksyj_inner.jkszh, | |
| 3666 | + hyhk_inner.md, | |
| 3667 | + COUNT(DISTINCT hyhk_inner.hy) AS head_count | |
| 3668 | + FROM lq_xh_jksyj jksyj_inner | |
| 3669 | + INNER JOIN lq_xh_hyhk hyhk_inner ON jksyj_inner.glkdbh = hyhk_inner.F_Id AND hyhk_inner.F_IsEffective = 1 | |
| 3670 | + WHERE jksyj_inner.F_IsEffective = 1 | |
| 3671 | + {monthCondition} | |
| 3672 | + GROUP BY jksyj_inner.jkszh, hyhk_inner.md | |
| 3673 | + ) headcount_stats ON jksyj.jkszh = headcount_stats.jkszh AND hyhk.md = headcount_stats.md | |
| 3674 | + LEFT JOIN ( | |
| 3675 | + -- 人次统计:日度去重客户数 | |
| 3676 | + SELECT | |
| 3677 | + jksyj_inner.jkszh, | |
| 3678 | + hyhk_inner.md, | |
| 3679 | + COUNT(DISTINCT CONCAT(hyhk_inner.hy, '-', DATE(hyhk_inner.hksj))) AS person_count | |
| 3680 | + FROM lq_xh_jksyj jksyj_inner | |
| 3681 | + INNER JOIN lq_xh_hyhk hyhk_inner ON jksyj_inner.glkdbh = hyhk_inner.F_Id AND hyhk_inner.F_IsEffective = 1 | |
| 3682 | + WHERE jksyj_inner.F_IsEffective = 1 | |
| 3683 | + {monthCondition} | |
| 3684 | + GROUP BY jksyj_inner.jkszh, hyhk_inner.md | |
| 3685 | + ) personcount_stats ON jksyj.jkszh = personcount_stats.jkszh AND hyhk.md = personcount_stats.md | |
| 3686 | + WHERE jksyj.F_IsEffective = 1 | |
| 3687 | + {(!string.IsNullOrEmpty(baseWhere) ? "AND " + baseWhere : "")} | |
| 3688 | + {employeeNameConditionJks} | |
| 3689 | + {storeNameCondition} | |
| 3690 | + GROUP BY jksyj.jkszh, jksyj.jksxm, hyhk.md, hyhk.mdmc, md.dm, DATE_FORMAT(hyhk.hksj, '%Y%m'), headcount_stats.head_count, personcount_stats.person_count, statistics_month | |
| 3691 | + | |
| 3692 | + UNION ALL | |
| 3693 | + | |
| 3694 | + -- 科技部老师消耗业绩统计 | |
| 3695 | + SELECT | |
| 3696 | + '科技部老师' AS dept_type, | |
| 3697 | + kjbsyj.kjblszh AS user_id, | |
| 3698 | + kjbsyj.kjblsxm AS user_name, | |
| 3699 | + hyhk.md AS store_id, | |
| 3700 | + COALESCE(hyhk.mdmc, md.dm, '') AS store_name, | |
| 3701 | + DATE_FORMAT(hyhk.hksj, '%Y%m') AS statistics_month, | |
| 3702 | + COALESCE(SUM(kjbsyj.kjblsyj), 0) AS consume_performance, | |
| 3703 | + COALESCE(SUM(kjbsyj.F_hdpxNumber), 0) AS consume_quantity, | |
| 3704 | + 0 AS head_count, | |
| 3705 | + 0 AS person_count | |
| 3706 | + FROM lq_xh_kjbsyj kjbsyj | |
| 3707 | + INNER JOIN lq_xh_hyhk hyhk ON kjbsyj.glkdbh = hyhk.F_Id AND hyhk.F_IsEffective = 1 | |
| 3708 | + LEFT JOIN lq_mdxx md ON hyhk.md = md.F_Id | |
| 3709 | + WHERE kjbsyj.F_IsEffective = 1 | |
| 3710 | + {(!string.IsNullOrEmpty(baseWhere) ? "AND " + baseWhere : "")} | |
| 3711 | + {employeeNameConditionKjbs} | |
| 3712 | + {storeNameCondition} | |
| 3713 | + GROUP BY kjbsyj.kjblszh, kjbsyj.kjblsxm, hyhk.md, hyhk.mdmc, md.dm, DATE_FORMAT(hyhk.hksj, '%Y%m') | |
| 3714 | + ) combined_stats | |
| 3715 | + WHERE 1=1 | |
| 3716 | + {positionCondition} | |
| 3717 | + ORDER BY consume_performance DESC, StatisticsMonth DESC | |
| 3718 | + LIMIT @PageSize OFFSET @Offset"; | |
| 3719 | + | |
| 3720 | + parameters.Add(new SugarParameter("@PageSize", input.PageSize)); | |
| 3721 | + parameters.Add(new SugarParameter("@Offset", (input.PageIndex - 1) * input.PageSize)); | |
| 3722 | + | |
| 3723 | + // 查询总数(需要重新构建,因为UNION ALL的结构) | |
| 3724 | + var countSql = $@" | |
| 3725 | + SELECT COUNT(*) | |
| 3726 | + FROM ( | |
| 3727 | + SELECT | |
| 3728 | + '健康师' AS dept_type, | |
| 3729 | + jksyj.jkszh AS user_id, | |
| 3730 | + jksyj.jksxm AS user_name, | |
| 3731 | + hyhk.md AS store_id, | |
| 3732 | + COALESCE(hyhk.mdmc, md.dm, '') AS store_name | |
| 3733 | + FROM lq_xh_jksyj jksyj | |
| 3734 | + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id AND hyhk.F_IsEffective = 1 | |
| 3735 | + LEFT JOIN lq_mdxx md ON hyhk.md = md.F_Id | |
| 3736 | + WHERE jksyj.F_IsEffective = 1 | |
| 3737 | + {(!string.IsNullOrEmpty(baseWhere) ? "AND " + baseWhere : "")} | |
| 3738 | + {employeeNameConditionJks} | |
| 3739 | + {storeNameCondition} | |
| 3740 | + GROUP BY jksyj.jkszh, jksyj.jksxm, hyhk.md, hyhk.mdmc, md.dm, DATE_FORMAT(hyhk.hksj, '%Y%m') | |
| 3741 | + | |
| 3742 | + UNION ALL | |
| 3743 | + | |
| 3744 | + SELECT | |
| 3745 | + '科技部老师' AS dept_type, | |
| 3746 | + kjbsyj.kjblszh AS user_id, | |
| 3747 | + kjbsyj.kjblsxm AS user_name, | |
| 3748 | + hyhk.md AS store_id, | |
| 3749 | + COALESCE(hyhk.mdmc, md.dm, '') AS store_name | |
| 3750 | + FROM lq_xh_kjbsyj kjbsyj | |
| 3751 | + INNER JOIN lq_xh_hyhk hyhk ON kjbsyj.glkdbh = hyhk.F_Id AND hyhk.F_IsEffective = 1 | |
| 3752 | + LEFT JOIN lq_mdxx md ON hyhk.md = md.F_Id | |
| 3753 | + WHERE kjbsyj.F_IsEffective = 1 | |
| 3754 | + {(!string.IsNullOrEmpty(baseWhere) ? "AND " + baseWhere : "")} | |
| 3755 | + {employeeNameConditionKjbs} | |
| 3756 | + {storeNameCondition} | |
| 3757 | + GROUP BY kjbsyj.kjblszh, kjbsyj.kjblsxm, hyhk.md, hyhk.mdmc, md.dm, DATE_FORMAT(hyhk.hksj, '%Y%m') | |
| 3758 | + ) combined_stats | |
| 3759 | + WHERE 1=1 | |
| 3760 | + {positionCondition}"; | |
| 3761 | + | |
| 3762 | + var countParameters = parameters.Where(p => p.ParameterName != "@PageSize" && p.ParameterName != "@Offset").ToList(); | |
| 3763 | + var totalCount = await _db.Ado.GetIntAsync(countSql, countParameters); | |
| 3764 | + | |
| 3765 | + // 执行查询 | |
| 3766 | + var result = await _db.Ado.SqlQueryAsync<LqDepartmentConsumePerformanceStatisticsListOutput>(sql, parameters); | |
| 3381 | 3767 | |
| 3382 | 3768 | return new |
| 3383 | 3769 | { |
| 3384 | - list = outputList, | |
| 3770 | + list = result, | |
| 3385 | 3771 | pagination = new |
| 3386 | 3772 | { |
| 3387 | 3773 | pageIndex = input.PageIndex, |
| 3388 | 3774 | pageSize = input.PageSize, |
| 3389 | - total = pagedResult.pagination.Total | |
| 3775 | + total = totalCount | |
| 3390 | 3776 | } |
| 3391 | 3777 | }; |
| 3392 | 3778 | } |
| ... | ... | @@ -4074,6 +4460,22 @@ namespace NCC.Extend.LqStatistics |
| 4074 | 4460 | /// 1. 会员必须有购买女神卡的记录 |
| 4075 | 4461 | /// 2. 该会员的所有有效开单记录中,所有品项都必须是女神卡(px = "61") |
| 4076 | 4462 | /// |
| 4463 | + /// 示例请求: | |
| 4464 | + /// ```json | |
| 4465 | + /// { | |
| 4466 | + /// "PageIndex": 1, | |
| 4467 | + /// "PageSize": 20, | |
| 4468 | + /// "StoreId": "门店ID", | |
| 4469 | + /// "StoreIds": ["门店ID1", "门店ID2"] | |
| 4470 | + /// } | |
| 4471 | + /// ``` | |
| 4472 | + /// | |
| 4473 | + /// 参数说明: | |
| 4474 | + /// - PageIndex: 当前页码(从1开始) | |
| 4475 | + /// - PageSize: 每页数量 | |
| 4476 | + /// - StoreId: 门店ID(单个门店筛选,与StoreIds二选一) | |
| 4477 | + /// - StoreIds: 门店ID列表(支持多门店筛选,与StoreId二选一) | |
| 4478 | + /// | |
| 4077 | 4479 | /// 返回说明: |
| 4078 | 4480 | /// - list: 会员列表 |
| 4079 | 4481 | /// - memberId: 会员ID |
| ... | ... | @@ -4111,9 +4513,30 @@ namespace NCC.Extend.LqStatistics |
| 4111 | 4513 | { |
| 4112 | 4514 | try |
| 4113 | 4515 | { |
| 4516 | + // 构建门店筛选条件 | |
| 4517 | + var storeFilterConditions = new List<string>(); | |
| 4518 | + var parameters = new List<SugarParameter>(); | |
| 4519 | + | |
| 4520 | + if (!string.IsNullOrEmpty(input.StoreId)) | |
| 4521 | + { | |
| 4522 | + storeFilterConditions.Add("kd1.djmd = @StoreId"); | |
| 4523 | + parameters.Add(new SugarParameter("@StoreId", input.StoreId)); | |
| 4524 | + } | |
| 4525 | + else if (input.StoreIds != null && input.StoreIds.Any()) | |
| 4526 | + { | |
| 4527 | + var storeIdParams = string.Join(",", input.StoreIds.Select((_, i) => $"@StoreId{i}")); | |
| 4528 | + storeFilterConditions.Add($"kd1.djmd IN ({storeIdParams})"); | |
| 4529 | + for (int i = 0; i < input.StoreIds.Count; i++) | |
| 4530 | + { | |
| 4531 | + parameters.Add(new SugarParameter($"@StoreId{i}", input.StoreIds[i])); | |
| 4532 | + } | |
| 4533 | + } | |
| 4534 | + | |
| 4535 | + var storeFilterClause = storeFilterConditions.Any() ? "AND " + string.Join(" AND ", storeFilterConditions) : ""; | |
| 4536 | + | |
| 4114 | 4537 | // 使用SQL一次性查询出符合条件的会员ID |
| 4115 | 4538 | // 逻辑:会员有购买女神卡的记录,且该会员的所有开单记录的所有品项都是女神卡 |
| 4116 | - var sql = @" | |
| 4539 | + var sql = $@" | |
| 4117 | 4540 | SELECT DISTINCT kd1.Kdhy AS MemberId |
| 4118 | 4541 | FROM lq_kd_pxmx pxmx1 |
| 4119 | 4542 | INNER JOIN lq_kd_kdjlb kd1 ON pxmx1.glkdbh = kd1.F_Id |
| ... | ... | @@ -4122,6 +4545,7 @@ namespace NCC.Extend.LqStatistics |
| 4122 | 4545 | AND kd1.F_IsEffective = 1 |
| 4123 | 4546 | AND kd1.Kdhy IS NOT NULL |
| 4124 | 4547 | AND kd1.Kdhy != '' |
| 4548 | + {storeFilterClause} | |
| 4125 | 4549 | AND NOT EXISTS ( |
| 4126 | 4550 | -- 排除那些有非女神卡品项的会员 |
| 4127 | 4551 | SELECT 1 |
| ... | ... | @@ -4133,7 +4557,7 @@ namespace NCC.Extend.LqStatistics |
| 4133 | 4557 | AND pxmx2.px != '61' |
| 4134 | 4558 | )"; |
| 4135 | 4559 | |
| 4136 | - var validMemberIds = await _db.Ado.SqlQueryAsync<string>(sql); | |
| 4560 | + var validMemberIds = await _db.Ado.SqlQueryAsync<string>(sql, parameters); | |
| 4137 | 4561 | |
| 4138 | 4562 | if (!validMemberIds.Any()) |
| 4139 | 4563 | { |
| ... | ... | @@ -4299,6 +4723,11 @@ namespace NCC.Extend.LqStatistics |
| 4299 | 4723 | /// - LeadCustomerId: 线索池客户(拓客编号) |
| 4300 | 4724 | /// - CustomerName: 客户姓名 |
| 4301 | 4725 | /// - ExpansionTime: 拓客时间 |
| 4726 | + /// - StoreId: 归属门店ID(从客户信息表获取) | |
| 4727 | + /// - StoreName: 归属门店名称 | |
| 4728 | + /// - Phone: 电话(优先使用拓客记录的电话,如果没有则使用客户信息表的电话) | |
| 4729 | + /// - ExpansionUserId: 拓客人员ID | |
| 4730 | + /// - ExpansionUserName: 拓客人员姓名 | |
| 4302 | 4731 | /// - HasInvite: 是否邀约(是/否),通过拓客编号关联邀约表 |
| 4303 | 4732 | /// - HasAppointment: 是否预约(是/否),只统计通过邀约产生的预约(预约表的F_InviteId关联邀约表) |
| 4304 | 4733 | /// - HasConsume: 是否有消耗(是/否),只统计通过预约产生的耗卡(耗卡表的F_AppointmentId关联预约表) |
| ... | ... | @@ -4319,6 +4748,11 @@ namespace NCC.Extend.LqStatistics |
| 4319 | 4748 | /// "LeadCustomerId": "751248448816153862", |
| 4320 | 4749 | /// "CustomerName": "王女士", |
| 4321 | 4750 | /// "ExpansionTime": "2025-10-24T03:33:10.000Z", |
| 4751 | + /// "StoreId": "1649328471923847169", | |
| 4752 | + /// "StoreName": "绿纤紫荆店", | |
| 4753 | + /// "Phone": "13800138000", | |
| 4754 | + /// "ExpansionUserId": "123456789", | |
| 4755 | + /// "ExpansionUserName": "张三", | |
| 4322 | 4756 | /// "HasInvite": "否", |
| 4323 | 4757 | /// "HasAppointment": "否", |
| 4324 | 4758 | /// "HasConsume": "否", |
| ... | ... | @@ -4392,6 +4826,16 @@ namespace NCC.Extend.LqStatistics |
| 4392 | 4826 | tk.F_Id as LeadCustomerId, |
| 4393 | 4827 | tk.F_CustomerName as CustomerName, |
| 4394 | 4828 | tk.F_ExpansionTime as ExpansionTime, |
| 4829 | + -- 归属门店ID(从客户信息表获取) | |
| 4830 | + COALESCE(kh.gsmd, '') as StoreId, | |
| 4831 | + -- 归属门店名称 | |
| 4832 | + COALESCE(md.dm, '') as StoreName, | |
| 4833 | + -- 电话(优先使用拓客记录的电话,如果没有则使用客户信息表的电话) | |
| 4834 | + COALESCE(NULLIF(tk.F_CustomerPhone, ''), kh.sjh, '') as Phone, | |
| 4835 | + -- 拓客人员ID | |
| 4836 | + COALESCE(tk.F_ExpansionUserId, '') as ExpansionUserId, | |
| 4837 | + -- 拓客人员姓名 | |
| 4838 | + COALESCE(usr.F_REALNAME, '') as ExpansionUserName, | |
| 4395 | 4839 | -- 是否邀约:通过会员ID关联(邀约表的yykh字段存储的是会员ID) |
| 4396 | 4840 | CASE WHEN yaoy_stats.has_invite = 1 THEN '是' ELSE '否' END as HasInvite, |
| 4397 | 4841 | -- 是否预约:通过邀约ID关联(只统计通过邀约产生的预约) |
| ... | ... | @@ -4413,6 +4857,12 @@ namespace NCC.Extend.LqStatistics |
| 4413 | 4857 | -- 实际开单记录数(不管是否通过预约产生) |
| 4414 | 4858 | COALESCE(kd_actual.count, 0) as ActualBillingCount |
| 4415 | 4859 | FROM lq_tkjlb tk |
| 4860 | + -- 关联客户信息表(获取归属门店和电话) | |
| 4861 | + LEFT JOIN lq_khxx kh ON kh.F_Id = tk.F_MemberId | |
| 4862 | + -- 关联门店表(获取归属门店名称) | |
| 4863 | + LEFT JOIN lq_mdxx md ON md.F_Id = kh.gsmd | |
| 4864 | + -- 关联用户表(获取拓客人员姓名) | |
| 4865 | + LEFT JOIN BASE_USER usr ON usr.F_Id = tk.F_ExpansionUserId AND usr.F_DeleteMark IS NULL | |
| 4416 | 4866 | -- 邀约统计子查询(通过会员ID关联:邀约表的yykh字段存储的是会员ID) |
| 4417 | 4867 | LEFT JOIN ( |
| 4418 | 4868 | SELECT |
| ... | ... | @@ -5020,6 +5470,9 @@ namespace NCC.Extend.LqStatistics |
| 5020 | 5470 | var khWhereClause = khWhereConditions.Any() ? "WHERE " + string.Join(" AND ", khWhereConditions) : "WHERE kh.gsmd IS NOT NULL"; |
| 5021 | 5471 | var khWhereClauseNoAlias = khWhereConditionsNoAlias.Any() ? "WHERE " + string.Join(" AND ", khWhereConditionsNoAlias) : "WHERE gsmd IS NOT NULL"; |
| 5022 | 5472 | |
| 5473 | + // 判断是否有活动筛选 | |
| 5474 | + var hasEventFilter = !string.IsNullOrEmpty(input.EventId); | |
| 5475 | + | |
| 5023 | 5476 | // 使用子查询优化性能,避免复杂的JOIN |
| 5024 | 5477 | var sql = $@" |
| 5025 | 5478 | SELECT |
| ... | ... | @@ -5037,6 +5490,12 @@ namespace NCC.Extend.LqStatistics |
| 5037 | 5490 | SELECT gsmd as StoreId FROM lq_khxx {khWhereClauseNoAlias} |
| 5038 | 5491 | UNION |
| 5039 | 5492 | SELECT F_StoreId as StoreId FROM lq_tkjlb {whereClauseNoAlias} |
| 5493 | + UNION | |
| 5494 | + SELECT F_StoreId as StoreId FROM lq_yaoyjl WHERE F_StoreId IS NOT NULL | |
| 5495 | + UNION | |
| 5496 | + SELECT djmd as StoreId FROM lq_yyjl WHERE djmd IS NOT NULL | |
| 5497 | + UNION | |
| 5498 | + SELECT djmd as StoreId FROM lq_kd_kdjlb WHERE djmd IS NOT NULL AND F_IsEffective = 1 | |
| 5040 | 5499 | ) as all_stores |
| 5041 | 5500 | ) as stores |
| 5042 | 5501 | LEFT JOIN lq_mdxx md ON md.F_Id = stores.StoreId |
| ... | ... | @@ -5058,51 +5517,92 @@ namespace NCC.Extend.LqStatistics |
| 5058 | 5517 | {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} |
| 5059 | 5518 | GROUP BY tk.F_StoreId |
| 5060 | 5519 | ) tk_stats ON tk_stats.StoreId = stores.StoreId |
| 5061 | - -- 邀约数统计 | |
| 5520 | + -- 邀约数统计(如果有活动筛选,通过拓客记录关联;否则直接统计) | |
| 5062 | 5521 | LEFT JOIN ( |
| 5522 | + {(hasEventFilter ? @" | |
| 5063 | 5523 | SELECT |
| 5064 | 5524 | tk.F_StoreId as StoreId, |
| 5065 | 5525 | COUNT(DISTINCT yaoy.F_Id) as InviteCount |
| 5066 | - FROM lq_tkjlb tk | |
| 5067 | - INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk.F_Id | |
| 5068 | - {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} | |
| 5069 | - GROUP BY tk.F_StoreId | |
| 5526 | + FROM lq_yaoyjl yaoy | |
| 5527 | + INNER JOIN lq_tkjlb tk ON tk.F_Id = yaoy.tkbh | |
| 5528 | + WHERE tk.F_StoreId IS NOT NULL | |
| 5529 | + AND tk.F_EventId = @EventId | |
| 5530 | + GROUP BY tk.F_StoreId" : @" | |
| 5531 | + SELECT | |
| 5532 | + yaoy.F_StoreId as StoreId, | |
| 5533 | + COUNT(DISTINCT yaoy.F_Id) as InviteCount | |
| 5534 | + FROM lq_yaoyjl yaoy | |
| 5535 | + WHERE yaoy.F_StoreId IS NOT NULL | |
| 5536 | + GROUP BY yaoy.F_StoreId")} | |
| 5070 | 5537 | ) yaoy_stats ON yaoy_stats.StoreId = stores.StoreId |
| 5071 | - -- 预约数统计(通过邀约ID关联) | |
| 5538 | + -- 预约数统计(如果有活动筛选,通过邀约->拓客链路关联;否则直接统计) | |
| 5072 | 5539 | LEFT JOIN ( |
| 5540 | + {(hasEventFilter ? @" | |
| 5073 | 5541 | SELECT |
| 5074 | 5542 | tk.F_StoreId as StoreId, |
| 5075 | 5543 | COUNT(DISTINCT yy.F_Id) as AppointmentCount |
| 5076 | - FROM lq_tkjlb tk | |
| 5077 | - INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk.F_Id | |
| 5078 | - INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id | |
| 5079 | - {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} | |
| 5080 | - GROUP BY tk.F_StoreId | |
| 5544 | + FROM lq_yyjl yy | |
| 5545 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.F_Id = yy.F_InviteId | |
| 5546 | + INNER JOIN lq_tkjlb tk ON tk.F_Id = yaoy.tkbh | |
| 5547 | + WHERE tk.F_StoreId IS NOT NULL | |
| 5548 | + AND tk.F_EventId = @EventId | |
| 5549 | + GROUP BY tk.F_StoreId" : @" | |
| 5550 | + SELECT | |
| 5551 | + yy.djmd as StoreId, | |
| 5552 | + COUNT(DISTINCT yy.F_Id) as AppointmentCount | |
| 5553 | + FROM lq_yyjl yy | |
| 5554 | + WHERE yy.djmd IS NOT NULL | |
| 5555 | + GROUP BY yy.djmd")} | |
| 5081 | 5556 | ) yy_stats ON yy_stats.StoreId = stores.StoreId |
| 5082 | - -- 耗卡数统计(通过预约ID关联) | |
| 5557 | + -- 耗卡数统计(如果有活动筛选,通过预约->邀约->拓客链路关联;否则直接统计) | |
| 5083 | 5558 | LEFT JOIN ( |
| 5559 | + {(hasEventFilter ? @" | |
| 5084 | 5560 | SELECT |
| 5085 | 5561 | tk.F_StoreId as StoreId, |
| 5086 | 5562 | COUNT(DISTINCT xh.F_Id) as ConsumeCount |
| 5087 | - FROM lq_tkjlb tk | |
| 5088 | - INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk.F_Id | |
| 5089 | - INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id | |
| 5563 | + FROM lq_yyjl yy | |
| 5090 | 5564 | INNER JOIN lq_xh_hyhk xh ON xh.F_AppointmentId = yy.F_Id AND xh.F_IsEffective = 1 |
| 5091 | - {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} | |
| 5092 | - GROUP BY tk.F_StoreId | |
| 5565 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.F_Id = yy.F_InviteId | |
| 5566 | + INNER JOIN lq_tkjlb tk ON tk.F_Id = yaoy.tkbh | |
| 5567 | + WHERE tk.F_StoreId IS NOT NULL | |
| 5568 | + AND tk.F_EventId = @EventId | |
| 5569 | + GROUP BY tk.F_StoreId" : @" | |
| 5570 | + SELECT | |
| 5571 | + yy.djmd as StoreId, | |
| 5572 | + COUNT(DISTINCT xh.F_Id) as ConsumeCount | |
| 5573 | + FROM lq_yyjl yy | |
| 5574 | + INNER JOIN lq_xh_hyhk xh ON xh.F_AppointmentId = yy.F_Id AND xh.F_IsEffective = 1 | |
| 5575 | + WHERE yy.djmd IS NOT NULL | |
| 5576 | + GROUP BY yy.djmd")} | |
| 5093 | 5577 | ) xh_stats ON xh_stats.StoreId = stores.StoreId |
| 5094 | - -- 开单数和开单金额统计(通过预约ID关联) | |
| 5578 | + -- 开单数和开单金额统计(如果有活动筛选,通过预约->邀约->拓客链路关联;否则直接统计) | |
| 5095 | 5579 | LEFT JOIN ( |
| 5580 | + {(hasEventFilter ? @" | |
| 5096 | 5581 | SELECT |
| 5097 | 5582 | tk.F_StoreId as StoreId, |
| 5098 | 5583 | COUNT(DISTINCT kd.F_Id) as BillingCount, |
| 5099 | 5584 | SUM(kd.zdyj) as BillingAmount |
| 5100 | - FROM lq_tkjlb tk | |
| 5101 | - INNER JOIN lq_yaoyjl yaoy ON yaoy.tkbh = tk.F_Id | |
| 5102 | - INNER JOIN lq_yyjl yy ON yy.F_InviteId = yaoy.F_Id | |
| 5103 | - INNER JOIN lq_kd_kdjlb kd ON kd.F_AppointmentId = yy.F_Id AND kd.F_IsEffective = 1 | |
| 5104 | - {(string.IsNullOrEmpty(whereClause) ? "" : whereClause)} | |
| 5105 | - GROUP BY tk.F_StoreId | |
| 5585 | + FROM lq_kd_kdjlb kd | |
| 5586 | + INNER JOIN lq_yyjl yy ON yy.F_Id = kd.F_AppointmentId | |
| 5587 | + INNER JOIN lq_yaoyjl yaoy ON yaoy.F_Id = yy.F_InviteId | |
| 5588 | + INNER JOIN lq_tkjlb tk ON tk.F_Id = yaoy.tkbh | |
| 5589 | + WHERE kd.F_IsEffective = 1 | |
| 5590 | + AND kd.F_AppointmentId IS NOT NULL | |
| 5591 | + AND kd.F_AppointmentId != '' | |
| 5592 | + AND tk.F_StoreId IS NOT NULL | |
| 5593 | + AND tk.F_EventId = @EventId | |
| 5594 | + GROUP BY tk.F_StoreId" : @" | |
| 5595 | + SELECT | |
| 5596 | + kd.djmd as StoreId, | |
| 5597 | + COUNT(DISTINCT kd.F_Id) as BillingCount, | |
| 5598 | + SUM(kd.zdyj) as BillingAmount | |
| 5599 | + FROM lq_kd_kdjlb kd | |
| 5600 | + INNER JOIN lq_yyjl yy ON yy.F_Id = kd.F_AppointmentId | |
| 5601 | + WHERE kd.F_IsEffective = 1 | |
| 5602 | + AND kd.F_AppointmentId IS NOT NULL | |
| 5603 | + AND kd.F_AppointmentId != '' | |
| 5604 | + AND kd.djmd IS NOT NULL | |
| 5605 | + GROUP BY kd.djmd")} | |
| 5106 | 5606 | ) kd_stats ON kd_stats.StoreId = stores.StoreId |
| 5107 | 5607 | WHERE stores.StoreId IS NOT NULL |
| 5108 | 5608 | ORDER BY stores.StoreId"; | ... | ... |
接口调用说明-修改开单信息.md
0 → 100644
| 1 | +# 修改开单信息接口调用说明 | |
| 2 | + | |
| 3 | +## 接口信息 | |
| 4 | + | |
| 5 | +- **接口地址**: `PUT /api/Extend/lqkdkdjlb/UpdateBillingInfo` | |
| 6 | +- **请求方式**: `PUT` | |
| 7 | +- **Content-Type**: `application/json` | |
| 8 | +- **需要认证**: 是(需要在Header中携带Authorization token) | |
| 9 | + | |
| 10 | +## 请求参数 | |
| 11 | + | |
| 12 | +| 参数名 | 类型 | 必填 | 说明 | | |
| 13 | +|--------|------|------|------| | |
| 14 | +| id | string | 是 | 开单记录ID | | |
| 15 | +| scwj | List<FileControlsModel> | 否 | 上传文件列表(不传则不更新) | | |
| 16 | +| F_FIleUrl | string | 否 | 方案其他文件URL(不传则不更新) | | |
| 17 | +| Bz | string | 否 | 备注(不传则不更新) | | |
| 18 | +| Jj | string | 否 | 简介(不传则不更新) | | |
| 19 | + | |
| 20 | +**注意**: 至少需要提供一个要更新的字段(scwj、F_FIleUrl、Bz或Jj) | |
| 21 | + | |
| 22 | +## 响应格式 | |
| 23 | + | |
| 24 | +### 成功响应 (200) | |
| 25 | + | |
| 26 | +```json | |
| 27 | +{ | |
| 28 | + "code": 200, | |
| 29 | + "msg": "更新成功", | |
| 30 | + "data": { | |
| 31 | + "id": "开单记录ID", | |
| 32 | + "updatedFields": ["Bz", "Jj"] | |
| 33 | + } | |
| 34 | +} | |
| 35 | +``` | |
| 36 | + | |
| 37 | +### 错误响应 | |
| 38 | + | |
| 39 | +```json | |
| 40 | +{ | |
| 41 | + "code": 400, | |
| 42 | + "msg": "错误信息", | |
| 43 | + "data": null | |
| 44 | +} | |
| 45 | +``` | |
| 46 | + | |
| 47 | +## 调用示例 | |
| 48 | + | |
| 49 | +### JavaScript/Axios 示例 | |
| 50 | + | |
| 51 | +```javascript | |
| 52 | +import axios from 'axios'; | |
| 53 | + | |
| 54 | +// 更新备注和简介 | |
| 55 | +const updateBillingInfo = async (billingId, remark, description) => { | |
| 56 | + try { | |
| 57 | + const token = localStorage.getItem('token'); // 从本地存储获取token | |
| 58 | + | |
| 59 | + const response = await axios.put( | |
| 60 | + '/api/Extend/lqkdkdjlb/UpdateBillingInfo', | |
| 61 | + { | |
| 62 | + id: billingId, | |
| 63 | + Bz: remark, // 备注 | |
| 64 | + Jj: description // 简介 | |
| 65 | + }, | |
| 66 | + { | |
| 67 | + headers: { | |
| 68 | + 'Authorization': token, | |
| 69 | + 'Content-Type': 'application/json' | |
| 70 | + } | |
| 71 | + } | |
| 72 | + ); | |
| 73 | + | |
| 74 | + if (response.data.code === 200) { | |
| 75 | + console.log('更新成功', response.data.data); | |
| 76 | + return response.data; | |
| 77 | + } else { | |
| 78 | + console.error('更新失败', response.data.msg); | |
| 79 | + throw new Error(response.data.msg); | |
| 80 | + } | |
| 81 | + } catch (error) { | |
| 82 | + console.error('请求失败', error); | |
| 83 | + throw error; | |
| 84 | + } | |
| 85 | +}; | |
| 86 | + | |
| 87 | +// 使用示例 | |
| 88 | +updateBillingInfo('759263766553560325', '这是备注信息', '这是简介信息'); | |
| 89 | +``` | |
| 90 | + | |
| 91 | +### 只更新备注 | |
| 92 | + | |
| 93 | +```javascript | |
| 94 | +const updateRemark = async (billingId, remark) => { | |
| 95 | + const response = await axios.put( | |
| 96 | + '/api/Extend/lqkdkdjlb/UpdateBillingInfo', | |
| 97 | + { | |
| 98 | + id: billingId, | |
| 99 | + Bz: remark | |
| 100 | + }, | |
| 101 | + { | |
| 102 | + headers: { | |
| 103 | + 'Authorization': localStorage.getItem('token'), | |
| 104 | + 'Content-Type': 'application/json' | |
| 105 | + } | |
| 106 | + } | |
| 107 | + ); | |
| 108 | + return response.data; | |
| 109 | +}; | |
| 110 | +``` | |
| 111 | + | |
| 112 | +### 只更新简介 | |
| 113 | + | |
| 114 | +```javascript | |
| 115 | +const updateDescription = async (billingId, description) => { | |
| 116 | + const response = await axios.put( | |
| 117 | + '/api/Extend/lqkdkdjlb/UpdateBillingInfo', | |
| 118 | + { | |
| 119 | + id: billingId, | |
| 120 | + Jj: description | |
| 121 | + }, | |
| 122 | + { | |
| 123 | + headers: { | |
| 124 | + 'Authorization': localStorage.getItem('token'), | |
| 125 | + 'Content-Type': 'application/json' | |
| 126 | + } | |
| 127 | + } | |
| 128 | + ); | |
| 129 | + return response.data; | |
| 130 | +}; | |
| 131 | +``` | |
| 132 | + | |
| 133 | +### 同时更新文件、备注和简介 | |
| 134 | + | |
| 135 | +```javascript | |
| 136 | +const updateAll = async (billingId, files, remark, description, fileUrl) => { | |
| 137 | + const response = await axios.put( | |
| 138 | + '/api/Extend/lqkdkdjlb/UpdateBillingInfo', | |
| 139 | + { | |
| 140 | + id: billingId, | |
| 141 | + scwj: files, // 文件列表 | |
| 142 | + F_FIleUrl: fileUrl, // 方案其他文件URL | |
| 143 | + Bz: remark, // 备注 | |
| 144 | + Jj: description // 简介 | |
| 145 | + }, | |
| 146 | + { | |
| 147 | + headers: { | |
| 148 | + 'Authorization': localStorage.getItem('token'), | |
| 149 | + 'Content-Type': 'application/json' | |
| 150 | + } | |
| 151 | + } | |
| 152 | + ); | |
| 153 | + return response.data; | |
| 154 | +}; | |
| 155 | +``` | |
| 156 | + | |
| 157 | +### cURL 示例 | |
| 158 | + | |
| 159 | +```bash | |
| 160 | +# 更新备注和简介 | |
| 161 | +curl -X PUT "http://localhost:2011/api/Extend/lqkdkdjlb/UpdateBillingInfo" \ | |
| 162 | + -H "Authorization: Bearer YOUR_TOKEN" \ | |
| 163 | + -H "Content-Type: application/json" \ | |
| 164 | + -d '{ | |
| 165 | + "id": "759263766553560325", | |
| 166 | + "Bz": "这是备注信息", | |
| 167 | + "Jj": "这是简介信息" | |
| 168 | + }' | |
| 169 | + | |
| 170 | +# 只更新备注 | |
| 171 | +curl -X PUT "http://localhost:2011/api/Extend/lqkdkdjlb/UpdateBillingInfo" \ | |
| 172 | + -H "Authorization: Bearer YOUR_TOKEN" \ | |
| 173 | + -H "Content-Type: application/json" \ | |
| 174 | + -d '{ | |
| 175 | + "id": "759263766553560325", | |
| 176 | + "Bz": "这是备注信息" | |
| 177 | + }' | |
| 178 | + | |
| 179 | +# 只更新简介 | |
| 180 | +curl -X PUT "http://localhost:2011/api/Extend/lqkdkdjlb/UpdateBillingInfo" \ | |
| 181 | + -H "Authorization: Bearer YOUR_TOKEN" \ | |
| 182 | + -H "Content-Type: application/json" \ | |
| 183 | + -d '{ | |
| 184 | + "id": "759263766553560325", | |
| 185 | + "Jj": "这是简介信息" | |
| 186 | + }' | |
| 187 | +``` | |
| 188 | + | |
| 189 | +## 注意事项 | |
| 190 | + | |
| 191 | +1. **服务重启**: 修改代码后需要重启后端服务才能生效 | |
| 192 | +2. **Token获取**: 需要先调用登录接口获取token | |
| 193 | +3. **字段可选**: 所有字段都是可选的,只需要传入要更新的字段即可 | |
| 194 | +4. **至少一个字段**: 必须至少提供一个要更新的字段,否则会返回错误 | |
| 195 | + | |
| 196 | +## 错误码说明 | |
| 197 | + | |
| 198 | +- `200`: 更新成功 | |
| 199 | +- `400`: 参数错误或开单记录不存在 | |
| 200 | +- `500`: 服务器错误 | |
| 201 | + | ... | ... |