Commit 9ec80591acd5b0dd7317dc85419f0869e2c792bb
1 parent
887ceb49
优化库存使用批量创建接口:库存不足时直接抛出异常;优化批量查询性能;添加实体类描述显示到Swagger;更新项目配置以生成XML注释文件
Showing
17 changed files
with
638 additions
and
228 deletions
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
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 | + | ... | ... |