diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationCrInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationCrInput.cs index ef85e65..67a4309 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationCrInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationCrInput.cs @@ -64,7 +64,7 @@ namespace NCC.Extend.Entitys.Dto.LqReimbursementApplication public List selectedPurchaseRecordIds { get; set; } /// - /// 节点配置列表(3-5个节点) + /// 节点配置列表(至少1个节点,建议不超过20个) /// public List nodes { get; set; } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationInfoOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationInfoOutput.cs index 8f14a0a..cbcda0d 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationInfoOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationInfoOutput.cs @@ -27,6 +27,11 @@ namespace NCC.Extend.Entitys.Dto.LqReimbursementApplication /// 申请门店 /// public string applicationStoreId { get; set; } + + /// + /// 申请门店名称 + /// + public string applicationStoreName { get; set; } /// /// 申请时间 diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationListOutput.cs index 2d190ad..10c03c7 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqReimbursementApplicationListOutput.cs @@ -26,6 +26,11 @@ namespace NCC.Extend.Entitys.Dto.LqReimbursementApplication /// 申请门店 /// public string applicationStoreId { get; set; } + + /// + /// 申请门店名称 + /// + public string applicationStoreName { get; set; } /// /// 申请时间 diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdXdbhsj/LqMdXdbhsjCrInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdXdbhsj/LqMdXdbhsjCrInput.cs index cf4f511..2b2b168 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdXdbhsj/LqMdXdbhsjCrInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdXdbhsj/LqMdXdbhsjCrInput.cs @@ -43,7 +43,7 @@ namespace NCC.Extend.Entitys.Dto.LqMdXdbhsj /// 阶段 /// [Required(ErrorMessage = "阶段不能为空")] - [Range(0, 1, ErrorMessage = "阶段值必须在1-3之间")] + [Range(1, 3, ErrorMessage = "阶段值必须在1-3之间")] public int stage { get; set; } = 1; } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdXdbhsj/LqMdXdbhsjUpInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdXdbhsj/LqMdXdbhsjUpInput.cs index 5a06375..751c37f 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdXdbhsj/LqMdXdbhsjUpInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdXdbhsj/LqMdXdbhsjUpInput.cs @@ -43,7 +43,7 @@ namespace NCC.Extend.Entitys.Dto.LqMdXdbhsj /// 阶段 /// [Required(ErrorMessage = "阶段不能为空")] - [Range(0, 1, ErrorMessage = "阶段值必须在1-3之间")] + [Range(1, 3, ErrorMessage = "阶段值必须在1-3之间")] public int stage { get; set; } = 1; } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqAssistantSalaryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqAssistantSalaryService.cs index f0a7ebd..f701278 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqAssistantSalaryService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqAssistantSalaryService.cs @@ -27,7 +27,7 @@ namespace NCC.Extend /// /// 店助薪酬服务 /// - [ApiDescriptionSettings(Tag = "店助薪酬服务", Name = "LqAssistantSalary", Order = 301)] + [ApiDescriptionSettings(Tag = "店助、店助主任薪酬服务", Name = "LqAssistantSalary", Order = 301)] [Route("api/Extend/[controller]")] public class LqAssistantSalaryService : IDynamicApiController, ITransient { @@ -156,14 +156,14 @@ namespace NCC.Extend var storeList = await _db.Queryable().ToListAsync(); var storeDict = storeList.Where(x => !string.IsNullOrEmpty(x.Id)).ToDictionary(x => x.Id, x => x); - // 1.3 门店目标信息 (lq_md_target) - 包含门店生命线和阶段目标 + // 1.4 门店目标信息 (lq_md_target) - 包含门店生命线和阶段目标 var storeTargets = await _db.Queryable() .Where(x => x.Month == monthStr) .ToListAsync(); var storeTargetDict = storeTargets.Where(x => !string.IsNullOrEmpty(x.StoreId)) .ToDictionary(x => x.StoreId, x => x); - // 1.4 门店新店保护信息 (lq_md_xdbhsj) + // 1.5 门店新店保护信息 (lq_md_xdbhsj) var newStoreProtectionList = await _db.Queryable() .Where(x => x.Sfqy == 1) .ToListAsync(); @@ -172,7 +172,7 @@ namespace NCC.Extend .GroupBy(x => x.Mdid) .ToDictionary(g => g.Key, g => g.First()); - // 1.5 门店总业绩计算 (开单实付 - 退卡金额) + // 1.6 门店总业绩计算 (开单实付 - 退卡金额) // 开单实付 var storeBillingList = await _db.Queryable() .Where(x => x.Kdrq >= startDate && x.Kdrq <= endDate.AddDays(1) && x.IsEffective == 1) @@ -193,7 +193,7 @@ namespace NCC.Extend .GroupBy(x => x.Md) .ToDictionary(g => g.Key, g => g.Sum(x => x.ActualRefundAmount ?? x.Tkje ?? 0)); - // 1.6 进店消耗人数统计(有消费金额的,按门店按月去重客户数) + // 1.7 进店消耗人数统计(有消费金额的,按门店按月去重客户数) // 使用SQL查询优化性能 var headcountSql = $@" SELECT @@ -216,7 +216,7 @@ namespace NCC.Extend .Where(x => x.StoreId != null) .ToDictionary(x => x.StoreId.ToString(), x => Convert.ToInt32(x.HeadCount)); - // 1.7 考勤数据 (lq_attendance_summary) + // 1.8 考勤数据 (lq_attendance_summary) var attendanceList = await _db.Queryable() .Where(x => x.Year == year && x.Month == month && x.IsEffective == 1) .ToListAsync(); @@ -312,9 +312,12 @@ namespace NCC.Extend } // 2.5 计算门店总提成(先计算门店级别的提成) + // 判断岗位类型:店助 或 店助主任 + bool isDirector = salary.Position == "店助主任"; + decimal storeTotalCommission = 0; decimal commissionRate = 0; - + // 如果门店生命线未设置(<=0),则没有提成 if (salary.StoreLifeline <= 0) { @@ -323,10 +326,43 @@ namespace NCC.Extend } else { - commissionRate = CalculateCommissionRate(salary.StoreTotalPerformance, salary.StoreLifeline); - storeTotalCommission = salary.StoreTotalPerformance * commissionRate; + // 根据岗位类型计算提成 + if (isDirector) + { + // 店助主任:使用阶梯提成模式 + // 业绩 < 70%:0% + // 70% ≤ 业绩 < 100%:0.4%(阶梯) + // 超过生命线部分:1.6%(阶梯) + storeTotalCommission = CalculateDirectorCommission(salary.StoreTotalPerformance, salary.StoreLifeline); + // 店助主任的提成比例用于显示,计算平均比例 + if (salary.StoreTotalPerformance > 0) + { + commissionRate = storeTotalCommission / salary.StoreTotalPerformance; + } + else + { + commissionRate = 0; + } + } + else + { + // 店助:使用阶梯提成模式 + // 业绩 < 70%:0% + // 70% ≤ 业绩 < 100%:0.4%(阶梯) + // 业绩 ≥ 100%:0.6%(阶梯) + storeTotalCommission = CalculateAssistantCommission(salary.StoreTotalPerformance, salary.StoreLifeline); + // 店助的提成比例用于显示,计算平均比例 + if (salary.StoreTotalPerformance > 0) + { + commissionRate = storeTotalCommission / salary.StoreTotalPerformance; + } + else + { + commissionRate = 0; + } + } } - + salary.CommissionRate = commissionRate; // 2.6 统计进店消耗人数 @@ -336,7 +372,7 @@ namespace NCC.Extend decimal storeTotalStageReward = 0; bool reachedStage1 = false; bool reachedStage2 = false; - + // 如果阶段目标未设置(为0),则没有奖励考核,奖励金额为0 if (salary.Stage1TargetHeadCount <= 0 && salary.Stage2TargetHeadCount <= 0) { @@ -372,7 +408,7 @@ namespace NCC.Extend } } - // 2.8 计算底薪(根据门店分类) + // 2.8 计算底薪(店助和店助主任底薪规则相同,都根据门店分类确定) salary.BaseSalary = CalculateBaseSalary(salary.StoreCategory.Value); // 2.9 固定奖励(手机管理费) @@ -400,10 +436,10 @@ namespace NCC.Extend { // 按比例计算提成 salary.CommissionAmount = storeTotalCommission / daysInMonth * workingDays; - + // 按比例计算奖励 salary.StageRewardAmount = storeTotalStageReward / daysInMonth * workingDays; - + // 计算阶段奖励的明细(按比例分配) if (reachedStage2) { @@ -482,12 +518,12 @@ namespace NCC.Extend } /// - /// 计算提成比例 + /// 计算店助提成(阶梯提成模式) /// /// 门店业绩 /// 门店生命线 - /// 提成比例(0%/0.4%/0.6%) - private decimal CalculateCommissionRate(decimal storePerformance, decimal storeLifeline) + /// 提成金额 + private decimal CalculateAssistantCommission(decimal storePerformance, decimal storeLifeline) { if (storeLifeline <= 0) { @@ -503,18 +539,34 @@ namespace NCC.Extend } else if (ratio < 1.0m) { - // 门店生命线 × 70% ≤ 门店业绩 < 门店生命线 × 100% → 0.4% - return 0.004m; + // 门店生命线 × 70% ≤ 门店业绩 < 门店生命线 × 100% → 0.4%(阶梯) + // 70%以下部分:0% + // 70%-100%部分:0.4% + decimal stage70 = storeLifeline * 0.7m; + decimal stage100 = storeLifeline; + decimal performanceInRange = storePerformance - stage70; + return performanceInRange * 0.004m; } else { - // 门店业绩 ≥ 门店生命线 × 100% → 0.6% - return 0.006m; + // 门店业绩 ≥ 门店生命线 × 100% → 0.6%(阶梯) + // 70%以下部分:0% + // 70%-100%部分:0.4% + // 100%以上部分:0.6% + decimal stage70 = storeLifeline * 0.7m; + decimal stage100 = storeLifeline; + decimal performance70To100 = stage100 - stage70; + decimal performanceAbove100 = storePerformance - stage100; + + decimal commission70To100 = performance70To100 * 0.004m; + decimal commissionAbove100 = performanceAbove100 * 0.006m; + + return commission70To100 + commissionAbove100; } } /// - /// 计算底薪 + /// 计算底薪(店助) /// /// 门店分类(1=A类,2=B类,3=C类) /// 底薪金额 @@ -528,6 +580,53 @@ namespace NCC.Extend _ => throw new Exception($"门店分类值无效:{storeCategory},有效值为1(A类)、2(B类)、3(C类)") }; } + + /// + /// 计算店助主任提成(阶梯提成模式) + /// + /// 门店业绩 + /// 门店生命线 + /// 提成金额 + private decimal CalculateDirectorCommission(decimal storePerformance, decimal storeLifeline) + { + if (storeLifeline <= 0) + { + return 0; + } + + decimal ratio = storePerformance / storeLifeline; + + if (ratio < 0.7m) + { + // 门店业绩 < 门店生命线 × 70% → 0% + return 0; + } + else if (ratio < 1.0m) + { + // 门店生命线 × 70% ≤ 门店业绩 < 门店生命线 × 100% → 0.4%(阶梯) + // 70%以下部分:0% + // 70%-100%部分:0.4% + decimal stage70 = storeLifeline * 0.7m; + decimal performanceInRange = storePerformance - stage70; + return performanceInRange * 0.004m; + } + else + { + // 门店业绩 ≥ 门店生命线 × 100% → 阶梯提成 + // 70%以下部分:0% + // 70%-100%部分:0.4% + // 超过生命线部分:1.6% + decimal stage70 = storeLifeline * 0.7m; + decimal stage100 = storeLifeline; + decimal performance70To100 = stage100 - stage70; + decimal performanceAbove100 = storePerformance - stage100; + + decimal commission70To100 = performance70To100 * 0.004m; + decimal commissionAbove100 = performanceAbove100 * 0.016m; + + return commission70To100 + commissionAbove100; + } + } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs index 9429339..17f8bfa 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; @@ -2381,6 +2381,10 @@ namespace NCC.Extend.LqKdKdjlb kdhyc = SqlFunc.Subqueryable().Where(x => x.Id == it.Kdhy).Select(x => x.Khmc), kdhysjh = SqlFunc.Subqueryable().Where(x => x.Id == it.Kdhy).Select(x => x.Sjh), fkfs = it.Fkfs, // 付款方式 + fkyy = it.Fkyy, // 付款医院ID + fkyyName = SqlFunc.Subqueryable().Where(x => x.Id == it.Fkyy).Select(x => x.Hzmc), // 付款医院名称 + activityId = it.ActivityId, // 营销活动ID + activityName = SqlFunc.Subqueryable().Where(x => x.Id == it.ActivityId).Select(x => x.ActivityName), // 营销活动名称 khly = it.Khly, // 客户来源 bz = it.Bz, // 备注 createTime = it.CreateTime @@ -2564,6 +2568,10 @@ namespace NCC.Extend.LqKdKdjlb customerType = billing.gjlx, cooperationInstitution = billing.hgjg, cooperationInstitutionName = billing.hgjgName, + paymentHospital = billing.fkyy, // 付款医院ID + paymentHospitalName = billing.fkyyName, // 付款医院名称 + activityId = billing.activityId, // 营销活动ID + activityName = billing.activityName, // 营销活动名称 // 品项分类 purchasedItems = itemDetails.Where(x => x.glkdbh == billing.id && x.sourceType == "购买").Select(x => new { diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqPurchaseRecordsService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqPurchaseRecordsService.cs index 9683234..8131193 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqPurchaseRecordsService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqPurchaseRecordsService.cs @@ -79,7 +79,8 @@ namespace NCC.Extend.LqPurchaseRecords List queryApproveTime = input.approveTime != null ? input.approveTime.Split(',').ToObeject>() : null; DateTime? startApproveTime = queryApproveTime != null ? Ext.GetDateTime(queryApproveTime.First()) : null; DateTime? endApproveTime = queryApproveTime != null ? Ext.GetDateTime(queryApproveTime.Last()) : null; - var data = await _db.Queryable() + // 先查询购买记录数据 + var purchaseRecordsQuery = _db.Queryable() .WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id)) .WhereIF(!string.IsNullOrEmpty(input.reimbursementCategoryId), p => p.ReimbursementCategoryId.Contains(input.reimbursementCategoryId)) .WhereIF(!string.IsNullOrEmpty(input.reimbursementCategoryName), p => p.ReimbursementCategoryName.Contains(input.reimbursementCategoryName)) @@ -93,30 +94,92 @@ namespace NCC.Extend.LqPurchaseRecords .WhereIF(queryCreateTime != null, p => p.CreateTime <= new DateTime(endCreateTime.ToDate().Year, endCreateTime.ToDate().Month, endCreateTime.ToDate().Day, 23, 59, 59)) .WhereIF(!string.IsNullOrEmpty(input.createUser), p => p.CreateUser.Equals(input.createUser)) .WhereIF(!string.IsNullOrEmpty(input.createUserStoreId), p => p.CreateUserStoreId.Contains(input.createUserStoreId)) - .WhereIF(!string.IsNullOrEmpty(input.approveStatus), p => p.ApproveStatus.Contains(input.approveStatus)) .WhereIF(!string.IsNullOrEmpty(input.approveUser), p => p.ApproveUser.Equals(input.approveUser)) .WhereIF(queryApproveTime != null, p => p.ApproveTime >= new DateTime(startApproveTime.ToDate().Year, startApproveTime.ToDate().Month, startApproveTime.ToDate().Day, 0, 0, 0)) .WhereIF(queryApproveTime != null, p => p.ApproveTime <= new DateTime(endApproveTime.ToDate().Year, endApproveTime.ToDate().Month, endApproveTime.ToDate().Day, 23, 59, 59)) - .WhereIF(!string.IsNullOrEmpty(input.applicationId), p => p.ApplicationId.Contains(input.applicationId)) - .Select(it => new LqPurchaseRecordsListOutput + .WhereIF(!string.IsNullOrEmpty(input.applicationId), p => p.ApplicationId.Contains(input.applicationId)); + + var total = await purchaseRecordsQuery.CountAsync(); + var purchaseRecords = await purchaseRecordsQuery.ToPageListAsync(input.currentPage, input.pageSize); + + // 获取所有关联的报销申请ID + var applicationIds = purchaseRecords.Where(pr => !string.IsNullOrEmpty(pr.ApplicationId)).Select(pr => pr.ApplicationId).Distinct().ToList(); + + // 查询关联的报销申请状态 + var applications = new Dictionary(); + if (applicationIds.Any()) + { + var appList = await _db.Queryable() + .Where(x => applicationIds.Contains(x.Id)) + .Select(x => new { x.Id, ApprovalStatus = x.ApprovalStatus ?? x.ApproveStatus }) + .ToListAsync(); + + foreach (var app in appList) { - id = it.Id, - reimbursementCategoryId = it.ReimbursementCategoryId, - reimbursementCategoryName = it.ReimbursementCategoryName, - unitPrice = it.UnitPrice, - quantity = it.Quantity, - amount = it.Amount, - memo = it.Memo, - purchaseTime = it.PurchaseTime, - createTime = it.CreateTime, - createUser = it.CreateUser, - createUserStoreId = it.CreateUserStoreId, - approveStatus = it.ApproveStatus, - approveUser = it.ApproveUser, - approveTime = it.ApproveTime, - applicationId = it.ApplicationId, - }).MergeTable().OrderBy(sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize); - return PageResult.SqlSugarPageResult(data); + // 状态映射:已通过 -> 已审批,其他状态保持原样 + var mappedStatus = app.ApprovalStatus == "已通过" ? "已审批" : app.ApprovalStatus; + applications[app.Id] = mappedStatus; + } + } + + // 组装返回数据,如果关联了报销申请,优先使用报销申请的审批状态 + var result = purchaseRecords.Select(pr => new LqPurchaseRecordsListOutput + { + id = pr.Id, + reimbursementCategoryId = pr.ReimbursementCategoryId, + reimbursementCategoryName = pr.ReimbursementCategoryName, + unitPrice = pr.UnitPrice, + quantity = pr.Quantity, + amount = pr.Amount, + memo = pr.Memo, + purchaseTime = pr.PurchaseTime, + createTime = pr.CreateTime, + createUser = pr.CreateUser, + createUserStoreId = pr.CreateUserStoreId, + // 如果关联了报销申请,优先使用报销申请的审批状态;否则使用购买记录的状态 + approveStatus = !string.IsNullOrEmpty(pr.ApplicationId) && applications.ContainsKey(pr.ApplicationId) + ? applications[pr.ApplicationId] + : pr.ApproveStatus, + approveUser = pr.ApproveUser, + approveTime = pr.ApproveTime, + applicationId = pr.ApplicationId, + }).ToList(); + + // 处理审批状态筛选(在内存中处理,因为状态可能来自报销申请) + if (!string.IsNullOrEmpty(input.approveStatus)) + { + result = result.Where(x => x.approveStatus != null && x.approveStatus.Contains(input.approveStatus)).ToList(); + total = result.Count; + } + + // 处理排序 + if (string.IsNullOrEmpty(input.sidx)) + { + result = result.OrderByDescending(x => x.createTime).ToList(); + } + else + { + var sortType = input.sort?.ToLower() == "desc" ? OrderByType.Desc : OrderByType.Asc; + switch (input.sidx.ToLower()) + { + case "id": + result = sortType == OrderByType.Desc ? result.OrderByDescending(x => x.id).ToList() : result.OrderBy(x => x.id).ToList(); + break; + case "createtime": + result = sortType == OrderByType.Desc ? result.OrderByDescending(x => x.createTime).ToList() : result.OrderBy(x => x.createTime).ToList(); + break; + default: + result = result.OrderByDescending(x => x.createTime).ToList(); + break; + } + } + + return PageResult.SqlSugarPageResult( + new SqlSugarPagedList + { + list = result, + pagination = new PagedModel { PageIndex = input.currentPage, PageSize = input.pageSize, Total = total } + }); } /// diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqReimbursementApplicationService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqReimbursementApplicationService.cs index 17f1bd8..accc82e 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqReimbursementApplicationService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqReimbursementApplicationService.cs @@ -18,6 +18,7 @@ using NCC.Extend.Entitys.Dto.LqReimbursementApplication; using NCC.Extend.Entitys.lq_reimbursement_application_node; using NCC.Extend.Entitys.lq_reimbursement_application_node_user; using NCC.Extend.Entitys.lq_reimbursement_approval_record; +using NCC.Extend.Entitys.lq_mdxx; using Yitter.IdGenerator; using NCC.Common.Helper; using NCC.JsonSerialization; @@ -84,6 +85,24 @@ namespace NCC.Extend.LqReimbursementApplication .OrderBy(x => x.ApprovalTime) .ToListAsync(); + // 获取关联的购买记录 + var purchaseRecords = await _db.Queryable() + .Where(x => x.ApplicationId == id) + .OrderBy(x => x.CreateTime) + .ToListAsync(); + + // 获取门店名称 + string storeName = null; + if (!string.IsNullOrEmpty(entity.ApplicationStoreId)) + { + var store = await _db.Queryable() + .Where(x => x.Id == entity.ApplicationStoreId) + .Select(x => x.Dm) + .FirstAsync(); + storeName = store ?? null; + } + output.applicationStoreName = storeName; + // 组装节点信息 var nodeList = nodes.Select(n => new { @@ -122,6 +141,27 @@ namespace NCC.Extend.LqReimbursementApplication .ToList(); } + // 组装购买记录数据 + var purchaseRecordsList = purchaseRecords.Select(pr => new + { + id = pr.Id, + reimbursementCategoryId = pr.ReimbursementCategoryId, + reimbursementCategoryName = pr.ReimbursementCategoryName, + unitPrice = pr.UnitPrice, + quantity = pr.Quantity, + amount = pr.Amount, + memo = pr.Memo, + attachment = pr.Attachment, + purchaseTime = pr.PurchaseTime, + createTime = pr.CreateTime, + createUser = pr.CreateUser, + createUserStoreId = pr.CreateUserStoreId, + approveStatus = pr.ApproveStatus, + approveUser = pr.ApproveUser, + approveTime = pr.ApproveTime, + applicationId = pr.ApplicationId + }).ToList(); + return new { form = output, @@ -129,7 +169,8 @@ namespace NCC.Extend.LqReimbursementApplication currentApprovers = currentApprovers, currentNodeOrder = entity.CurrentNodeOrder, approvalStatus = entity.ApprovalStatus ?? entity.ApproveStatus, - returnedReason = entity.ReturnedReason + returnedReason = entity.ReturnedReason, + purchaseRecords = purchaseRecordsList }; } @@ -141,7 +182,6 @@ namespace NCC.Extend.LqReimbursementApplication [HttpGet("")] public async Task GetList([FromQuery] LqReimbursementApplicationListQueryInput input) { - var sidx = input.sidx == null ? "id" : input.sidx; List queryApplicationTime = input.applicationTime != null ? input.applicationTime.Split(',').ToObeject>() : null; DateTime? startApplicationTime = queryApplicationTime != null ? Ext.GetDateTime(queryApplicationTime.First()) : null; DateTime? endApplicationTime = queryApplicationTime != null ? Ext.GetDateTime(queryApplicationTime.Last()) : null; @@ -160,8 +200,50 @@ namespace NCC.Extend.LqReimbursementApplication .WhereIF(!string.IsNullOrEmpty(input.approveStatus), p => (p.ApprovalStatus ?? p.ApproveStatus).Contains(input.approveStatus)) // .WhereIF(queryApproveTime != null, p => p.ApproveTime >= new DateTime(startApproveTime.ToDate().Year, startApproveTime.ToDate().Month, startApproveTime.ToDate().Day, 0, 0, 0)) //.WhereIF(queryApproveTime != null, p => p.ApproveTime <= new DateTime(endApproveTime.ToDate().Year, endApproveTime.ToDate().Month, endApproveTime.ToDate().Day, 23, 59, 59)) - .WhereIF(!string.IsNullOrEmpty(input.purchaseRecordsId), p => p.PurchaseRecordsId.Contains(input.purchaseRecordsId)) - .OrderBy(sidx + " " + input.sort); + .WhereIF(!string.IsNullOrEmpty(input.purchaseRecordsId), p => p.PurchaseRecordsId.Contains(input.purchaseRecordsId)); + + // 处理排序(兼容前端传入的字段名) + if (string.IsNullOrEmpty(input.sidx)) + { + query = query.OrderBy(x => x.ApplicationTime, OrderByType.Desc); + } + else + { + var sortType = input.sort?.ToLower() == "desc" ? OrderByType.Desc : OrderByType.Asc; + // 根据字段名映射到实体属性(兼容前端传入的字段名) + switch (input.sidx.ToLower()) + { + case "id": + query = query.OrderBy(x => x.Id, sortType); + break; + case "applicationtime": + case "application_time": + query = query.OrderBy(x => x.ApplicationTime, sortType); + break; + case "amount": + query = query.OrderBy(x => x.Amount, sortType); + break; + case "applicationuserid": + case "application_user_id": + query = query.OrderBy(x => x.ApplicationUserId, sortType); + break; + case "applicationusername": + case "application_user_name": + query = query.OrderBy(x => x.ApplicationUserName, sortType); + break; + case "approvestatus": + case "approve_status": + query = query.OrderBy(x => x.ApprovalStatus ?? x.ApproveStatus, sortType); + break; + case "approvetime": + case "approve_time": + query = query.OrderBy(x => x.ApproveTime, sortType); + break; + default: + query = query.OrderBy(x => x.ApplicationTime, OrderByType.Desc); + break; + } + } var total = await query.CountAsync(); var entities = await query.ToPageListAsync(input.currentPage, input.pageSize); @@ -187,6 +269,18 @@ namespace NCC.Extend.LqReimbursementApplication .GroupBy(x => (string)x.applicationId) .ToDictionary(g => g.Key, g => string.Join(", ", g.Select(x => (string)x.approverName))); + // 获取门店名称 + var storeIds = entities.Where(x => !string.IsNullOrEmpty(x.ApplicationStoreId)).Select(x => x.ApplicationStoreId).Distinct().ToList(); + var storeDict = new Dictionary(); + if (storeIds.Any()) + { + var stores = await _db.Queryable() + .Where(x => storeIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Dm }) + .ToListAsync(); + storeDict = stores.ToDictionary(x => x.Id, x => x.Dm ?? ""); + } + // 组装返回数据 var result = entities.Select(item => new LqReimbursementApplicationListOutput { @@ -194,6 +288,9 @@ namespace NCC.Extend.LqReimbursementApplication applicationUserId = item.ApplicationUserId, applicationUserName = item.ApplicationUserName, applicationStoreId = item.ApplicationStoreId, + applicationStoreName = !string.IsNullOrEmpty(item.ApplicationStoreId) && storeDict.ContainsKey(item.ApplicationStoreId) + ? storeDict[item.ApplicationStoreId] + : null, applicationTime = item.ApplicationTime, amount = item.Amount, approveUser = item.ApproveUser, @@ -217,9 +314,9 @@ namespace NCC.Extend.LqReimbursementApplication /// 新建报销申请表 /// /// 参数 - /// + /// 返回创建的申请ID [HttpPost("")] - public async Task Create([FromBody] LqReimbursementApplicationCrInput input) + public async Task Create([FromBody] LqReimbursementApplicationCrInput input) { var userInfo = await _userManager.GetUserInfo(); var entity = input.Adapt(); @@ -231,9 +328,15 @@ namespace NCC.Extend.LqReimbursementApplication _db.BeginTran(); // 1. 验证节点配置 - if (input.nodes == null || input.nodes.Count < 3 || input.nodes.Count > 5) + if (input.nodes == null || input.nodes.Count == 0) + { + throw new Exception("至少需要配置1个审批节点"); + } + + // 设置合理的上限,避免节点过多 + if (input.nodes.Count > 20) { - throw new Exception("节点数量必须在3-5个之间"); + throw new Exception("节点数量不能超过20个"); } // 验证节点顺序是否连续(1, 2, 3, ...) @@ -340,6 +443,9 @@ namespace NCC.Extend.LqReimbursementApplication //关闭事务 _db.CommitTran(); + + // 返回创建的申请ID + return new { id = entity.Id }; } catch (Exception) { @@ -484,6 +590,13 @@ namespace NCC.Extend.LqReimbursementApplication // 获取原有的关联购买记录ID var oldEntity = await _db.Queryable().FirstAsync(p => p.Id == id); + _ = oldEntity ?? throw NCCException.Oh(ErrorCode.COM1005); + + // 检查是否可以修改:只有"待审批"(CurrentNodeOrder=0)或"已退回"状态的申请才能修改 + if (oldEntity.CurrentNodeOrder != null && oldEntity.CurrentNodeOrder != 0 && oldEntity.ApprovalStatus != "已退回") + { + throw new Exception($"该申请当前状态为{oldEntity.ApprovalStatus},无法修改。只有待审批或已退回状态的申请才能修改。"); + } var oldIds = new List(); if (oldEntity != null && !string.IsNullOrEmpty(oldEntity.PurchaseRecordsId)) { @@ -582,7 +695,7 @@ namespace NCC.Extend.LqReimbursementApplication throw new Exception("该申请已经提交审批,不能重复提交"); } - if (entity.NodeCount == null || entity.NodeCount < 3 || entity.NodeCount > 5) + if (entity.NodeCount == null || entity.NodeCount == 0) { throw new Exception("节点配置异常,无法提交审批"); } @@ -605,30 +718,61 @@ namespace NCC.Extend.LqReimbursementApplication entity.CurrentNodeOrder = 1; entity.CurrentNodeId = firstNode.Id; entity.ApprovalStatus = "审批中"; + // 清除退回原因(重新提交审批) + entity.ReturnedReason = null; + entity.ReturnedNodeOrder = null; await _db.Updateable(entity).ExecuteCommandAsync(); - // 为第一个节点的每个审批人创建待审批记录 + // 获取第一个节点的所有审批人 var firstNodeApprovers = await _db.Queryable() .Where(x => x.ApplicationId == id && x.NodeOrder == 1) .ToListAsync(); + // 获取第一个节点已有的审批记录 + var existingRecords = await _db.Queryable() + .Where(x => x.ApplicationId == id && x.NodeOrder == 1) + .ToListAsync(); + + // 为第一个节点的每个审批人创建待审批记录(如果不存在) foreach (var approver in firstNodeApprovers) { - var record = new LqReimbursementApprovalRecordEntity + // 检查是否已存在该审批人的"待审批"记录 + var existingPendingRecord = existingRecords.FirstOrDefault(x => + x.ApproverId == approver.UserId && x.ApprovalResult == "待审批"); + + if (existingPendingRecord == null) { - Id = YitIdHelper.NextId().ToString(), - ApplicationId = id, - NodeId = firstNode.Id, - NodeOrder = 1, - ApproverId = approver.UserId, - ApproverName = approver.UserName, - ApprovalResult = "待审批", - IsCurrentNode = 1, - ApprovalTime = null - }; - await _db.Insertable(record).ExecuteCommandAsync(); + // 如果不存在"待审批"记录,创建新的待审批记录 + // 注意:即使之前有"退回"记录,也创建新的"待审批"记录,保留历史记录 + var record = new LqReimbursementApprovalRecordEntity + { + Id = YitIdHelper.NextId().ToString(), + ApplicationId = id, + NodeId = firstNode.Id, + NodeOrder = 1, + ApproverId = approver.UserId, + ApproverName = approver.UserName, + ApprovalResult = "待审批", + IsCurrentNode = 1, + ApprovalTime = null + }; + await _db.Insertable(record).ExecuteCommandAsync(); + } + else + { + // 如果已存在"待审批"记录,只更新IsCurrentNode状态 + existingPendingRecord.IsCurrentNode = 1; + await _db.Updateable(existingPendingRecord).ExecuteCommandAsync(); + } } + // 更新所有审批记录的IsCurrentNode状态(将第一个节点的"待审批"记录设为1,其他设为0) + // 注意:保留所有历史记录(包括"退回"记录),只更新IsCurrentNode状态 + await _db.Updateable() + .SetColumns(it => it.IsCurrentNode == 0) + .Where(it => it.ApplicationId == id && (it.NodeOrder != 1 || it.ApprovalResult != "待审批")) + .ExecuteCommandAsync(); + _db.CommitTran(); } catch (Exception) @@ -678,17 +822,33 @@ namespace NCC.Extend.LqReimbursementApplication } } - // 检查是否已经审批过 - var hasApproved = await _db.Queryable() + // 检查是否已经审批过(排除待审批状态) + // 注意:如果存在"待审批"记录,说明可以审批 + // 如果不存在"待审批"记录,但存在其他状态的记录(通过、不通过),说明已经审批过 + // 但是,如果之前有"退回"记录,重新提交审批后会创建新的"待审批"记录,所以这里优先检查"待审批"状态 + var existingPendingApprovalRecord = await _db.Queryable() .Where(x => x.ApplicationId == id && x.NodeOrder == entity.CurrentNodeOrder && x.ApproverId == userInfo.userId - && x.ApprovalResult != "待审批") - .AnyAsync(); + && x.ApprovalResult == "待审批") + .FirstAsync(); - if (hasApproved) + // 如果存在"待审批"记录,说明可以审批,不需要抛出异常 + // 如果不存在"待审批"记录,需要检查是否有"通过"或"不通过"的记录(不包括"退回",因为退回后可以重新审批) + if (existingPendingApprovalRecord == null) { - throw new Exception("您已经审批过该节点"); + // 检查是否有"通过"或"不通过"的记录(不包括"退回") + var completedRecord = await _db.Queryable() + .Where(x => x.ApplicationId == id + && x.NodeOrder == entity.CurrentNodeOrder + && x.ApproverId == userInfo.userId + && (x.ApprovalResult == "通过" || x.ApprovalResult == "不通过")) + .FirstAsync(); + + if (completedRecord != null) + { + throw new Exception("您已经审批过该节点"); + } } try @@ -705,7 +865,7 @@ namespace NCC.Extend.LqReimbursementApplication throw new Exception("未找到当前节点配置"); } - // 更新待审批记录为已审批(如果存在待审批记录) + // 查找现有的审批记录(优先查找"待审批"记录) var existingRecord = await _db.Queryable() .Where(x => x.ApplicationId == id && x.NodeOrder == entity.CurrentNodeOrder @@ -713,12 +873,35 @@ namespace NCC.Extend.LqReimbursementApplication && x.ApprovalResult == "待审批") .FirstAsync(); + // 如果不存在"待审批"记录,再查找其他记录 + if (existingRecord == null) + { + existingRecord = await _db.Queryable() + .Where(x => x.ApplicationId == id + && x.NodeOrder == entity.CurrentNodeOrder + && x.ApproverId == userInfo.userId) + .FirstAsync(); + } + if (existingRecord != null) { - // 更新现有记录 + // 如果审批结果是"待审批",允许更新 + // 如果已经有明确的审批结果(通过/不通过),则不允许重复审批 + // 注意:不包括"退回",因为退回后可以重新审批 + if (!string.IsNullOrEmpty(existingRecord.ApprovalResult) + && existingRecord.ApprovalResult != "待审批" + && existingRecord.ApprovalResult != "" + && existingRecord.ApprovalResult != "退回") + { + // 已经有明确的审批结果(通过/不通过),不允许重复审批 + throw new Exception("您已经审批过该节点"); + } + + // 更新现有记录(包括空字符串、"待审批"、"退回"的情况) existingRecord.ApprovalResult = result; existingRecord.ApprovalOpinion = opinion; existingRecord.ApprovalTime = DateTime.Now; + existingRecord.IsCurrentNode = 1; await _db.Updateable(existingRecord).ExecuteCommandAsync(); } else @@ -761,6 +944,13 @@ namespace NCC.Extend.LqReimbursementApplication else if (result == "退回") { // 退回:退回到上一节点 + // 先更新当前节点的退回记录的IsCurrentNode状态(设为0,因为不再是当前节点) + var currentNodeOrder = entity.CurrentNodeOrder.Value; + await _db.Updateable() + .SetColumns(it => it.IsCurrentNode == 0) + .Where(x => x.ApplicationId == id && x.NodeOrder == currentNodeOrder) + .ExecuteCommandAsync(); + if (entity.CurrentNodeOrder == 1) { // 退回到申请人 @@ -769,6 +959,7 @@ namespace NCC.Extend.LqReimbursementApplication entity.ReturnedNodeOrder = 0; entity.ReturnedReason = opinion; entity.CurrentNodeId = null; + // 注意:不退回到发起人时,不删除审批记录,保留所有历史记录(包括退回记录) } else { @@ -787,31 +978,47 @@ namespace NCC.Extend.LqReimbursementApplication entity.CurrentNodeId = prevNode.Id; } - // 清除上一节点的所有审批记录(重新审批) - await _db.Deleteable() + // 获取上一节点已有的审批记录 + var prevNodeExistingRecords = await _db.Queryable() .Where(x => x.ApplicationId == id && x.NodeOrder == entity.CurrentNodeOrder) - .ExecuteCommandAsync(); + .ToListAsync(); - // 为上一节点的每个审批人创建新的待审批记录 + // 获取上一节点的所有审批人 var prevNodeApprovers = await _db.Queryable() .Where(x => x.ApplicationId == id && x.NodeOrder == entity.CurrentNodeOrder) .ToListAsync(); + // 为上一节点的每个审批人创建待审批记录(如果不存在) foreach (var approver in prevNodeApprovers) { - var record = new LqReimbursementApprovalRecordEntity + // 检查是否已存在该审批人的"待审批"记录 + var prevNodeExistingPendingRecord = prevNodeExistingRecords.FirstOrDefault(x => + x.ApproverId == approver.UserId && x.ApprovalResult == "待审批"); + + if (prevNodeExistingPendingRecord == null) + { + // 如果不存在"待审批"记录,创建新的待审批记录 + // 注意:即使之前有"退回"或其他记录,也创建新的"待审批"记录,保留历史记录 + var record = new LqReimbursementApprovalRecordEntity + { + Id = YitIdHelper.NextId().ToString(), + ApplicationId = id, + NodeId = prevNode.Id, + NodeOrder = entity.CurrentNodeOrder.Value, + ApproverId = approver.UserId, + ApproverName = approver.UserName, + ApprovalResult = "待审批", + IsCurrentNode = 1, + ApprovalTime = null + }; + await _db.Insertable(record).ExecuteCommandAsync(); + } + else { - Id = YitIdHelper.NextId().ToString(), - ApplicationId = id, - NodeId = prevNode.Id, - NodeOrder = entity.CurrentNodeOrder.Value, - ApproverId = approver.UserId, - ApproverName = approver.UserName, - ApprovalResult = "待审批", - IsCurrentNode = 1, - ApprovalTime = null - }; - await _db.Insertable(record).ExecuteCommandAsync(); + // 如果已存在"待审批"记录,只更新IsCurrentNode状态 + prevNodeExistingPendingRecord.IsCurrentNode = 1; + await _db.Updateable(prevNodeExistingPendingRecord).ExecuteCommandAsync(); + } } } @@ -848,6 +1055,11 @@ namespace NCC.Extend.LqReimbursementApplication // 所有人都已通过 shouldMoveToNext = true; } + // 特殊情况:如果只有一个审批人,且当前审批人就是该审批人,且审批结果是"通过",则直接进入下一节点 + else if (approvers.Count == 1 && approvers.Contains(userInfo.userId) && result == "通过") + { + shouldMoveToNext = true; + } } if (shouldMoveToNext) @@ -952,13 +1164,36 @@ namespace NCC.Extend.LqReimbursementApplication [HttpGet("Actions/AllPendingApproval")] public async Task GetAllPendingApprovalList([FromQuery] LqReimbursementApplicationListQueryInput input) { - var sidx = input.sidx == null ? "id" : input.sidx; - // 管理员可以查看所有待审批的申请 var query = _db.Queryable() .Where(x => x.ApprovalStatus == "审批中") - .WhereIF(!string.IsNullOrEmpty(input.applicationStoreId), p => p.ApplicationStoreId.Contains(input.applicationStoreId)) - .OrderBy(sidx + " " + input.sort); + .WhereIF(!string.IsNullOrEmpty(input.applicationStoreId), p => p.ApplicationStoreId.Contains(input.applicationStoreId)); + + // 处理排序 + if (string.IsNullOrEmpty(input.sidx)) + { + query = query.OrderBy(x => x.ApplicationTime, OrderByType.Desc); + } + else + { + var sortType = input.sort?.ToLower() == "desc" ? OrderByType.Desc : OrderByType.Asc; + // 根据字段名映射到实体属性 + switch (input.sidx.ToLower()) + { + case "id": + query = query.OrderBy(x => x.Id, sortType); + break; + case "applicationtime": + query = query.OrderBy(x => x.ApplicationTime, sortType); + break; + case "amount": + query = query.OrderBy(x => x.Amount, sortType); + break; + default: + query = query.OrderBy(x => x.ApplicationTime, OrderByType.Desc); + break; + } + } var total = await query.CountAsync(); var entities = await query.ToPageListAsync(input.currentPage, input.pageSize); @@ -984,6 +1219,18 @@ namespace NCC.Extend.LqReimbursementApplication .GroupBy(x => (string)x.applicationId) .ToDictionary(g => g.Key, g => string.Join(", ", g.Select(x => (string)x.approverName))); + // 获取门店名称 + var storeIds = entities.Where(x => !string.IsNullOrEmpty(x.ApplicationStoreId)).Select(x => x.ApplicationStoreId).Distinct().ToList(); + var storeDict = new Dictionary(); + if (storeIds.Any()) + { + var stores = await _db.Queryable() + .Where(x => storeIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Dm }) + .ToListAsync(); + storeDict = stores.ToDictionary(x => x.Id, x => x.Dm ?? ""); + } + // 组装返回数据 var result = entities.Select(item => new LqReimbursementApplicationListOutput { @@ -991,6 +1238,9 @@ namespace NCC.Extend.LqReimbursementApplication applicationUserId = item.ApplicationUserId, applicationUserName = item.ApplicationUserName, applicationStoreId = item.ApplicationStoreId, + applicationStoreName = !string.IsNullOrEmpty(item.ApplicationStoreId) && storeDict.ContainsKey(item.ApplicationStoreId) + ? storeDict[item.ApplicationStoreId] + : null, applicationTime = item.ApplicationTime, amount = item.Amount, approveUser = item.ApproveUser, @@ -1019,7 +1269,6 @@ namespace NCC.Extend.LqReimbursementApplication public async Task GetPendingApprovalList([FromQuery] LqReimbursementApplicationListQueryInput input) { var userInfo = await _userManager.GetUserInfo(); - var sidx = input.sidx == null ? "id" : input.sidx; // 查询当前用户作为审批人的节点 var userNodeOrders = await _db.Queryable() @@ -1044,16 +1293,71 @@ namespace NCC.Extend.LqReimbursementApplication var applicationIds = userApplications.Keys.ToList(); - // 查询这些申请中,当前节点是用户有权限的节点,且状态为"审批中"的申请 - var query = _db.Queryable() + // 先查询所有符合条件的申请(状态为"审批中"且在用户有权限的申请列表中) + var allApplications = await _db.Queryable() .Where(x => applicationIds.Contains(x.Id) && x.ApprovalStatus == "审批中") + .WhereIF(!string.IsNullOrEmpty(input.applicationStoreId), p => p.ApplicationStoreId.Contains(input.applicationStoreId)) + .ToListAsync(); + + // 在内存中过滤:当前节点必须是用户有权限的节点 + var filteredApplications = allApplications .Where(x => userApplications.ContainsKey(x.Id) && userApplications[x.Id].Contains(x.CurrentNodeOrder ?? 0)) - .WhereIF(!string.IsNullOrEmpty(input.applicationStoreId), p => p.ApplicationStoreId.Contains(input.applicationStoreId)) - .OrderBy(sidx + " " + input.sort); + .ToList(); - var total = await query.CountAsync(); - var entities = await query.ToPageListAsync(input.currentPage, input.pageSize); + // 获取过滤后的申请ID列表 + var filteredApplicationIds = filteredApplications.Select(x => x.Id).ToList(); + + // 如果没有符合条件的申请,直接返回空列表 + if (!filteredApplicationIds.Any()) + { + return PageResult.SqlSugarPageResult( + new SqlSugarPagedList + { + list = new List(), + pagination = new PagedModel { PageIndex = input.currentPage, PageSize = input.pageSize, Total = 0 } + }); + } + + // 对过滤后的申请进行排序 + var sortType = input.sort?.ToLower() == "desc" ? OrderByType.Desc : OrderByType.Asc; + IOrderedEnumerable orderedApplications; + + if (string.IsNullOrEmpty(input.sidx)) + { + orderedApplications = filteredApplications.OrderByDescending(x => x.ApplicationTime); + } + else + { + switch (input.sidx.ToLower()) + { + case "id": + orderedApplications = sortType == OrderByType.Desc + ? filteredApplications.OrderByDescending(x => x.Id) + : filteredApplications.OrderBy(x => x.Id); + break; + case "applicationtime": + orderedApplications = sortType == OrderByType.Desc + ? filteredApplications.OrderByDescending(x => x.ApplicationTime) + : filteredApplications.OrderBy(x => x.ApplicationTime); + break; + case "amount": + orderedApplications = sortType == OrderByType.Desc + ? filteredApplications.OrderByDescending(x => x.Amount) + : filteredApplications.OrderBy(x => x.Amount); + break; + default: + orderedApplications = filteredApplications.OrderByDescending(x => x.ApplicationTime); + break; + } + } + + // 手动分页 + var total = filteredApplications.Count; + var entities = orderedApplications + .Skip((input.currentPage - 1) * input.pageSize) + .Take(input.pageSize) + .ToList(); // 获取当前审批人信息 var resultApplicationIds = entities.Select(x => x.Id).ToList(); @@ -1076,6 +1380,18 @@ namespace NCC.Extend.LqReimbursementApplication .GroupBy(x => (string)x.applicationId) .ToDictionary(g => g.Key, g => string.Join(", ", g.Select(x => (string)x.approverName))); + // 获取门店名称 + var storeIds = entities.Where(x => !string.IsNullOrEmpty(x.ApplicationStoreId)).Select(x => x.ApplicationStoreId).Distinct().ToList(); + var storeDict = new Dictionary(); + if (storeIds.Any()) + { + var stores = await _db.Queryable() + .Where(x => storeIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Dm }) + .ToListAsync(); + storeDict = stores.ToDictionary(x => x.Id, x => x.Dm ?? ""); + } + // 组装返回数据 var result = entities.Select(item => new LqReimbursementApplicationListOutput { @@ -1083,6 +1399,9 @@ namespace NCC.Extend.LqReimbursementApplication applicationUserId = item.ApplicationUserId, applicationUserName = item.ApplicationUserName, applicationStoreId = item.ApplicationStoreId, + applicationStoreName = !string.IsNullOrEmpty(item.ApplicationStoreId) && storeDict.ContainsKey(item.ApplicationStoreId) + ? storeDict[item.ApplicationStoreId] + : null, applicationTime = item.ApplicationTime, amount = item.Amount, approveUser = item.ApproveUser, diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs index 7870d0c..d8e49dc 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs @@ -18,6 +18,7 @@ using NCC.Extend.Entitys.lq_xh_jksyj; using NCC.Extend.Entitys.lq_ycsd_jsj; using NCC.Extend.Entitys.lq_mdxx; using NCC.Extend.Entitys.lq_hytk_hytk; +using NCC.Extend.Entitys.lq_hytk_jksyj; using NCC.Extend.Entitys.lq_md_xdbhsj; using NCC.Extend.Entitys.lq_salary_extra_calculation; using NCC.System.Entitys.Permission; @@ -224,6 +225,11 @@ namespace NCC.Extend .Where(x => x.Year == year && x.Month == month && x.IsEffective == 1) .ToListAsync(); + // 1.3.1 退款数据 (lq_hytk_jksyj) + var refundList = await _db.Queryable() + .Where(x => x.Tksj >= startDate && x.Tksj <= endDate.AddDays(1) && x.IsEffective == 1) + .ToListAsync(); + // 1.4 战队成员及顾问信息 (lq_jinsanjiao_user + lq_ycsd_jsj) var teamUserList = await _db.Queryable() .Where(x => x.Month == monthStr && x.DeleteMark == 0) @@ -272,12 +278,12 @@ namespace NCC.Extend // 退款金额 var storeRefundList = await _db.Queryable() .Where(x => x.Tksj >= startDate && x.Tksj <= endDate.AddDays(1) && x.IsEffective == 1) - .Select(x => new { x.Mdbh, x.Tkje }) + .Select(x => new { x.Mdbh, x.Tkje, x.ActualRefundAmount }) .ToListAsync(); var storeRefundDict = storeRefundList .Where(x => !string.IsNullOrEmpty(x.Mdbh)) .GroupBy(x => x.Mdbh) - .ToDictionary(g => g.Key, g => g.Sum(x => x.Tkje ?? 0)); + .ToDictionary(g => g.Key, g => g.Sum(x => x.ActualRefundAmount ?? 0)); // 1.7 门店信息 (lq_mdxx) var storeList = await _db.Queryable().ToListAsync(); @@ -412,6 +418,26 @@ namespace NCC.Extend salary.CooperationPerformance = myPerf.Where(x => (x.PerformanceType ?? "").Trim() == "合作业绩").Sum(x => decimal.Parse(x.Jksyj ?? "0")); salary.TotalPerformance = myPerf.Sum(x => decimal.Parse(x.Jksyj ?? "0")); + // 扣除退款 + var myRefunds = refundList.Where(x => x.Jks == empId).ToList(); + if (myRefunds.Any()) + { + decimal totalRefund = myRefunds.Sum(x => x.Jksyj ?? 0); + decimal baseRefund = myRefunds.Where(x => (x.PerformanceType ?? "").Trim() == "基础业绩").Sum(x => x.Jksyj ?? 0); + decimal cooperationRefund = myRefunds.Where(x => (x.PerformanceType ?? "").Trim() == "合作业绩").Sum(x => x.Jksyj ?? 0); + + // 如果退款记录未标记类型,且总退款大于0,则可能需要处理(当前暂不处理未分类退款的明细扣除,仅扣除总额) + // 修正:如果PerformanceType为空,应当从总业绩扣除。若要从Base或Coop扣除,需确认业务规则。 + // 假设:如果未分类,暂时不从Base/Coop扣(或者按比例扣?)。 + // 根据现有数据,有部分是null。 + // 安全起见,TotalPerformance 减去 totalRefund。 + // Base 和 Coop 减去各自明确标识的部分。 + + salary.TotalPerformance -= totalRefund; + salary.BasePerformance -= baseRefund; + salary.CooperationPerformance -= cooperationRefund; + } + // 新客与升单业绩 salary.NewCustomerPerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "是")).Sum(x => decimal.Parse(x.Jksyj ?? "0")); salary.UpgradePerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "否")).Sum(x => decimal.Parse(x.Jksyj ?? "0")); diff --git a/sql/更新历史数据科技部归类字段.sql b/sql/更新历史数据科技部归类字段.sql new file mode 100644 index 0000000..6ec7529 --- /dev/null +++ b/sql/更新历史数据科技部归类字段.sql @@ -0,0 +1,256 @@ +-- ============================================ +-- 批量更新品项明细表和业绩表的科技部归类字段 +-- ============================================ +-- 说明:此脚本用于批量更新以下表的 F_KjbCategory 字段 +-- 1. lq_kd_pxmx(开单品项明细表) +-- 2. lq_kd_jksyj(开单健康师业绩表) +-- 3. lq_kd_kjbsyj(开单科技部老师业绩表) +-- 4. lq_hytk_mx(退卡品项明细表) +-- 5. lq_hytk_jksyj(退卡健康师业绩表) +-- 6. lq_hytk_kjbsyj(退卡科技部老师业绩表) +-- +-- 数据来源:从关联的项目资料表(lq_xmzl)的 F_BeautyType 字段获取科技部归类 +-- +-- 关联关系: +-- - lq_kd_pxmx.px = lq_xmzl.F_Id +-- - lq_kd_jksyj.F_ItemId 或通过 lq_kd_pxmx 关联 = lq_xmzl.F_Id +-- - lq_kd_kjbsyj.F_ItemId 或通过 lq_kd_pxmx 关联 = lq_xmzl.F_Id +-- - lq_hytk_mx.px = lq_xmzl.F_Id +-- - lq_hytk_jksyj.F_ItemId 或通过 lq_hytk_mx 关联 = lq_xmzl.F_Id +-- - lq_hytk_kjbsyj.F_ItemId 或通过 lq_hytk_mx 关联 = lq_xmzl.F_Id +-- +-- 更新逻辑: +-- - 更新所有记录(不判断是否有效) +-- - 只更新关联的项目资料存在且F_BeautyType字段有值的记录 +-- - 从 lq_xmzl.F_BeautyType 字段获取科技部归类 + +-- ============================================ +-- 1. 更新开单品项明细表的科技部归类字段 +-- ============================================ +UPDATE lq_kd_pxmx pxmx +INNER JOIN lq_xmzl xmzl ON pxmx.px = xmzl.F_Id +SET pxmx.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != ''; + +-- ============================================ +-- 2. 更新开单健康师业绩表的科技部归类字段 +-- ============================================ +-- 方式1:通过品项ID直接关联 +UPDATE lq_kd_jksyj jksyj +INNER JOIN lq_xmzl xmzl ON jksyj.F_ItemId = xmzl.F_Id +SET jksyj.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != '' + AND jksyj.F_ItemId IS NOT NULL + AND jksyj.F_ItemId != ''; + +-- 方式2:通过开单品项明细表关联(当F_ItemId为空时) +UPDATE lq_kd_jksyj jksyj +INNER JOIN lq_kd_pxmx pxmx ON jksyj.F_kdpxid = pxmx.F_Id +INNER JOIN lq_xmzl xmzl ON pxmx.px = xmzl.F_Id +SET jksyj.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != '' + AND (jksyj.F_ItemId IS NULL OR jksyj.F_ItemId = '') + AND jksyj.F_kdpxid IS NOT NULL + AND jksyj.F_kdpxid != ''; + +-- ============================================ +-- 3. 更新开单科技部老师业绩表的科技部归类字段 +-- ============================================ +-- 方式1:通过品项ID直接关联 +UPDATE lq_kd_kjbsyj kjbsyj +INNER JOIN lq_xmzl xmzl ON kjbsyj.F_ItemId = xmzl.F_Id +SET kjbsyj.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != '' + AND kjbsyj.F_ItemId IS NOT NULL + AND kjbsyj.F_ItemId != ''; + +-- 方式2:通过开单品项明细表关联(当F_ItemId为空时) +UPDATE lq_kd_kjbsyj kjbsyj +INNER JOIN lq_kd_pxmx pxmx ON kjbsyj.F_kdpxid = pxmx.F_Id +INNER JOIN lq_xmzl xmzl ON pxmx.px = xmzl.F_Id +SET kjbsyj.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != '' + AND (kjbsyj.F_ItemId IS NULL OR kjbsyj.F_ItemId = '') + AND kjbsyj.F_kdpxid IS NOT NULL + AND kjbsyj.F_kdpxid != ''; + +-- ============================================ +-- 4. 更新退卡品项明细表的科技部归类字段 +-- ============================================ +UPDATE lq_hytk_mx mx +INNER JOIN lq_xmzl xmzl ON mx.px = xmzl.F_Id +SET mx.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != ''; + +-- ============================================ +-- 5. 更新退卡健康师业绩表的科技部归类字段 +-- ============================================ +-- 方式1:通过品项ID直接关联 +UPDATE lq_hytk_jksyj jksyj +INNER JOIN lq_xmzl xmzl ON jksyj.F_ItemId = xmzl.F_Id +SET jksyj.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != '' + AND jksyj.F_ItemId IS NOT NULL + AND jksyj.F_ItemId != ''; + +-- 方式2:通过退卡品项明细表关联(当F_ItemId为空时) +UPDATE lq_hytk_jksyj jksyj +INNER JOIN lq_hytk_mx mx ON jksyj.F_tkpxid = mx.F_Id +INNER JOIN lq_xmzl xmzl ON mx.px = xmzl.F_Id +SET jksyj.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != '' + AND (jksyj.F_ItemId IS NULL OR jksyj.F_ItemId = '') + AND jksyj.F_tkpxid IS NOT NULL + AND jksyj.F_tkpxid != ''; + +-- ============================================ +-- 6. 更新退卡科技部老师业绩表的科技部归类字段 +-- ============================================ +-- 方式1:通过品项ID直接关联 +UPDATE lq_hytk_kjbsyj kjbsyj +INNER JOIN lq_xmzl xmzl ON kjbsyj.F_ItemId = xmzl.F_Id +SET kjbsyj.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != '' + AND kjbsyj.F_ItemId IS NOT NULL + AND kjbsyj.F_ItemId != ''; + +-- 方式2:通过退卡品项明细表关联(当F_ItemId为空时) +UPDATE lq_hytk_kjbsyj kjbsyj +INNER JOIN lq_hytk_mx mx ON kjbsyj.F_tkpxid = mx.F_Id +INNER JOIN lq_xmzl xmzl ON mx.px = xmzl.F_Id +SET kjbsyj.F_KjbCategory = xmzl.F_BeautyType +WHERE xmzl.F_BeautyType IS NOT NULL + AND xmzl.F_BeautyType != '' + AND (kjbsyj.F_ItemId IS NULL OR kjbsyj.F_ItemId = '') + AND kjbsyj.F_tkpxid IS NOT NULL + AND kjbsyj.F_tkpxid != ''; + +-- ============================================ +-- 7. 验证更新结果 +-- ============================================ +-- 查看各表更新后的统计信息 +-- +-- lq_kd_pxmx 更新后的统计信息 +-- SELECT +-- '开单品项明细' AS 表名, +-- F_KjbCategory AS 科技部归类, +-- COUNT(*) AS 记录数 +-- FROM lq_kd_pxmx +-- WHERE F_KjbCategory IS NOT NULL +-- GROUP BY F_KjbCategory +-- ORDER BY 记录数 DESC; + +-- lq_kd_jksyj 更新后的统计信息 +-- SELECT +-- '开单健康师业绩' AS 表名, +-- F_KjbCategory AS 科技部归类, +-- COUNT(*) AS 记录数 +-- FROM lq_kd_jksyj +-- WHERE F_KjbCategory IS NOT NULL +-- GROUP BY F_KjbCategory +-- ORDER BY 记录数 DESC; + +-- lq_kd_kjbsyj 更新后的统计信息 +-- SELECT +-- '开单科技部老师业绩' AS 表名, +-- F_KjbCategory AS 科技部归类, +-- COUNT(*) AS 记录数 +-- FROM lq_kd_kjbsyj +-- WHERE F_KjbCategory IS NOT NULL +-- GROUP BY F_KjbCategory +-- ORDER BY 记录数 DESC; + +-- lq_hytk_mx 更新后的统计信息 +-- SELECT +-- '退卡品项明细' AS 表名, +-- F_KjbCategory AS 科技部归类, +-- COUNT(*) AS 记录数 +-- FROM lq_hytk_mx +-- WHERE F_KjbCategory IS NOT NULL +-- GROUP BY F_KjbCategory +-- ORDER BY 记录数 DESC; + +-- lq_hytk_jksyj 更新后的统计信息 +-- SELECT +-- '退卡健康师业绩' AS 表名, +-- F_KjbCategory AS 科技部归类, +-- COUNT(*) AS 记录数 +-- FROM lq_hytk_jksyj +-- WHERE F_KjbCategory IS NOT NULL +-- GROUP BY F_KjbCategory +-- ORDER BY 记录数 DESC; + +-- lq_hytk_kjbsyj 更新后的统计信息 +-- SELECT +-- '退卡科技部老师业绩' AS 表名, +-- F_KjbCategory AS 科技部归类, +-- COUNT(*) AS 记录数 +-- FROM lq_hytk_kjbsyj +-- WHERE F_KjbCategory IS NOT NULL +-- GROUP BY F_KjbCategory +-- ORDER BY 记录数 DESC; + +-- ============================================ +-- 8. 查看未更新的记录数(关联的项目资料不存在或fl4为空) +-- ============================================ +-- +-- lq_kd_pxmx 未更新记录数 +-- SELECT COUNT(*) AS 未更新记录数 +-- FROM lq_kd_pxmx pxmx +-- LEFT JOIN lq_xmzl xmzl ON pxmx.px = xmzl.F_Id +-- WHERE xmzl.F_Id IS NULL +-- OR xmzl.F_BeautyType IS NULL +-- OR xmzl.F_BeautyType = ''; + +-- lq_kd_jksyj 未更新记录数 +-- SELECT COUNT(*) AS 未更新记录数 +-- FROM lq_kd_jksyj jksyj +-- LEFT JOIN lq_xmzl xmzl ON jksyj.F_ItemId = xmzl.F_Id +-- LEFT JOIN lq_kd_pxmx pxmx ON jksyj.F_kdpxid = pxmx.F_Id +-- LEFT JOIN lq_xmzl xmzl2 ON pxmx.px = xmzl2.F_Id +-- WHERE (xmzl.F_Id IS NULL OR xmzl.F_BeautyType IS NULL OR xmzl.F_BeautyType = '') +-- AND (xmzl2.F_Id IS NULL OR xmzl2.F_BeautyType IS NULL OR xmzl2.F_BeautyType = ''); + +-- lq_kd_kjbsyj 未更新记录数 +-- SELECT COUNT(*) AS 未更新记录数 +-- FROM lq_kd_kjbsyj kjbsyj +-- LEFT JOIN lq_xmzl xmzl ON kjbsyj.F_ItemId = xmzl.F_Id +-- LEFT JOIN lq_kd_pxmx pxmx ON kjbsyj.F_kdpxid = pxmx.F_Id +-- LEFT JOIN lq_xmzl xmzl2 ON pxmx.px = xmzl2.F_Id +-- WHERE (xmzl.F_Id IS NULL OR xmzl.F_BeautyType IS NULL OR xmzl.F_BeautyType = '') +-- AND (xmzl2.F_Id IS NULL OR xmzl2.F_BeautyType IS NULL OR xmzl2.F_BeautyType = ''); + +-- lq_hytk_mx 未更新记录数 +-- SELECT COUNT(*) AS 未更新记录数 +-- FROM lq_hytk_mx mx +-- LEFT JOIN lq_xmzl xmzl ON mx.px = xmzl.F_Id +-- WHERE xmzl.F_Id IS NULL +-- OR xmzl.F_BeautyType IS NULL +-- OR xmzl.F_BeautyType = ''; + +-- lq_hytk_jksyj 未更新记录数 +-- SELECT COUNT(*) AS 未更新记录数 +-- FROM lq_hytk_jksyj jksyj +-- LEFT JOIN lq_xmzl xmzl ON jksyj.F_ItemId = xmzl.F_Id +-- LEFT JOIN lq_hytk_mx mx ON jksyj.F_tkpxid = mx.F_Id +-- LEFT JOIN lq_xmzl xmzl2 ON mx.px = xmzl2.F_Id +-- WHERE (xmzl.F_Id IS NULL OR xmzl.F_BeautyType IS NULL OR xmzl.F_BeautyType = '') +-- AND (xmzl2.F_Id IS NULL OR xmzl2.F_BeautyType IS NULL OR xmzl2.F_BeautyType = ''); + +-- lq_hytk_kjbsyj 未更新记录数 +-- SELECT COUNT(*) AS 未更新记录数 +-- FROM lq_hytk_kjbsyj kjbsyj +-- LEFT JOIN lq_xmzl xmzl ON kjbsyj.F_ItemId = xmzl.F_Id +-- LEFT JOIN lq_hytk_mx mx ON kjbsyj.F_tkpxid = mx.F_Id +-- LEFT JOIN lq_xmzl xmzl2 ON mx.px = xmzl2.F_Id +-- WHERE (xmzl.F_Id IS NULL OR xmzl.F_BeautyType IS NULL OR xmzl.F_BeautyType = '') +-- AND (xmzl2.F_Id IS NULL OR xmzl2.F_BeautyType IS NULL OR xmzl2.F_BeautyType = ''); diff --git a/sql/添加科技部归类字段.sql b/sql/添加科技部归类字段.sql new file mode 100644 index 0000000..8e8f7a6 --- /dev/null +++ b/sql/添加科技部归类字段.sql @@ -0,0 +1,91 @@ +-- ============================================ +-- 为品项明细表和业绩表添加科技部归类字段 +-- ============================================ +-- 说明:此脚本为品项明细相关表和业绩表添加科技部归类字段,用于存储品项的科技部归类信息 +-- +-- 字段说明: +-- F_KjbCategory:科技部归类,用于存储科技部对品项的分类信息 +-- +-- 业务含义: +-- - 科技部归类用于科技部对品项进行分类统计和分析 +-- - 分类值来源于项目资料表(lq_xmzl)的 F_BeautyType 字段(科美类型) +-- +-- 注意事项: +-- - 字段类型为VARCHAR(50),可存储各种分类值 +-- - 所有字段允许为NULL,因为历史数据可能没有这些分类信息 +-- - 字段位置:放在品项相关字段(px、pxmc)或业绩相关字段之后 + +-- ============================================ +-- 1. lq_kd_pxmx(开单品项明细表) - 添加科技部归类字段 +-- ============================================ +ALTER TABLE lq_kd_pxmx +ADD COLUMN F_KjbCategory VARCHAR(50) NULL COMMENT '科技部归类(来源:lq_xmzl.F_BeautyType)' AFTER F_PerformanceType; + +-- ============================================ +-- 2. lq_kd_jksyj(开单健康师业绩表) - 添加科技部归类字段 +-- ============================================ +ALTER TABLE lq_kd_jksyj +ADD COLUMN F_KjbCategory VARCHAR(50) NULL COMMENT '科技部归类(来源:lq_xmzl.F_BeautyType)' AFTER F_PerformanceType; + +-- ============================================ +-- 3. lq_kd_kjbsyj(开单科技部老师业绩表) - 添加科技部归类字段 +-- ============================================ +ALTER TABLE lq_kd_kjbsyj +ADD COLUMN F_KjbCategory VARCHAR(50) NULL COMMENT '科技部归类(来源:lq_xmzl.F_BeautyType)' AFTER F_PerformanceType; + +-- ============================================ +-- 4. lq_hytk_mx(退卡品项明细表) - 添加科技部归类字段 +-- ============================================ +ALTER TABLE lq_hytk_mx +ADD COLUMN F_KjbCategory VARCHAR(50) NULL COMMENT '科技部归类(来源:lq_xmzl.F_BeautyType)' AFTER F_PerformanceType; + +-- ============================================ +-- 5. lq_hytk_jksyj(退卡健康师业绩表) - 添加科技部归类字段 +-- ============================================ +ALTER TABLE lq_hytk_jksyj +ADD COLUMN F_KjbCategory VARCHAR(50) NULL COMMENT '科技部归类(来源:lq_xmzl.F_BeautyType)' AFTER F_PerformanceType; + +-- ============================================ +-- 6. lq_hytk_kjbsyj(退卡科技部老师业绩表) - 添加科技部归类字段 +-- ============================================ +ALTER TABLE lq_hytk_kjbsyj +ADD COLUMN F_KjbCategory VARCHAR(50) NULL COMMENT '科技部归类(来源:lq_xmzl.F_BeautyType)' AFTER F_PerformanceType; + +-- ============================================ +-- 7. 验证字段创建 +-- ============================================ +-- 验证 lq_kd_pxmx 表 +-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT +-- FROM INFORMATION_SCHEMA.COLUMNS +-- WHERE TABLE_NAME = 'lq_kd_pxmx' +-- AND COLUMN_NAME = 'F_KjbCategory'; + +-- 验证 lq_kd_jksyj 表 +-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT +-- FROM INFORMATION_SCHEMA.COLUMNS +-- WHERE TABLE_NAME = 'lq_kd_jksyj' +-- AND COLUMN_NAME = 'F_KjbCategory'; + +-- 验证 lq_kd_kjbsyj 表 +-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT +-- FROM INFORMATION_SCHEMA.COLUMNS +-- WHERE TABLE_NAME = 'lq_kd_kjbsyj' +-- AND COLUMN_NAME = 'F_KjbCategory'; + +-- 验证 lq_hytk_mx 表 +-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT +-- FROM INFORMATION_SCHEMA.COLUMNS +-- WHERE TABLE_NAME = 'lq_hytk_mx' +-- AND COLUMN_NAME = 'F_KjbCategory'; + +-- 验证 lq_hytk_jksyj 表 +-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT +-- FROM INFORMATION_SCHEMA.COLUMNS +-- WHERE TABLE_NAME = 'lq_hytk_jksyj' +-- AND COLUMN_NAME = 'F_KjbCategory'; + +-- 验证 lq_hytk_kjbsyj 表 +-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT +-- FROM INFORMATION_SCHEMA.COLUMNS +-- WHERE TABLE_NAME = 'lq_hytk_kjbsyj' +-- AND COLUMN_NAME = 'F_KjbCategory';