Commit 9ec80591acd5b0dd7317dc85419f0869e2c792bb

Authored by “wangming”
1 parent 887ceb49

优化库存使用批量创建接口:库存不足时直接抛出异常;优化批量查询性能;添加实体类描述显示到Swagger;更新项目配置以生成XML注释文件

netcore/src/Infrastructure/NCC/SpecificationDocument/Builders/SpecificationDocumentBuilder.cs
... ... @@ -152,6 +152,9 @@ namespace NCC.SpecificationDocument
152 152 //使得 Swagger 能够正确地显示 Enum 的对应关系
153 153 if (_specificationDocumentSettings.EnableEnumSchemaFilter == true) swaggerGenOptions.SchemaFilter<EnumSchemaFilter>();
154 154  
  155 + // 使得 Swagger 能够显示实体类的描述(从 XML 注释中读取)
  156 + swaggerGenOptions.SchemaFilter<EntityDescriptionSchemaFilter>();
  157 +
155 158 // 支持控制器排序操作
156 159 if (_specificationDocumentSettings.EnableTagsOrderDocumentFilter == true) swaggerGenOptions.DocumentFilter<TagsOrderDocumentFilter>();
157 160  
... ...
netcore/src/Infrastructure/NCC/SpecificationDocument/Filters/EntityDescriptionSchemaFilter.cs 0 → 100644
  1 +using NCC.Dependency;
  2 +using NCC.ConfigurableOptions;
  3 +using Microsoft.OpenApi.Models;
  4 +using Swashbuckle.AspNetCore.SwaggerGen;
  5 +using System;
  6 +using System.Collections.Generic;
  7 +using System.IO;
  8 +using System.Linq;
  9 +using System.Xml.Linq;
  10 +
  11 +namespace NCC.SpecificationDocument
  12 +{
  13 + /// <summary>
  14 + /// 修正 规范化文档实体类描述提示
  15 + /// </summary>
  16 + [SuppressSniffer]
  17 + public class EntityDescriptionSchemaFilter : ISchemaFilter
  18 + {
  19 + /// <summary>
  20 + /// 实现过滤器方法
  21 + /// </summary>
  22 + /// <param name="schema">OpenAPI Schema</param>
  23 + /// <param name="context">Schema 过滤器上下文</param>
  24 + public void Apply(OpenApiSchema schema, SchemaFilterContext context)
  25 + {
  26 + var type = context.Type;
  27 +
  28 + // 只处理项目程序集中的类型
  29 + if (!App.Assemblies.Contains(type.Assembly))
  30 + return;
  31 +
  32 + // 尝试从 XML 注释中获取类型描述
  33 + try
  34 + {
  35 + // 直接使用程序集名称查找 XML 文件
  36 + var assemblyName = type.Assembly.GetName().Name;
  37 + var xmlFileName = $"{assemblyName}.xml";
  38 + var xmlFilePath = Path.Combine(AppContext.BaseDirectory, xmlFileName);
  39 +
  40 + if (File.Exists(xmlFilePath))
  41 + {
  42 + try
  43 + {
  44 + var xmlDoc = XDocument.Load(xmlFilePath);
  45 + var memberName = $"T:{type.FullName}";
  46 + var memberElement = xmlDoc.Descendants("member")
  47 + .FirstOrDefault(m => m.Attribute("name")?.Value == memberName);
  48 +
  49 + if (memberElement != null)
  50 + {
  51 + var summaryElement = memberElement.Element("summary");
  52 + if (summaryElement != null)
  53 + {
  54 + var description = summaryElement.Value.Trim();
  55 + if (!string.IsNullOrEmpty(description))
  56 + {
  57 + schema.Description = description;
  58 + return;
  59 + }
  60 + }
  61 + }
  62 + }
  63 + catch
  64 + {
  65 + // 忽略 XML 解析错误
  66 + }
  67 + }
  68 +
  69 + // 如果直接查找失败,尝试从配置的 XML 注释列表中查找
  70 + var specificationDocumentSettings = App.GetOptions<SpecificationDocumentSettingsOptions>();
  71 + var xmlComments = specificationDocumentSettings?.XmlComments;
  72 + if (xmlComments != null && xmlComments.Any())
  73 + {
  74 + foreach (var xmlComment in xmlComments)
  75 + {
  76 + var assemblyXmlName = xmlComment.EndsWith(".xml") ? xmlComment : $"{xmlComment}.xml";
  77 + var assemblyXmlPath = Path.Combine(AppContext.BaseDirectory, assemblyXmlName);
  78 +
  79 + if (File.Exists(assemblyXmlPath) && assemblyXmlPath != xmlFilePath)
  80 + {
  81 + try
  82 + {
  83 + var xmlDoc = XDocument.Load(assemblyXmlPath);
  84 + var memberName = $"T:{type.FullName}";
  85 + var memberElement = xmlDoc.Descendants("member")
  86 + .FirstOrDefault(m => m.Attribute("name")?.Value == memberName);
  87 +
  88 + if (memberElement != null)
  89 + {
  90 + var summaryElement = memberElement.Element("summary");
  91 + if (summaryElement != null)
  92 + {
  93 + var description = summaryElement.Value.Trim();
  94 + if (!string.IsNullOrEmpty(description))
  95 + {
  96 + schema.Description = description;
  97 + break;
  98 + }
  99 + }
  100 + }
  101 + }
  102 + catch
  103 + {
  104 + // 忽略 XML 解析错误
  105 + }
  106 + }
  107 + }
  108 + }
  109 + }
  110 + catch
  111 + {
  112 + // 忽略配置获取错误
  113 + }
  114 + }
  115 + }
  116 +}
  117 +
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/HealthCoachStatisticsOutput.cs
... ... @@ -66,14 +66,24 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb
66 66 public decimal consumeAmount { get; set; }
67 67  
68 68 /// <summary>
69   - /// 人头 - 统计该健康师在指定时间周期内服务的唯一客户数量(按客户去重
  69 + /// 有效人头 - 统计该健康师在指定时间周期内服务的唯一客户数量(按客户去重,F_HasBilling=1,支持小数
70 70 /// </summary>
71   - public int headCount { get; set; }
  71 + public decimal headCount { get; set; }
72 72  
73 73 /// <summary>
74   - /// 人次 - 统计该健康师在指定时间周期内服务的客户人次(按客户+日期去重,同一客户不同天算多次
  74 + /// 有效人次 - 统计该健康师在指定时间周期内服务的客户人次(按客户+日期去重,F_HasBilling=1,同一客户不同天算多次,支持小数
75 75 /// </summary>
76   - public int personCount { get; set; }
  76 + public decimal personCount { get; set; }
  77 +
  78 + /// <summary>
  79 + /// 无效人头 - 统计该健康师在指定时间周期内服务的唯一客户数量(按客户去重,F_HasBilling=0,支持小数)
  80 + /// </summary>
  81 + public decimal invalidHeadCount { get; set; }
  82 +
  83 + /// <summary>
  84 + /// 无效人次 - 统计该健康师在指定时间周期内服务的客户人次(按客户+日期去重,F_HasBilling=0,同一客户不同天算多次,支持小数)
  85 + /// </summary>
  86 + public decimal invalidPersonCount { get; set; }
77 87  
78 88 /// <summary>
79 89 /// 消耗项目数 - 统计该健康师在指定时间周期内消耗的项目总次数
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqProduct/LqProductCrInput.cs
1 1 using System;
2 2 using System.ComponentModel.DataAnnotations;
  3 +using NCC.Dependency;
3 4  
4 5 namespace NCC.Extend.Entitys.Dto.LqProduct
5 6 {
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/NCC.Extend.Entitys.csproj
... ... @@ -2,9 +2,12 @@
2 2 <PropertyGroup>
3 3 <TargetFramework>net6.0</TargetFramework>
4 4 </PropertyGroup>
5   - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
  5 + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
  6 + <DocumentationFile>bin\Debug\$(AssemblyName).xml</DocumentationFile>
  7 + </PropertyGroup>
  8 + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
6 9 <OutputPath />
7   - <DocumentationFile>bin\Release\NCC.Extend.Entitys.xml</DocumentationFile>
  10 + <DocumentationFile>bin\Release\$(AssemblyName).xml</DocumentationFile>
8 11 </PropertyGroup>
9 12 <ItemGroup>
10 13 <ProjectReference Include="..\..\..\Infrastructure\NCC.Expand.Thirdparty\NCC.Expand.Thirdparty.csproj" />
... ...
netcore/src/Modularity/Extend/NCC.Extend.Interfaces/NCC.Extend.Interfaces.csproj
... ... @@ -3,6 +3,12 @@
3 3 <PropertyGroup>
4 4 <TargetFramework>net6.0</TargetFramework>
5 5 </PropertyGroup>
  6 + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
  7 + <DocumentationFile>bin\Debug\$(AssemblyName).xml</DocumentationFile>
  8 + </PropertyGroup>
  9 + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  10 + <DocumentationFile>bin\Release\$(AssemblyName).xml</DocumentationFile>
  11 + </PropertyGroup>
6 12  
7 13 <ItemGroup>
8 14 <ProjectReference Include="..\NCC.Extend.Entitys\NCC.Extend.Entitys.csproj" />
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqInventoryService.cs
... ... @@ -399,9 +399,7 @@ namespace NCC.Extend
399 399 throw NCCException.Oh("库存ID不能为空");
400 400 }
401 401  
402   - var inventory = await _db.Queryable<LqInventoryEntity>()
403   - .Where(x => x.Id == id && x.IsEffective == StatusEnum.有效.GetHashCode())
404   - .FirstAsync();
  402 + var inventory = await _db.Queryable<LqInventoryEntity>().Where(x => x.Id == id && x.IsEffective == StatusEnum.有效.GetHashCode()).FirstAsync();
405 403  
406 404 if (inventory == null)
407 405 {
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
... ... @@ -166,71 +166,59 @@ namespace NCC.Extend
166 166 }
167 167  
168 168 // 生成批次ID(如果未提供)
169   - var batchId = string.IsNullOrWhiteSpace(input.BatchId)
170   - ? YitIdHelper.NextId().ToString()
171   - : input.BatchId;
172   -
  169 + var batchId = string.IsNullOrWhiteSpace(input.BatchId) ? YitIdHelper.NextId().ToString() : input.BatchId;
173 170 var successIds = new List<string>();
174   - var failItems = new List<BatchCreateFailItem>();
175 171  
176   - _db.Ado.BeginTran();
  172 + // 按产品ID分组,批量验证库存(在事务外先检查,避免不必要的回滚)
  173 + var productGroups = input.UsageItems.Select((item, index) => new { Item = item, Index = index }).GroupBy(x => x.Item.ProductId).ToList();
177 174  
178   - try
179   - {
180   - // 按产品ID分组,批量验证库存
181   - var productGroups = input.UsageItems
182   - .Select((item, index) => new { Item = item, Index = index })
183   - .GroupBy(x => x.Item.ProductId)
184   - .ToList();
185   -
186   - // 计算每个产品的总需求并检查库存
187   - foreach (var productGroup in productGroups)
188   - {
189   - var productId = productGroup.Key;
190   - var totalRequired = productGroup.Sum(x => x.Item.UsageQuantity);
  175 + // 获取所有需要检查的产品ID
  176 + var productIds = productGroups.Select(x => x.Key).Distinct().ToList();
191 177  
192   - // 计算该产品的总库存数量
193   - var totalInventory = await _db.Queryable<LqInventoryEntity>()
194   - .Where(x => x.ProductId == productId && x.IsEffective == StatusEnum.有效.GetHashCode())
195   - .SumAsync(x => (int?)x.Quantity) ?? 0;
  178 + // 批量查询所有产品的库存信息(总库存)
  179 + var inventoryList = await _db.Queryable<LqInventoryEntity>().Where(x => productIds.Contains(x.ProductId) && x.IsEffective == StatusEnum.有效.GetHashCode()).GroupBy(x => x.ProductId).Select(x => new { ProductId = x.ProductId, TotalInventory = SqlFunc.AggregateSum(x.Quantity) }).ToListAsync();
  180 + var inventoryMap = inventoryList.ToDictionary(x => x.ProductId, x => Convert.ToInt32(x.TotalInventory));
196 181  
197   - // 计算该产品的已使用数量
198   - var totalUsage = await _db.Queryable<LqInventoryUsageEntity>()
199   - .Where(x => x.ProductId == productId && x.IsEffective == StatusEnum.有效.GetHashCode())
200   - .SumAsync(x => (int?)x.UsageQuantity) ?? 0;
  182 + // 批量查询所有产品的已使用数量
  183 + var usageList = await _db.Queryable<LqInventoryUsageEntity>().Where(x => productIds.Contains(x.ProductId) && x.IsEffective == StatusEnum.有效.GetHashCode()).GroupBy(x => x.ProductId).Select(x => new { ProductId = x.ProductId, TotalUsage = SqlFunc.AggregateSum(x.UsageQuantity) }).ToListAsync();
  184 + var usageMap = usageList.ToDictionary(x => x.ProductId, x => Convert.ToInt32(x.TotalUsage));
201 185  
202   - // 计算可用库存
203   - var availableInventory = totalInventory - totalUsage;
  186 + // 批量查询所有产品的名称
  187 + var productDict = await _db.Queryable<LqProductEntity>()
  188 + .Where(x => productIds.Contains(x.Id))
  189 + .Select(x => new { x.Id, x.ProductName })
  190 + .ToListAsync();
  191 + var productNameMap = productDict.ToDictionary(x => x.Id, x => x.ProductName ?? "未知产品");
204 192  
205   - // 检查库存是否足够
206   - if (availableInventory < totalRequired)
207   - {
208   - var failIndices = productGroup.Select(x => x.Index).ToList();
209   -
210   - foreach (var index in failIndices)
211   - {
212   - failItems.Add(new BatchCreateFailItem
213   - {
214   - Index = index,
215   - ProductId = productId,
216   - Reason = $"库存不足,当前可用库存:{availableInventory},需要数量:{totalRequired}"
217   - });
218   - }
219   - }
  193 + // 检查每个产品的库存
  194 + foreach (var productGroup in productGroups)
  195 + {
  196 + var productId = productGroup.Key;
  197 + var totalRequired = productGroup.Sum(x => x.Item.UsageQuantity);
  198 +
  199 + // 从字典中获取库存信息
  200 + var totalInventory = inventoryMap.GetValueOrDefault(productId, 0);
  201 + var totalUsage = usageMap.GetValueOrDefault(productId, 0);
  202 + var availableInventory = totalInventory - totalUsage;
  203 +
  204 + // 检查库存是否足够,如果不足则直接抛出异常
  205 + if (availableInventory < totalRequired)
  206 + {
  207 + var productName = productNameMap.GetValueOrDefault(productId, "未知产品");
  208 + throw NCCException.Oh($"产品【{productName}】(ID: {productId}) 库存不足,当前可用库存:{availableInventory},需要数量:{totalRequired}");
220 209 }
  210 + }
  211 +
  212 + _db.Ado.BeginTran();
221 213  
222   - // 创建成功的使用记录
  214 + try
  215 + {
  216 + // 创建使用记录
223 217 var entitiesToInsert = new List<LqInventoryUsageEntity>();
224 218 for (int i = 0; i < input.UsageItems.Count; i++)
225 219 {
226 220 var item = input.UsageItems[i];
227 221  
228   - // 跳过失败项
229   - if (failItems.Any(x => x.Index == i))
230   - {
231   - continue;
232   - }
233   -
234 222 var usageEntity = new LqInventoryUsageEntity
235 223 {
236 224 Id = YitIdHelper.NextId().ToString(),
... ... @@ -265,9 +253,9 @@ namespace NCC.Extend
265 253 {
266 254 BatchId = batchId,
267 255 SuccessCount = successIds.Count,
268   - FailCount = failItems.Count,
  256 + FailCount = 0,
269 257 SuccessIds = successIds,
270   - FailItems = failItems
  258 + FailItems = new List<BatchCreateFailItem>()
271 259 };
272 260 }
273 261 catch
... ... @@ -346,35 +334,34 @@ namespace NCC.Extend
346 334 var sidx = input.sidx == null ? "id" : input.sidx;
347 335  
348 336 // 查询使用记录信息,关联产品表
349   - var data = await _db.Queryable<LqInventoryUsageEntity, LqProductEntity>(
350   - (usage, product) => usage.ProductId == product.Id)
351   - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (usage, product) => usage.ProductId == input.ProductId)
352   - .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (usage, product) => usage.StoreId == input.StoreId)
353   - .WhereIF(input.UsageStartTime.HasValue, (usage, product) => usage.UsageTime >= input.UsageStartTime.Value)
354   - .WhereIF(input.UsageEndTime.HasValue, (usage, product) => usage.UsageTime <= input.UsageEndTime.Value)
355   - .WhereIF(!string.IsNullOrWhiteSpace(input.RelatedConsumeId), (usage, product) => usage.RelatedConsumeId == input.RelatedConsumeId)
356   - .WhereIF(!string.IsNullOrWhiteSpace(input.UsageBatchId), (usage, product) => usage.UsageBatchId == input.UsageBatchId)
357   - .WhereIF(input.IsEffective.HasValue, (usage, product) => usage.IsEffective == input.IsEffective.Value)
358   - .Select((usage, product) => new LqInventoryUsageListOutput
  337 + var data = await _db.Queryable<LqInventoryUsageEntity, LqProductEntity>((u, product) => u.ProductId == product.Id)
  338 + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (u, product) => u.ProductId == input.ProductId)
  339 + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (u, product) => u.StoreId == input.StoreId)
  340 + .WhereIF(input.UsageStartTime.HasValue, (u, product) => u.UsageTime >= input.UsageStartTime.Value)
  341 + .WhereIF(input.UsageEndTime.HasValue, (u, product) => u.UsageTime <= input.UsageEndTime.Value)
  342 + .WhereIF(!string.IsNullOrWhiteSpace(input.RelatedConsumeId), (u, product) => u.RelatedConsumeId == input.RelatedConsumeId)
  343 + .WhereIF(!string.IsNullOrWhiteSpace(input.UsageBatchId), (u, product) => u.UsageBatchId == input.UsageBatchId)
  344 + .WhereIF(input.IsEffective.HasValue, (u, product) => u.IsEffective == input.IsEffective.Value)
  345 + .Select((u, product) => new LqInventoryUsageListOutput
359 346 {
360   - id = usage.Id,
361   - productId = usage.ProductId,
  347 + id = u.Id,
  348 + productId = u.ProductId,
362 349 productName = product.ProductName,
363 350 productCategory = product.ProductCategory,
364 351 productPrice = product.Price,
365   - storeId = usage.StoreId,
366   - storeName = SqlFunc.Subqueryable<LqMdxxEntity>().Where(u => u.Id == usage.StoreId).Select(u => u.Dm),
367   - usageTime = usage.UsageTime,
368   - usageQuantity = usage.UsageQuantity,
369   - relatedConsumeId = usage.RelatedConsumeId,
370   - usageBatchId = usage.UsageBatchId,
371   - createUser = usage.CreateUser,
  352 + storeId = u.StoreId,
  353 + storeName = SqlFunc.Subqueryable<LqMdxxEntity>().Where(store => store.Id == u.StoreId).Select(store => store.Dm),
  354 + usageTime = u.UsageTime,
  355 + usageQuantity = u.UsageQuantity,
  356 + relatedConsumeId = u.RelatedConsumeId,
  357 + usageBatchId = u.UsageBatchId,
  358 + createUser = u.CreateUser,
372 359 createUserName = "",
373   - createTime = usage.CreateTime,
374   - updateUser = usage.UpdateUser,
  360 + createTime = u.CreateTime,
  361 + updateUser = u.UpdateUser,
375 362 updateUserName = "",
376   - updateTime = usage.UpdateTime,
377   - isEffective = usage.IsEffective
  363 + updateTime = u.UpdateTime,
  364 + isEffective = u.IsEffective
378 365 })
379 366 .MergeTable()
380 367 .OrderBy(sidx + " " + input.sort)
... ... @@ -460,29 +447,29 @@ namespace NCC.Extend
460 447  
461 448 // 查询该批次的所有使用记录
462 449 var usageRecords = await _db.Queryable<LqInventoryUsageEntity, LqProductEntity>(
463   - (usage, product) => usage.ProductId == product.Id)
464   - .LeftJoin<LqMdxxEntity>((usage, product, store) => usage.StoreId == store.Id)
465   - .Where((usage, product, store) => usage.UsageBatchId == batchId)
466   - .Select((usage, product, store) => new LqInventoryUsageListOutput
  450 + (u, product) => u.ProductId == product.Id)
  451 + .LeftJoin<LqMdxxEntity>((u, product, store) => u.StoreId == store.Id)
  452 + .Where((u, product, store) => u.UsageBatchId == batchId)
  453 + .Select((u, product, store) => new LqInventoryUsageListOutput
467 454 {
468   - id = usage.Id,
469   - productId = usage.ProductId,
  455 + id = u.Id,
  456 + productId = u.ProductId,
470 457 productName = product.ProductName,
471 458 productCategory = product.ProductCategory,
472 459 productPrice = product.Price,
473   - storeId = usage.StoreId,
  460 + storeId = u.StoreId,
474 461 storeName = store.Dm,
475   - usageTime = usage.UsageTime,
476   - usageQuantity = usage.UsageQuantity,
477   - relatedConsumeId = usage.RelatedConsumeId,
478   - usageBatchId = usage.UsageBatchId,
479   - createUser = usage.CreateUser,
  462 + usageTime = u.UsageTime,
  463 + usageQuantity = u.UsageQuantity,
  464 + relatedConsumeId = u.RelatedConsumeId,
  465 + usageBatchId = u.UsageBatchId,
  466 + createUser = u.CreateUser,
480 467 createUserName = "",
481   - createTime = usage.CreateTime,
482   - updateUser = usage.UpdateUser,
  468 + createTime = u.CreateTime,
  469 + updateUser = u.UpdateUser,
483 470 updateUserName = "",
484   - updateTime = usage.UpdateTime,
485   - isEffective = usage.IsEffective
  471 + updateTime = u.UpdateTime,
  472 + isEffective = u.IsEffective
486 473 })
487 474 .MergeTable()
488 475 .OrderBy("createTime")
... ... @@ -563,23 +550,23 @@ namespace NCC.Extend
563 550 try
564 551 {
565 552 var data = await _db.Queryable<LqInventoryUsageEntity>()
566   - .LeftJoin<LqProductEntity>((usage, product) => usage.ProductId == product.Id)
567   - .Where((usage, product) => usage.UsageTime >= input.StartTime && usage.UsageTime <= input.EndTime)
568   - .Where((usage, product) => usage.IsEffective == StatusEnum.有效.GetHashCode())
569   - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (usage, product) => usage.ProductId == input.ProductId)
570   - .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (usage, product) => usage.StoreId == input.StoreId)
571   - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductCategory), (usage, product) => product.ProductCategory == input.ProductCategory)
572   - .GroupBy((usage, product) => new { usage.ProductId, product.ProductName, product.ProductCategory, product.Price })
573   - .Select((usage, product) => new ProductUsageStatisticsOutput
  553 + .LeftJoin<LqProductEntity>((u, product) => u.ProductId == product.Id)
  554 + .Where((u, product) => u.UsageTime >= input.StartTime && u.UsageTime <= input.EndTime)
  555 + .Where((u, product) => u.IsEffective == StatusEnum.有效.GetHashCode())
  556 + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (u, product) => u.ProductId == input.ProductId)
  557 + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (u, product) => u.StoreId == input.StoreId)
  558 + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductCategory), (u, product) => product.ProductCategory == input.ProductCategory)
  559 + .GroupBy((u, product) => new { u.ProductId, product.ProductName, product.ProductCategory, product.Price })
  560 + .Select((u, product) => new ProductUsageStatisticsOutput
574 561 {
575   - ProductId = usage.ProductId,
  562 + ProductId = u.ProductId,
576 563 ProductName = product.ProductName,
577 564 ProductCategory = product.ProductCategory,
578 565 ProductPrice = product.Price,
579   - TotalUsageQuantity = SqlFunc.AggregateSum(usage.UsageQuantity),
580   - TotalUsageAmount = SqlFunc.AggregateSum(usage.UsageQuantity * product.Price),
581   - UsageCount = SqlFunc.AggregateCount(usage.Id),
582   - AverageUsageQuantity = SqlFunc.AggregateAvg(usage.UsageQuantity)
  566 + TotalUsageQuantity = SqlFunc.AggregateSum(u.UsageQuantity),
  567 + TotalUsageAmount = SqlFunc.AggregateSum(u.UsageQuantity * product.Price),
  568 + UsageCount = SqlFunc.AggregateCount(u.Id),
  569 + AverageUsageQuantity = SqlFunc.AggregateAvg(u.UsageQuantity)
583 570 })
584 571 .ToListAsync();
585 572  
... ... @@ -611,22 +598,22 @@ namespace NCC.Extend
611 598 try
612 599 {
613 600 var data = await _db.Queryable<LqInventoryUsageEntity>()
614   - .LeftJoin<LqProductEntity>((usage, product) => usage.ProductId == product.Id)
615   - .LeftJoin<LqMdxxEntity>((usage, product, store) => usage.StoreId == store.Id)
616   - .Where((usage, product, store) => usage.UsageTime >= input.StartTime && usage.UsageTime <= input.EndTime)
617   - .Where((usage, product, store) => usage.IsEffective == StatusEnum.有效.GetHashCode())
618   - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (usage, product, store) => usage.ProductId == input.ProductId)
619   - .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (usage, product, store) => usage.StoreId == input.StoreId)
620   - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductCategory), (usage, product, store) => product.ProductCategory == input.ProductCategory)
621   - .GroupBy((usage, product, store) => new { usage.StoreId, store.Dm })
622   - .Select((usage, product, store) => new StoreUsageStatisticsOutput
  601 + .LeftJoin<LqProductEntity>((u, product) => u.ProductId == product.Id)
  602 + .LeftJoin<LqMdxxEntity>((u, product, store) => u.StoreId == store.Id)
  603 + .Where((u, product, store) => u.UsageTime >= input.StartTime && u.UsageTime <= input.EndTime)
  604 + .Where((u, product, store) => u.IsEffective == StatusEnum.有效.GetHashCode())
  605 + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (u, product, store) => u.ProductId == input.ProductId)
  606 + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (u, product, store) => u.StoreId == input.StoreId)
  607 + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductCategory), (u, product, store) => product.ProductCategory == input.ProductCategory)
  608 + .GroupBy((u, product, store) => new { u.StoreId, store.Dm })
  609 + .Select((u, product, store) => new StoreUsageStatisticsOutput
623 610 {
624   - StoreId = usage.StoreId,
  611 + StoreId = u.StoreId,
625 612 StoreName = store.Dm,
626   - TotalUsageQuantity = SqlFunc.AggregateSum(usage.UsageQuantity),
627   - TotalUsageAmount = SqlFunc.AggregateSum(usage.UsageQuantity * product.Price),
628   - UsageCount = SqlFunc.AggregateCount(usage.Id),
629   - ProductVarietyCount = SqlFunc.AggregateCount(usage.ProductId)
  613 + TotalUsageQuantity = SqlFunc.AggregateSum(u.UsageQuantity),
  614 + TotalUsageAmount = SqlFunc.AggregateSum(u.UsageQuantity * product.Price),
  615 + UsageCount = SqlFunc.AggregateCount(u.Id),
  616 + ProductVarietyCount = SqlFunc.AggregateCount(u.ProductId)
630 617 })
631 618 .ToListAsync();
632 619  
... ... @@ -659,18 +646,18 @@ namespace NCC.Extend
659 646 {
660 647 // 先获取基础数据
661 648 var baseData = await _db.Queryable<LqInventoryUsageEntity>()
662   - .LeftJoin<LqProductEntity>((usage, product) => usage.ProductId == product.Id)
663   - .Where((usage, product) => usage.UsageTime >= input.StartTime && usage.UsageTime <= input.EndTime)
664   - .Where((usage, product) => usage.IsEffective == StatusEnum.有效.GetHashCode())
665   - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (usage, product) => usage.ProductId == input.ProductId)
666   - .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (usage, product) => usage.StoreId == input.StoreId)
667   - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductCategory), (usage, product) => product.ProductCategory == input.ProductCategory)
668   - .Select((usage, product) => new
  649 + .LeftJoin<LqProductEntity>((u, product) => u.ProductId == product.Id)
  650 + .Where((u, product) => u.UsageTime >= input.StartTime && u.UsageTime <= input.EndTime)
  651 + .Where((u, product) => u.IsEffective == StatusEnum.有效.GetHashCode())
  652 + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (u, product) => u.ProductId == input.ProductId)
  653 + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (u, product) => u.StoreId == input.StoreId)
  654 + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductCategory), (u, product) => product.ProductCategory == input.ProductCategory)
  655 + .Select((u, product) => new
669 656 {
670   - UsageTime = usage.UsageTime,
671   - UsageQuantity = usage.UsageQuantity,
672   - UsageAmount = usage.UsageQuantity * product.Price,
673   - ProductId = usage.ProductId
  657 + UsageTime = u.UsageTime,
  658 + UsageQuantity = u.UsageQuantity,
  659 + UsageAmount = u.UsageQuantity * product.Price,
  660 + ProductId = u.ProductId
674 661 })
675 662 .ToListAsync();
676 663  
... ... @@ -740,22 +727,22 @@ namespace NCC.Extend
740 727 try
741 728 {
742 729 var data = await _db.Queryable<LqInventoryUsageEntity>()
743   - .LeftJoin<LqProductEntity>((usage, product) => usage.ProductId == product.Id)
744   - .Where((usage, product) => usage.UsageTime >= input.StartTime && usage.UsageTime <= input.EndTime)
745   - .Where((usage, product) => usage.IsEffective == StatusEnum.有效.GetHashCode())
746   - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (usage, product) => usage.ProductId == input.ProductId)
747   - .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (usage, product) => usage.StoreId == input.StoreId)
748   - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductCategory), (usage, product) => product.ProductCategory == input.ProductCategory)
749   - .GroupBy((usage, product) => new { usage.ProductId, product.ProductName, product.ProductCategory })
750   - .Select((usage, product) => new ProductUsageRankingOutput
  730 + .LeftJoin<LqProductEntity>((u, product) => u.ProductId == product.Id)
  731 + .Where((u, product) => u.UsageTime >= input.StartTime && u.UsageTime <= input.EndTime)
  732 + .Where((u, product) => u.IsEffective == StatusEnum.有效.GetHashCode())
  733 + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (u, product) => u.ProductId == input.ProductId)
  734 + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (u, product) => u.StoreId == input.StoreId)
  735 + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductCategory), (u, product) => product.ProductCategory == input.ProductCategory)
  736 + .GroupBy((u, product) => new { u.ProductId, product.ProductName, product.ProductCategory })
  737 + .Select((u, product) => new ProductUsageRankingOutput
751 738 {
752   - ProductId = usage.ProductId,
  739 + ProductId = u.ProductId,
753 740 ProductName = product.ProductName,
754 741 ProductCategory = product.ProductCategory,
755   - TotalUsageQuantity = SqlFunc.AggregateSum(usage.UsageQuantity),
756   - TotalUsageAmount = SqlFunc.AggregateSum(usage.UsageQuantity * product.Price),
757   - UsageCount = SqlFunc.AggregateCount(usage.Id),
758   - StoreCount = SqlFunc.AggregateCount(usage.StoreId)
  742 + TotalUsageQuantity = SqlFunc.AggregateSum(u.UsageQuantity),
  743 + TotalUsageAmount = SqlFunc.AggregateSum(u.UsageQuantity * product.Price),
  744 + UsageCount = SqlFunc.AggregateCount(u.Id),
  745 + StoreCount = SqlFunc.AggregateCount(u.StoreId)
759 746 })
760 747 .OrderBy("TotalUsageQuantity desc")
761 748 .Take(input.RankingCount)
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
... ... @@ -2549,7 +2549,8 @@ namespace NCC.Extend.LqKdKdjlb
2549 2549 totalPrice = it.TotalPrice,
2550 2550 actualPrice = it.ActualPrice,
2551 2551 projectNumber = it.ProjectNumber,
2552   - remark = it.Remark
  2552 + remark = it.Remark,
  2553 + itemCategory = it.ItemCategory,
2553 2554 })
2554 2555 .ToListAsync();
2555 2556  
... ... @@ -2596,7 +2597,8 @@ namespace NCC.Extend.LqKdKdjlb
2596 2597 totalPrice = x.totalPrice,
2597 2598 actualPrice = x.actualPrice,
2598 2599 projectNumber = x.projectNumber,
2599   - remark = x.remark
  2600 + remark = x.remark,
  2601 + itemCategory = x.itemCategory,
2600 2602 }).ToList(),
2601 2603  
2602 2604 giftedItems = itemDetails.Where(x => x.glkdbh == billing.id && x.sourceType == "赠送").Select(x => new
... ... @@ -2608,7 +2610,8 @@ namespace NCC.Extend.LqKdKdjlb
2608 2610 totalPrice = x.totalPrice,
2609 2611 actualPrice = x.actualPrice,
2610 2612 projectNumber = x.projectNumber,
2611   - remark = x.remark
  2613 + remark = x.remark,
  2614 + itemCategory = x.itemCategory,
2612 2615 }).ToList(),
2613 2616  
2614 2617 experienceItems = itemDetails.Where(x => x.glkdbh == billing.id && x.sourceType == "体验").Select(x => new
... ... @@ -2620,7 +2623,8 @@ namespace NCC.Extend.LqKdKdjlb
2620 2623 totalPrice = x.totalPrice,
2621 2624 actualPrice = x.actualPrice,
2622 2625 projectNumber = x.projectNumber,
2623   - remark = x.remark
  2626 + remark = x.remark,
  2627 + itemCategory = x.itemCategory,
2624 2628 }).ToList(),
2625 2629  
2626 2630 // 金额信息
... ... @@ -2670,7 +2674,6 @@ namespace NCC.Extend.LqKdKdjlb
2670 2674 },
2671 2675 message = "获取开单记录汇总信息成功"
2672 2676 };
2673   -
2674 2677 return result;
2675 2678 }
2676 2679 catch (Exception ex)
... ... @@ -3210,8 +3213,10 @@ namespace NCC.Extend.LqKdKdjlb
3210 3213  
3211 3214 -- 消耗相关统计
3212 3215 COALESCE(consume_stats.ConsumeAmount, 0) as ConsumeAmount,
3213   - COALESCE(consume_stats.HeadCount, 0) as HeadCount,
3214   - COALESCE(consume_stats.PersonCount, 0) as PersonCount,
  3216 + CAST(COALESCE(headcount_stats.HeadCount, 0) AS DECIMAL(18,2)) as HeadCount,
  3217 + CAST(COALESCE(personcount_stats.PersonCount, 0) AS DECIMAL(18,2)) as PersonCount,
  3218 + CAST(COALESCE(invalid_headcount_stats.HeadCount, 0) AS DECIMAL(18,2)) as InvalidHeadCount,
  3219 + CAST(COALESCE(invalid_personcount_stats.PersonCount, 0) AS DECIMAL(18,2)) as InvalidPersonCount,
3215 3220 CAST(COALESCE(consume_stats.ProjectCount, 0) AS DECIMAL(18,2)) as ProjectCount
3216 3221  
3217 3222 FROM BASE_USER u
... ... @@ -3274,8 +3279,6 @@ namespace NCC.Extend.LqKdKdjlb
3274 3279 SELECT
3275 3280 jksyj.jkszh as EmployeeId,
3276 3281 SUM(jksyj.jksyj) as ConsumeAmount,
3277   - COUNT(DISTINCT hyhk.hy) as HeadCount,
3278   - COUNT(DISTINCT CONCAT(jksyj.jkszh, '_', hyhk.hy, '_', DATE(hyhk.hksj))) as PersonCount,
3279 3282 CAST(SUM(jksyj.F_kdpxNumber) AS DECIMAL(18,2)) as ProjectCount
3280 3283 FROM lq_xh_jksyj jksyj
3281 3284 INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
... ... @@ -3287,6 +3290,98 @@ namespace NCC.Extend.LqKdKdjlb
3287 3290 GROUP BY jksyj.jkszh
3288 3291 ) consume_stats ON u.F_Id = consume_stats.EmployeeId
3289 3292  
  3293 + -- 有效人头统计子查询(从人次记录表获取,按月份+客户+数量去重后累加数量,F_HasBilling=1)
  3294 + LEFT JOIN (
  3295 + SELECT
  3296 + F_PersonId as EmployeeId,
  3297 + CAST(COALESCE(SUM(F_Quantity), 0) AS DECIMAL(18,2)) as HeadCount
  3298 + FROM (
  3299 + SELECT
  3300 + F_PersonId,
  3301 + F_WorkMonth,
  3302 + F_MemberId,
  3303 + F_Quantity
  3304 + FROM lq_person_times_record
  3305 + WHERE F_PersonId IS NOT NULL
  3306 + AND F_IsEffective = 1
  3307 + AND F_PersonType = '健康师'
  3308 + AND F_HasBilling = 1
  3309 + AND F_WorkDate >= DATE(@startTime)
  3310 + AND F_WorkDate <= DATE(@endTime)
  3311 + GROUP BY F_PersonId, F_WorkMonth, F_MemberId, F_Quantity
  3312 + ) as distinct_headcount
  3313 + GROUP BY F_PersonId
  3314 + ) headcount_stats ON u.F_Id = headcount_stats.EmployeeId
  3315 +
  3316 + -- 有效人次统计子查询(从人次记录表获取,按日期+客户+数量去重后累加数量,F_HasBilling=1)
  3317 + LEFT JOIN (
  3318 + SELECT
  3319 + F_PersonId as EmployeeId,
  3320 + CAST(COALESCE(SUM(F_Quantity), 0) AS DECIMAL(18,2)) as PersonCount
  3321 + FROM (
  3322 + SELECT
  3323 + F_PersonId,
  3324 + F_WorkDate,
  3325 + F_MemberId,
  3326 + F_Quantity
  3327 + FROM lq_person_times_record
  3328 + WHERE F_PersonId IS NOT NULL
  3329 + AND F_IsEffective = 1
  3330 + AND F_PersonType = '健康师'
  3331 + AND F_HasBilling = 1
  3332 + AND F_WorkDate >= DATE(@startTime)
  3333 + AND F_WorkDate <= DATE(@endTime)
  3334 + GROUP BY F_PersonId, F_WorkDate, F_MemberId, F_Quantity
  3335 + ) as distinct_personcount
  3336 + GROUP BY F_PersonId
  3337 + ) personcount_stats ON u.F_Id = personcount_stats.EmployeeId
  3338 +
  3339 + -- 无效人头统计子查询(从人次记录表获取,按月份+客户+数量去重后累加数量,F_HasBilling=0)
  3340 + LEFT JOIN (
  3341 + SELECT
  3342 + F_PersonId as EmployeeId,
  3343 + CAST(COALESCE(SUM(F_Quantity), 0) AS DECIMAL(18,2)) as HeadCount
  3344 + FROM (
  3345 + SELECT
  3346 + F_PersonId,
  3347 + F_WorkMonth,
  3348 + F_MemberId,
  3349 + F_Quantity
  3350 + FROM lq_person_times_record
  3351 + WHERE F_PersonId IS NOT NULL
  3352 + AND F_IsEffective = 1
  3353 + AND F_PersonType = '健康师'
  3354 + AND F_HasBilling = 0
  3355 + AND F_WorkDate >= DATE(@startTime)
  3356 + AND F_WorkDate <= DATE(@endTime)
  3357 + GROUP BY F_PersonId, F_WorkMonth, F_MemberId, F_Quantity
  3358 + ) as distinct_headcount
  3359 + GROUP BY F_PersonId
  3360 + ) invalid_headcount_stats ON u.F_Id = invalid_headcount_stats.EmployeeId
  3361 +
  3362 + -- 无效人次统计子查询(从人次记录表获取,按日期+客户+数量去重后累加数量,F_HasBilling=0)
  3363 + LEFT JOIN (
  3364 + SELECT
  3365 + F_PersonId as EmployeeId,
  3366 + CAST(COALESCE(SUM(F_Quantity), 0) AS DECIMAL(18,2)) as PersonCount
  3367 + FROM (
  3368 + SELECT
  3369 + F_PersonId,
  3370 + F_WorkDate,
  3371 + F_MemberId,
  3372 + F_Quantity
  3373 + FROM lq_person_times_record
  3374 + WHERE F_PersonId IS NOT NULL
  3375 + AND F_IsEffective = 1
  3376 + AND F_PersonType = '健康师'
  3377 + AND F_HasBilling = 0
  3378 + AND F_WorkDate >= DATE(@startTime)
  3379 + AND F_WorkDate <= DATE(@endTime)
  3380 + GROUP BY F_PersonId, F_WorkDate, F_MemberId, F_Quantity
  3381 + ) as distinct_personcount
  3382 + GROUP BY F_PersonId
  3383 + ) invalid_personcount_stats ON u.F_Id = invalid_personcount_stats.EmployeeId
  3384 +
3290 3385 WHERE u.F_GW = '健康师'
3291 3386 ";
3292 3387  
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqProductService.cs
... ... @@ -228,7 +228,7 @@ namespace NCC.Extend
228 228 price = x.Price,
229 229 productCategory = x.ProductCategory,
230 230 departmentId = x.DepartmentId,
231   - departmentName = "",
  231 + departmentName = SqlFunc.Subqueryable<OrganizeEntity>().Where(y => y.Id == x.DepartmentId).Select(y => y.FullName),
232 232 standardUnit = x.StandardUnit,
233 233 onShelfStatus = x.OnShelfStatus,
234 234 statisticsCategory = x.StatisticsCategory,
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqPurchaseRecordsService.cs
... ... @@ -28,7 +28,7 @@ namespace NCC.Extend.LqPurchaseRecords
28 28 /// <summary>
29 29 /// 购买记录表服务
30 30 /// </summary>
31   - [ApiDescriptionSettings(Tag = "Extend",Name = "LqPurchaseRecords", Order = 200)]
  31 + [ApiDescriptionSettings(Tag = "Extend", Name = "LqPurchaseRecords", Order = 200)]
32 32 [Route("api/Extend/[controller]")]
33 33 public class LqPurchaseRecordsService : ILqPurchaseRecordsService, IDynamicApiController, ITransient
34 34 {
... ... @@ -43,7 +43,7 @@ namespace NCC.Extend.LqPurchaseRecords
43 43 ISqlSugarRepository<LqPurchaseRecordsEntity> lqPurchaseRecordsRepository,
44 44 IUserManager userManager)
45 45 {
46   - _lqPurchaseRecordsRepository = lqPurchaseRecordsRepository;
  46 + _lqPurchaseRecordsRepository = lqPurchaseRecordsRepository;
47 47 _db = _lqPurchaseRecordsRepository.Context;
48 48 _userManager = userManager;
49 49 }
... ... @@ -98,25 +98,25 @@ namespace NCC.Extend.LqPurchaseRecords
98 98 .WhereIF(queryApproveTime != null, p => p.ApproveTime >= new DateTime(startApproveTime.ToDate().Year, startApproveTime.ToDate().Month, startApproveTime.ToDate().Day, 0, 0, 0))
99 99 .WhereIF(queryApproveTime != null, p => p.ApproveTime <= new DateTime(endApproveTime.ToDate().Year, endApproveTime.ToDate().Month, endApproveTime.ToDate().Day, 23, 59, 59))
100 100 .WhereIF(!string.IsNullOrEmpty(input.applicationId), p => p.ApplicationId.Contains(input.applicationId))
101   - .Select(it=> new LqPurchaseRecordsListOutput
  101 + .Select(it => new LqPurchaseRecordsListOutput
102 102 {
103 103 id = it.Id,
104   - reimbursementCategoryId=it.ReimbursementCategoryId,
105   - reimbursementCategoryName=it.ReimbursementCategoryName,
106   - unitPrice=it.UnitPrice,
107   - quantity=it.Quantity,
108   - amount=it.Amount,
109   - memo=it.Memo,
110   - purchaseTime=it.PurchaseTime,
111   - createTime=it.CreateTime,
112   - createUser=it.CreateUser,
113   - createUserStoreId=it.CreateUserStoreId,
114   - approveStatus=it.ApproveStatus,
115   - approveUser=it.ApproveUser,
116   - approveTime=it.ApproveTime,
117   - applicationId=it.ApplicationId,
118   - }).MergeTable().OrderBy(sidx+" "+input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
119   - return PageResult<LqPurchaseRecordsListOutput>.SqlSugarPageResult(data);
  104 + reimbursementCategoryId = it.ReimbursementCategoryId,
  105 + reimbursementCategoryName = it.ReimbursementCategoryName,
  106 + unitPrice = it.UnitPrice,
  107 + quantity = it.Quantity,
  108 + amount = it.Amount,
  109 + memo = it.Memo,
  110 + purchaseTime = it.PurchaseTime,
  111 + createTime = it.CreateTime,
  112 + createUser = it.CreateUser,
  113 + createUserStoreId = it.CreateUserStoreId,
  114 + approveStatus = it.ApproveStatus,
  115 + approveUser = it.ApproveUser,
  116 + approveTime = it.ApproveTime,
  117 + applicationId = it.ApplicationId,
  118 + }).MergeTable().OrderBy(sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
  119 + return PageResult<LqPurchaseRecordsListOutput>.SqlSugarPageResult(data);
120 120 }
121 121  
122 122 /// <summary>
... ... @@ -171,25 +171,25 @@ namespace NCC.Extend.LqPurchaseRecords
171 171 .WhereIF(queryApproveTime != null, p => p.ApproveTime >= new DateTime(startApproveTime.ToDate().Year, startApproveTime.ToDate().Month, startApproveTime.ToDate().Day, 0, 0, 0))
172 172 .WhereIF(queryApproveTime != null, p => p.ApproveTime <= new DateTime(endApproveTime.ToDate().Year, endApproveTime.ToDate().Month, endApproveTime.ToDate().Day, 23, 59, 59))
173 173 .WhereIF(!string.IsNullOrEmpty(input.applicationId), p => p.ApplicationId.Contains(input.applicationId))
174   - .Select(it=> new LqPurchaseRecordsListOutput
  174 + .Select(it => new LqPurchaseRecordsListOutput
175 175 {
176 176 id = it.Id,
177   - reimbursementCategoryId=it.ReimbursementCategoryId,
178   - reimbursementCategoryName=it.ReimbursementCategoryName,
179   - unitPrice=it.UnitPrice,
180   - quantity=it.Quantity,
181   - amount=it.Amount,
182   - memo=it.Memo,
183   - purchaseTime=it.PurchaseTime,
184   - createTime=it.CreateTime,
185   - createUser=it.CreateUser,
186   - createUserStoreId=it.CreateUserStoreId,
187   - approveStatus=it.ApproveStatus,
188   - approveUser=it.ApproveUser,
189   - approveTime=it.ApproveTime,
190   - applicationId=it.ApplicationId,
191   - }).MergeTable().OrderBy(sidx+" "+input.sort).ToListAsync();
192   - return data;
  177 + reimbursementCategoryId = it.ReimbursementCategoryId,
  178 + reimbursementCategoryName = it.ReimbursementCategoryName,
  179 + unitPrice = it.UnitPrice,
  180 + quantity = it.Quantity,
  181 + amount = it.Amount,
  182 + memo = it.Memo,
  183 + purchaseTime = it.PurchaseTime,
  184 + createTime = it.CreateTime,
  185 + createUser = it.CreateUser,
  186 + createUserStoreId = it.CreateUserStoreId,
  187 + approveStatus = it.ApproveStatus,
  188 + approveUser = it.ApproveUser,
  189 + approveTime = it.ApproveTime,
  190 + applicationId = it.ApplicationId,
  191 + }).MergeTable().OrderBy(sidx + " " + input.sort).ToListAsync();
  192 + return data;
193 193 }
194 194  
195 195 /// <summary>
... ... @@ -211,7 +211,7 @@ namespace NCC.Extend.LqPurchaseRecords
211 211 {
212 212 exportData = await this.GetNoPagingList(input);
213 213 }
214   - List<ParamsModel> paramList = "[{\"value\":\"记录编号\",\"field\":\"id\"},{\"value\":\"购买物品编号\",\"field\":\"reimbursementCategoryId\"},{\"value\":\"购买物品名称\",\"field\":\"reimbursementCategoryName\"},{\"value\":\"单价\",\"field\":\"unitPrice\"},{\"value\":\"数量\",\"field\":\"quantity\"},{\"value\":\"总金额\",\"field\":\"amount\"},{\"value\":\"备注说明\",\"field\":\"memo\"},{\"value\":\"购买时间\",\"field\":\"purchaseTime\"},{\"value\":\"创建时间\",\"field\":\"createTime\"},{\"value\":\"创建人\",\"field\":\"createUser\"},{\"value\":\"创建人门店\",\"field\":\"createUserStoreId\"},{\"value\":\"审批状态\",\"field\":\"approveStatus\"},{\"value\":\"审批人\",\"field\":\"approveUser\"},{\"value\":\"审批时间\",\"field\":\"approveTime\"},{\"value\":\"审批单编号\",\"field\":\"applicationId\"},]".ToList<ParamsModel>();
  214 + List<ParamsModel> paramList = "[{\"value\":\"记录编号\",\"field\":\"id\"},{\"value\":\"购买物品编号\",\"field\":\"reimbursementCategoryId\"},{\"value\":\"购买物品名称\",\"field\":\"reimbursementCategoryName\"},{\"value\":\"单价\",\"field\":\"unitPrice\"},{\"value\":\"数量\",\"field\":\"quantity\"},{\"value\":\"总金额\",\"field\":\"amount\"},{\"value\":\"备注说明\",\"field\":\"memo\"},{\"value\":\"购买时间\",\"field\":\"purchaseTime\"},{\"value\":\"创建时间\",\"field\":\"createTime\"},{\"value\":\"创建人\",\"field\":\"createUser\"},{\"value\":\"创建人门店\",\"field\":\"createUserStoreId\"},{\"value\":\"审批状态\",\"field\":\"approveStatus\"},{\"value\":\"审批人\",\"field\":\"approveUser\"},{\"value\":\"审批时间\",\"field\":\"approveTime\"},{\"value\":\"审批单编号\",\"field\":\"applicationId\"},]".ToList<ParamsModel>();
215 215 ExcelConfig excelconfig = new ExcelConfig();
216 216 excelconfig.FileName = "购买记录表.xls";
217 217 excelconfig.HeadFont = "微软雅黑";
... ... @@ -254,7 +254,7 @@ namespace NCC.Extend.LqPurchaseRecords
254 254 //开启事务
255 255 _db.BeginTran();
256 256 //批量删除购买记录表
257   - await _db.Deleteable<LqPurchaseRecordsEntity>().In(d => d.Id,ids).ExecuteCommandAsync();
  257 + await _db.Deleteable<LqPurchaseRecordsEntity>().In(d => d.Id, ids).ExecuteCommandAsync();
258 258 //关闭事务
259 259 _db.CommitTran();
260 260 }
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs
... ... @@ -3504,6 +3504,7 @@ namespace NCC.Extend.LqStatistics
3504 3504 AND F_PersonType = '健康师'
3505 3505 AND F_WorkMonth = '{month}'
3506 3506 AND F_IsEffective = 1
  3507 + AND F_HasBilling = 1
3507 3508 GROUP BY F_PersonId, F_WorkMonth, F_MemberId, F_Quantity
3508 3509 ) as distinct_records";
3509 3510  
... ... @@ -3531,7 +3532,8 @@ namespace NCC.Extend.LqStatistics
3531 3532 WHERE F_PersonId = '{userId}'
3532 3533 AND F_PersonType = '健康师'
3533 3534 AND F_WorkMonth = '{month}'
3534   - AND F_IsEffective = 1
  3535 + AND F_IsEffective = 1
  3536 + AND F_HasBilling = 1
3535 3537 GROUP BY F_PersonId, F_WorkDate, F_MemberId, F_Quantity
3536 3538 ) as distinct_records";
3537 3539  
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
... ... @@ -1757,11 +1757,20 @@ namespace NCC.Extend.LqXhHyhk
1757 1757 var kjbsyjList = await _db.Queryable<LqXhKjbsyjEntity>().Where(x => consumeIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()).ToListAsync();
1758 1758  
1759 1759 // 查询已存在的人次记录(按BusinessId去重,避免重复添加)
1760   - var existingBusinessIds = await _db.Queryable<LqPersonTimesRecordEntity>()
1761   - .Where(x => consumeIds.Contains(x.BusinessId) && x.BusinessType == "耗卡" && x.IsEffective == StatusEnum.有效.GetHashCode())
1762   - .Select(x => x.BusinessId)
1763   - .Distinct()
1764   - .ToListAsync();
  1760 + var existingBusinessIds = await _db.Queryable<LqPersonTimesRecordEntity>().Where(x => consumeIds.Contains(x.BusinessId) && x.BusinessType == "耗卡" && x.IsEffective == StatusEnum.有效.GetHashCode()).Select(x => x.BusinessId).Distinct().ToListAsync();
  1761 +
  1762 + // 批量查询所有会员是否有开单记录(优化:避免在循环中执行N次查询)
  1763 + var memberIds = consumeList.Where(x => !string.IsNullOrEmpty(x.Hy)).Select(x => x.Hy).Distinct().ToList();
  1764 + var membersWithBilling = new HashSet<string>();
  1765 + if (memberIds.Any())
  1766 + {
  1767 + var billingMemberIds = await _db.Queryable<LqKdKdjlbEntity>()
  1768 + .Where(x => memberIds.Contains(x.Kdhy) && x.IsEffective == StatusEnum.有效.GetHashCode() && x.Sfyj > 0)
  1769 + .Select(x => x.Kdhy)
  1770 + .Distinct()
  1771 + .ToListAsync();
  1772 + membersWithBilling = new HashSet<string>(billingMemberIds);
  1773 + }
1765 1774  
1766 1775 // 3. 构建人次记录列表
1767 1776 var personTimesRecords = new List<LqPersonTimesRecordEntity>();
... ... @@ -1782,19 +1791,14 @@ namespace NCC.Extend.LqXhHyhk
1782 1791 }
1783 1792 var workDate = consume.Hksj.Value.Date; // 工作日期(用于人次统计)
1784 1793 var workMonth = consume.Hksj.Value.ToString("yyyyMM"); // 工作月份(用于人头统计)
1785   -
  1794 + //查看该会员是否在开单记录表中存在开单记录(从批量查询结果中查找)
  1795 + var billingRecord = !string.IsNullOrEmpty(consume.Hy) && membersWithBilling.Contains(consume.Hy);
1786 1796 // 处理健康师业绩:去重后计算人次数量(剔除T区健康师)
1787   - var consumeJksyjList = jksyjList.Where(x => x.Glkdbh == consume.Id
1788   - && !string.IsNullOrEmpty(x.Jks)
1789   - && !string.IsNullOrEmpty(x.Jksxm)
1790   - && (x.Jksxm == null || !x.Jksxm.Contains("T区"))).ToList();
  1797 + var consumeJksyjList = jksyjList.Where(x => x.Glkdbh == consume.Id && !string.IsNullOrEmpty(x.Jks) && !string.IsNullOrEmpty(x.Jksxm) && (x.Jksxm == null || !x.Jksxm.Contains("T区"))).ToList();
1791 1798 if (consumeJksyjList.Any())
1792 1799 {
1793 1800 // 按健康师ID去重
1794   - var distinctJksyjList = consumeJksyjList
1795   - .GroupBy(x => x.Jks)
1796   - .Select(g => g.First())
1797   - .ToList();
  1801 + var distinctJksyjList = consumeJksyjList.GroupBy(x => x.Jks).Select(g => g.First()).ToList();
1798 1802  
1799 1803 // 计算人次数量:1 / 健康师数量
1800 1804 var jksQuantity = distinctJksyjList.Count > 0 ? 1.0m / distinctJksyjList.Count : 0;
... ... @@ -1815,23 +1819,18 @@ namespace NCC.Extend.LqXhHyhk
1815 1819 WorkMonth = workMonth,
1816 1820 Quantity = jksQuantity,
1817 1821 CreateTime = DateTime.Now,
1818   - IsEffective = StatusEnum.有效.GetHashCode()
  1822 + IsEffective = StatusEnum.有效.GetHashCode(),
  1823 + HasBilling = billingRecord ? 1 : 0
1819 1824 });
1820 1825 }
1821 1826 }
1822 1827  
1823 1828 // 处理科技老师业绩:去重后计算人次数量(剔除T区科技老师)
1824   - var consumeKjbsyjList = kjbsyjList.Where(x => x.Glkdbh == consume.Id
1825   - && !string.IsNullOrEmpty(x.Kjbls)
1826   - && !string.IsNullOrEmpty(x.Kjblsxm)
1827   - && (x.Kjblsxm == null || !x.Kjblsxm.Contains("T区"))).ToList();
  1829 + var consumeKjbsyjList = kjbsyjList.Where(x => x.Glkdbh == consume.Id && !string.IsNullOrEmpty(x.Kjbls) && !string.IsNullOrEmpty(x.Kjblsxm) && (x.Kjblsxm == null || !x.Kjblsxm.Contains("T区"))).ToList();
1828 1830 if (consumeKjbsyjList.Any())
1829 1831 {
1830 1832 // 按科技老师ID去重
1831   - var distinctKjbsyjList = consumeKjbsyjList
1832   - .GroupBy(x => x.Kjbls)
1833   - .Select(g => g.First())
1834   - .ToList();
  1833 + var distinctKjbsyjList = consumeKjbsyjList.GroupBy(x => x.Kjbls).Select(g => g.First()).ToList();
1835 1834  
1836 1835 // 计算人次数量:1 / 科技老师数量
1837 1836 var kjbsQuantity = distinctKjbsyjList.Count > 0 ? 1.0m / distinctKjbsyjList.Count : 0;
... ... @@ -1852,7 +1851,8 @@ namespace NCC.Extend.LqXhHyhk
1852 1851 WorkMonth = workMonth,
1853 1852 Quantity = kjbsQuantity,
1854 1853 CreateTime = DateTime.Now,
1855   - IsEffective = StatusEnum.有效.GetHashCode()
  1854 + IsEffective = StatusEnum.有效.GetHashCode(),
  1855 + HasBilling = billingRecord ? 1 : 0
1856 1856 });
1857 1857 }
1858 1858 }
... ... @@ -1865,9 +1865,7 @@ namespace NCC.Extend.LqXhHyhk
1865 1865 // 如果没有指定耗卡ID,不删除任何记录(因为已经在构建记录列表时跳过了已存在的记录)
1866 1866 if (!string.IsNullOrEmpty(consumeId))
1867 1867 {
1868   - await _db.Deleteable<LqPersonTimesRecordEntity>()
1869   - .Where(x => x.BusinessId == consumeId && x.BusinessType == "耗卡")
1870   - .ExecuteCommandAsync();
  1868 + await _db.Deleteable<LqPersonTimesRecordEntity>().Where(x => x.BusinessId == consumeId && x.BusinessType == "耗卡").ExecuteCommandAsync();
1871 1869 }
1872 1870  
1873 1871 // 批量插入新记录
... ...
sql/分析健康师消耗项目数差异.sql 0 → 100644
  1 +-- ============================================
  2 +-- 分析健康师消耗项目数差异
  3 +-- 员工ID: 18566028067 (李芳)
  4 +-- ============================================
  5 +
  6 +-- 1. 接口统计逻辑(使用耗卡时间,时间范围:2025-11-01 到 2025-11-25 11:55:32)
  7 +SELECT
  8 + jksyj.jkszh as EmployeeId,
  9 + CAST(SUM(jksyj.F_kdpxNumber) AS DECIMAL(18,2)) as ProjectCount_接口逻辑
  10 +FROM lq_xh_jksyj jksyj
  11 +INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  12 +WHERE jksyj.jkszh = '18566028067'
  13 + AND jksyj.F_IsEffective = 1
  14 + AND hyhk.F_IsEffective = 1
  15 + AND hyhk.hksj >= '2025-11-01 00:00:00'
  16 + AND hyhk.hksj <= '2025-11-25 11:55:32'
  17 +GROUP BY jksyj.jkszh;
  18 +
  19 +-- 2. 整个11月的统计(使用业绩时间)
  20 +SELECT
  21 + jksyj.jkszh as EmployeeId,
  22 + CAST(SUM(jksyj.F_kdpxNumber) AS DECIMAL(18,2)) as ProjectCount_整个11月
  23 +FROM lq_xh_jksyj jksyj
  24 +WHERE (jksyj.jks = '18566028067' OR jksyj.jkszh = '18566028067')
  25 + AND jksyj.F_IsEffective = 1
  26 + AND DATE_FORMAT(jksyj.yjsj, '%Y%m') = '202511'
  27 +GROUP BY jksyj.jkszh;
  28 +
  29 +-- 3. 查看11月25日之后的记录(可能导致差异的原因)
  30 +SELECT
  31 + jksyj.jkszh as EmployeeId,
  32 + jksyj.F_kdpxNumber as 项目数,
  33 + jksyj.yjsj as 业绩时间,
  34 + hyhk.hksj as 耗卡时间,
  35 + hyhk.F_IsEffective as 耗卡记录是否有效,
  36 + jksyj.F_IsEffective as 业绩记录是否有效
  37 +FROM lq_xh_jksyj jksyj
  38 +LEFT JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  39 +WHERE (jksyj.jks = '18566028067' OR jksyj.jkszh = '18566028067')
  40 + AND jksyj.F_IsEffective = 1
  41 + AND (
  42 + (jksyj.yjsj >= '2025-11-25 11:55:32' AND jksyj.yjsj < '2025-12-01')
  43 + OR (hyhk.hksj >= '2025-11-25 11:55:32' AND hyhk.hksj < '2025-12-01')
  44 + )
  45 +ORDER BY jksyj.yjsj;
  46 +
  47 +-- 4. 查看耗卡记录无效但业绩记录有效的记录(可能导致差异的原因)
  48 +SELECT
  49 + jksyj.jkszh as EmployeeId,
  50 + jksyj.F_kdpxNumber as 项目数,
  51 + jksyj.yjsj as 业绩时间,
  52 + hyhk.hksj as 耗卡时间,
  53 + hyhk.F_IsEffective as 耗卡记录是否有效,
  54 + jksyj.F_IsEffective as 业绩记录是否有效
  55 +FROM lq_xh_jksyj jksyj
  56 +LEFT JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  57 +WHERE (jksyj.jks = '18566028067' OR jksyj.jkszh = '18566028067')
  58 + AND jksyj.F_IsEffective = 1
  59 + AND (hyhk.F_IsEffective != 1 OR hyhk.F_IsEffective IS NULL)
  60 + AND jksyj.yjsj >= '2025-11-01'
  61 + AND jksyj.yjsj < '2025-12-01'
  62 +ORDER BY jksyj.yjsj;
  63 +
  64 +-- 5. 查看耗卡时间和业绩时间不一致的记录(可能导致差异的原因)
  65 +SELECT
  66 + jksyj.jkszh as EmployeeId,
  67 + jksyj.F_kdpxNumber as 项目数,
  68 + jksyj.yjsj as 业绩时间,
  69 + hyhk.hksj as 耗卡时间,
  70 + DATEDIFF(jksyj.yjsj, hyhk.hksj) as 时间差_天,
  71 + CASE
  72 + WHEN hyhk.hksj >= '2025-11-01 00:00:00' AND hyhk.hksj <= '2025-11-25 11:55:32' THEN '在接口时间范围内'
  73 + ELSE '不在接口时间范围内'
  74 + END as 是否在接口时间范围
  75 +FROM lq_xh_jksyj jksyj
  76 +INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  77 +WHERE (jksyj.jks = '18566028067' OR jksyj.jkszh = '18566028067')
  78 + AND jksyj.F_IsEffective = 1
  79 + AND hyhk.F_IsEffective = 1
  80 + AND (
  81 + (jksyj.yjsj >= '2025-11-01' AND jksyj.yjsj < '2025-12-01')
  82 + OR (hyhk.hksj >= '2025-11-01' AND hyhk.hksj < '2025-12-01')
  83 + )
  84 + AND (
  85 + jksyj.yjsj < '2025-11-01'
  86 + OR jksyj.yjsj >= '2025-12-01'
  87 + OR hyhk.hksj < '2025-11-01'
  88 + OR hyhk.hksj >= '2025-12-01'
  89 + OR DATEDIFF(jksyj.yjsj, hyhk.hksj) != 0
  90 + )
  91 +ORDER BY jksyj.yjsj;
  92 +
  93 +
... ...
sql/查询员工11月25日之后的记录.sql 0 → 100644
  1 +-- ============================================
  2 +-- 查询员工在2025-11-25 11:55:32之后的记录
  3 +-- 员工ID: 18566028067 (李芳)
  4 +-- ============================================
  5 +
  6 +-- 1. 查询11月25日11:55:32之后的业绩记录(使用业绩时间)
  7 +SELECT
  8 + jksyj.jkszh as 健康师账号,
  9 + jksyj.jksxm as 健康师姓名,
  10 + jksyj.F_kdpxNumber as 项目数,
  11 + jksyj.yjsj as 业绩时间,
  12 + hyhk.hksj as 耗卡时间,
  13 + hyhk.F_IsEffective as 耗卡记录是否有效,
  14 + jksyj.F_IsEffective as 业绩记录是否有效,
  15 + hyhk.F_Id as 耗卡记录ID
  16 +FROM lq_xh_jksyj jksyj
  17 +LEFT JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  18 +WHERE (jksyj.jks = '18566028067' OR jksyj.jkszh = '18566028067')
  19 + AND jksyj.F_IsEffective = 1
  20 + AND jksyj.yjsj > '2025-11-25 11:55:32'
  21 + AND jksyj.yjsj < '2025-12-01'
  22 +ORDER BY jksyj.yjsj;
  23 +
  24 +-- 2. 查询11月25日11:55:32之后的耗卡记录(使用耗卡时间,这是接口统计使用的条件)
  25 +SELECT
  26 + jksyj.jkszh as 健康师账号,
  27 + jksyj.jksxm as 健康师姓名,
  28 + jksyj.F_kdpxNumber as 项目数,
  29 + jksyj.yjsj as 业绩时间,
  30 + hyhk.hksj as 耗卡时间,
  31 + hyhk.F_IsEffective as 耗卡记录是否有效,
  32 + jksyj.F_IsEffective as 业绩记录是否有效,
  33 + hyhk.F_Id as 耗卡记录ID
  34 +FROM lq_xh_jksyj jksyj
  35 +INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  36 +WHERE (jksyj.jks = '18566028067' OR jksyj.jkszh = '18566028067')
  37 + AND jksyj.F_IsEffective = 1
  38 + AND hyhk.F_IsEffective = 1
  39 + AND hyhk.hksj > '2025-11-25 11:55:32'
  40 + AND hyhk.hksj < '2025-12-01'
  41 +ORDER BY hyhk.hksj;
  42 +
  43 +-- 3. 统计11月25日11:55:32之后的项目数总和(使用耗卡时间,接口统计逻辑)
  44 +SELECT
  45 + jksyj.jkszh as 健康师账号,
  46 + CAST(SUM(jksyj.F_kdpxNumber) AS DECIMAL(18,2)) as 项目数总和
  47 +FROM lq_xh_jksyj jksyj
  48 +INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  49 +WHERE (jksyj.jks = '18566028067' OR jksyj.jkszh = '18566028067')
  50 + AND jksyj.F_IsEffective = 1
  51 + AND hyhk.F_IsEffective = 1
  52 + AND hyhk.hksj > '2025-11-25 11:55:32'
  53 + AND hyhk.hksj < '2025-12-01'
  54 +GROUP BY jksyj.jkszh;
  55 +
  56 +
... ...
sql/查询员工消耗项目数.sql 0 → 100644
  1 +-- ============================================
  2 +-- 查询员工在指定月份的消耗项目数
  3 +-- ============================================
  4 +-- 员工ID: 18566028067
  5 +-- 查询月份: 2025年11月 (202511)
  6 +-- ============================================
  7 +
  8 +-- 方式1:从健康师业绩表统计(推荐,使用F_kdpxNumber字段,包含原始+加班+陪同项目数)
  9 +SELECT
  10 + jksyj.jks as 健康师ID,
  11 + jksyj.jksxm as 健康师姓名,
  12 + jksyj.jkszh as 健康师账号,
  13 + COALESCE(SUM(jksyj.F_kdpxNumber), 0) as 消耗项目总数,
  14 + COALESCE(SUM(COALESCE(jksyj.F_OriginalKdpxNumber, jksyj.F_kdpxNumber)), 0) as 原始项目数,
  15 + COALESCE(SUM(COALESCE(jksyj.F_OvertimeKdpxNumber, 0)), 0) as 加班项目数,
  16 + COALESCE(SUM(COALESCE(jksyj.F_AccompaniedProjectNumber, 0)), 0) as 陪同项目数
  17 +FROM lq_xh_jksyj jksyj
  18 +WHERE (jksyj.jks = '18566028067' OR jksyj.jkszh = '18566028067')
  19 + AND jksyj.F_IsEffective = 1
  20 + AND DATE_FORMAT(jksyj.yjsj, '%Y%m') = '202511'
  21 +GROUP BY jksyj.jks, jksyj.jksxm, jksyj.jkszh;
  22 +
  23 +-- 方式2:从品项明细表统计(备用方式,统计F_ProjectNumber字段)
  24 +SELECT
  25 + jksyj.jks as 健康师ID,
  26 + jksyj.jksxm as 健康师姓名,
  27 + jksyj.jkszh as 健康师账号,
  28 + COALESCE(SUM(pxmx.F_ProjectNumber), 0) as 消耗项目数
  29 +FROM lq_xh_jksyj jksyj
  30 +INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id
  31 +INNER JOIN lq_xh_pxmx pxmx ON pxmx.F_ConsumeInfoId = hyhk.F_Id
  32 +WHERE (jksyj.jks = '18566028067' OR jksyj.jkszh = '18566028067')
  33 + AND jksyj.F_IsEffective = 1
  34 + AND hyhk.F_IsEffective = 1
  35 + AND pxmx.F_IsEffective = 1
  36 + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = '202511'
  37 +GROUP BY jksyj.jks, jksyj.jksxm, jksyj.jkszh;
  38 +
  39 +
... ...
sql/添加人次记录表字段.sql
... ... @@ -16,3 +16,5 @@ ADD COLUMN `F_HasBilling` INT(11) DEFAULT 0 COMMENT &#39;是否有开单(0-否,1-是
16 16 -- WHERE TABLE_NAME = 'lq_person_times_record'
17 17 -- AND COLUMN_NAME = 'F_HasBilling';
18 18  
  19 +
  20 +
... ...