diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys.Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys.Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs
new file mode 100644
index 0000000..c50954a
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys.Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary
+{
+ ///
+ /// 科技部老师统计数据输出
+ ///
+ public class TechTeacherStatisticsOutput
+ {
+ ///
+ /// 员工ID
+ ///
+ public string EmployeeId { get; set; }
+
+ ///
+ /// 员工姓名
+ ///
+ public string EmployeeName { get; set; }
+
+ ///
+ /// 开单业绩
+ ///
+ public decimal OrderAchievement { get; set; }
+
+ ///
+ /// 消耗业绩
+ ///
+ public decimal ConsumeAchievement { get; set; }
+
+ ///
+ /// 退卡业绩
+ ///
+ public decimal RefundAchievement { get; set; }
+
+ ///
+ /// 人头(按月份+客户去重统计)
+ ///
+ public int PersonCount { get; set; }
+
+ ///
+ /// 人次(按日期+客户去重统计)
+ ///
+ public decimal PersonTimes { get; set; }
+
+ ///
+ /// 手工费
+ ///
+ public decimal LaborCost { get; set; }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsageApplication/LqInventoryUsageApplicationListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsageApplication/LqInventoryUsageApplicationListOutput.cs
index 930dc84..a3fc6ec 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsageApplication/LqInventoryUsageApplicationListOutput.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsageApplication/LqInventoryUsageApplicationListOutput.cs
@@ -89,6 +89,11 @@ namespace NCC.Extend.Entitys.Dto.LqInventoryUsageApplication
public List currentApprovers { get; set; }
///
+ /// 当前审批人ID列表(用于快速获取审批人ID)
+ ///
+ public List approverIds { get; set; }
+
+ ///
/// 使用记录统计信息(批次总数量、总金额等)
///
public BatchUsageInfo batchUsageInfo { get; set; }
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherStatisticsInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherStatisticsInput.cs
new file mode 100644
index 0000000..2ee97b8
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherStatisticsInput.cs
@@ -0,0 +1,18 @@
+namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary
+{
+ ///
+ /// 科技部老师统计数据查询参数
+ ///
+ public class TechTeacherStatisticsInput
+ {
+ ///
+ /// 年份
+ ///
+ public int Year { get; set; }
+
+ ///
+ /// 月份(1-12)
+ ///
+ public int Month { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs
new file mode 100644
index 0000000..aea0d3b
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary
+{
+ ///
+ /// 科技部老师统计数据输出
+ ///
+ public class TechTeacherStatisticsOutput
+ {
+ ///
+ /// 员工ID
+ ///
+ public string EmployeeId { get; set; }
+
+ ///
+ /// 员工姓名
+ ///
+ public string EmployeeName { get; set; }
+
+ ///
+ /// 开单业绩
+ ///
+ public decimal OrderAchievement { get; set; }
+
+ ///
+ /// 消耗业绩
+ ///
+ public decimal ConsumeAchievement { get; set; }
+
+ ///
+ /// 退卡业绩
+ ///
+ public decimal RefundAchievement { get; set; }
+
+ ///
+ /// 人头(按月份+客户去重统计)
+ ///
+ public int PersonCount { get; set; }
+
+ ///
+ /// 人次(按日期+客户去重统计)
+ ///
+ public decimal PersonTimes { get; set; }
+
+ ///
+ /// 手工费(仅统计耗卡中的手工费)
+ ///
+ public decimal LaborCost { get; set; }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_application_node/LqInventoryUsageApplicationNodeEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_application_node/LqInventoryUsageApplicationNodeEntity.cs
index 68fa78a..07cc06b 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_application_node/LqInventoryUsageApplicationNodeEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_application_node/LqInventoryUsageApplicationNodeEntity.cs
@@ -64,3 +64,4 @@ namespace NCC.Extend.Entitys.lq_inventory_usage_application_node
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_approval_record/LqInventoryUsageApprovalRecordEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_approval_record/LqInventoryUsageApprovalRecordEntity.cs
index b9933d3..e4472cc 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_approval_record/LqInventoryUsageApprovalRecordEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_approval_record/LqInventoryUsageApprovalRecordEntity.cs
@@ -82,3 +82,4 @@ namespace NCC.Extend.Entitys.lq_inventory_usage_approval_record
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
index 8c53d98..8d53f7c 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
@@ -428,7 +428,7 @@ namespace NCC.Extend
CreateTime = DateTime.Now,
IsEffective = StatusEnum.有效.GetHashCode()
};
-
+
// 设置申请总金额(该批次所有商品的总价)
// 使用反射设置,避免服务未重启时找不到属性的问题
try
@@ -450,6 +450,27 @@ namespace NCC.Extend
{
throw NCCException.Oh("创建申请记录失败");
}
+
+ // 创建审批记录(当前节点的审批人)
+ var approvalRecord = new LqInventoryUsageApprovalRecordEntity
+ {
+ Id = YitIdHelper.NextId().ToString(),
+ ApplicationId = applicationEntity.Id,
+ NodeId = applicationEntity.CurrentNodeId,
+ NodeOrder = 1,
+ ApproverId = approverUser.Id,
+ ApproverName = approverUser.RealName ?? "",
+ ApprovalResult = "待审批",
+ ApprovalOpinion = "",
+ ApprovalTime = DateTime.Now,
+ IsCurrentNode = 1
+ };
+
+ var approvalInsertCount = await _db.Insertable(approvalRecord).ExecuteCommandAsync();
+ if (approvalInsertCount <= 0)
+ {
+ throw NCCException.Oh("创建审批记录失败");
+ }
}
_db.Ado.CommitTran();
@@ -779,7 +800,7 @@ namespace NCC.Extend
ReceiveUser = application.ReceiveUser,
Remarks = application.Remarks
};
-
+
// 设置申请总金额(该批次所有商品的总价)
// 使用反射设置,避免服务未重启时找不到属性的问题
try
@@ -1595,8 +1616,8 @@ namespace NCC.Extend
// 关键字搜索(申请编号、申请人姓名、门店名称)
if (!string.IsNullOrWhiteSpace(input.keyword))
{
- query = query.Where((app, store) =>
- app.Id.Contains(input.keyword) ||
+ query = query.Where((app, store) =>
+ app.Id.Contains(input.keyword) ||
app.ApplicationUserName.Contains(input.keyword) ||
store.Dm.Contains(input.keyword));
}
@@ -1651,17 +1672,20 @@ namespace NCC.Extend
// 获取所有申请ID,用于查询审批人和使用记录统计
var applicationIds = pageList.list.Select(x => x.id).ToList();
+ // 初始化审批人相关数据
+ var approvalRecords = new List();
+ var approverDict = new Dictionary();
+
if (applicationIds.Any())
{
// 查询当前审批人信息(通过审批记录表,查找当前节点的审批人)
- var approvalRecords = await _db.Queryable()
+ approvalRecords = await _db.Queryable()
.Where(x => applicationIds.Contains(x.ApplicationId) && x.IsCurrentNode == 1)
.Where(x => x.ApprovalResult == "待审批" || x.ApprovalResult == "")
.ToListAsync();
// 获取审批人ID列表
- var approverIds = approvalRecords.Select(x => x.ApproverId).Distinct().ToList();
- var approverDict = new Dictionary();
+ var approverIds = approvalRecords.Select(x => x.ApproverId).Distinct().Where(x => !string.IsNullOrEmpty(x)).ToList();
if (approverIds.Any())
{
var approvers = await _db.Queryable()
@@ -1670,9 +1694,13 @@ namespace NCC.Extend
.ToListAsync();
approverDict = approvers.ToDictionary(k => k.Id, v => v.RealName ?? "");
}
+ }
- // 查询使用记录统计(按批次ID分组)
- var batchIds = pageList.list.Select(x => x.usageBatchId).Distinct().ToList();
+ // 查询使用记录统计(按批次ID分组)
+ var batchIds = pageList.list.Select(x => x.usageBatchId).Distinct().ToList();
+ var usageDict = new Dictionary();
+ if (batchIds.Any())
+ {
var usageRecords = await _db.Queryable()
.Where(x => batchIds.Contains(x.UsageBatchId))
.Where(x => x.IsEffective == StatusEnum.有效.GetHashCode())
@@ -1686,64 +1714,70 @@ namespace NCC.Extend
})
.ToListAsync();
- var usageDict = usageRecords.ToDictionary(k => k.UsageBatchId, v => v);
+ usageDict = usageRecords.ToDictionary(k => k.UsageBatchId, v => (dynamic)v);
+ }
- // 查询领取人信息
- var receiveUserIds = pageList.list.Where(x => !string.IsNullOrWhiteSpace(x.receiveUser))
- .Select(x => x.receiveUser)
+ // 查询领取人信息
+ var receiveUserIds = pageList.list.Where(x => !string.IsNullOrWhiteSpace(x.receiveUser))
+ .Select(x => x.receiveUser)
+ .Distinct()
+ .ToList();
+ var receiveUserDict = new Dictionary();
+ if (receiveUserIds.Any())
+ {
+ var receiveUsers = await _db.Queryable()
+ .Where(x => receiveUserIds.Contains(x.Id))
+ .Select(x => new { x.Id, x.RealName })
+ .ToListAsync();
+ receiveUserDict = receiveUsers.ToDictionary(k => k.Id, v => v.RealName ?? "");
+ }
+
+ // 填充审批人和使用记录统计信息
+ foreach (var item in pageList.list)
+ {
+ // 当前审批人信息
+ var currentApprovers = approvalRecords
+ .Where(x => x.ApplicationId == item.id)
+ .Select(x => new CurrentApproverInfo
+ {
+ approverId = x.ApproverId,
+ approverName = approverDict.ContainsKey(x.ApproverId) ? approverDict[x.ApproverId] : x.ApproverName,
+ approvalResult = x.ApprovalResult
+ })
+ .ToList();
+ item.currentApprovers = currentApprovers ?? new List();
+ // 审批人ID列表(从审批人信息中提取)
+ item.approverIds = currentApprovers
+ .Where(x => !string.IsNullOrEmpty(x.approverId))
+ .Select(x => x.approverId)
.Distinct()
.ToList();
- var receiveUserDict = new Dictionary();
- if (receiveUserIds.Any())
- {
- var receiveUsers = await _db.Queryable()
- .Where(x => receiveUserIds.Contains(x.Id))
- .Select(x => new { x.Id, x.RealName })
- .ToListAsync();
- receiveUserDict = receiveUsers.ToDictionary(k => k.Id, v => v.RealName ?? "");
- }
- // 填充审批人和使用记录统计信息
- foreach (var item in pageList.list)
+ // 使用记录统计信息
+ if (usageDict.ContainsKey(item.usageBatchId))
{
- // 当前审批人信息
- var currentApprovers = approvalRecords
- .Where(x => x.ApplicationId == item.id)
- .Select(x => new CurrentApproverInfo
- {
- approverId = x.ApproverId,
- approverName = approverDict.ContainsKey(x.ApproverId) ? approverDict[x.ApproverId] : x.ApproverName,
- approvalResult = x.ApprovalResult
- })
- .ToList();
- item.currentApprovers = currentApprovers;
-
- // 使用记录统计信息
- if (usageDict.ContainsKey(item.usageBatchId))
+ var usage = usageDict[item.usageBatchId];
+ item.batchUsageInfo = new BatchUsageInfo
{
- var usage = usageDict[item.usageBatchId];
- item.batchUsageInfo = new BatchUsageInfo
- {
- totalCount = usage.TotalCount,
- totalQuantity = usage.TotalQuantity,
- totalAmount = usage.TotalAmount
- };
- }
- else
+ totalCount = usage.TotalCount,
+ totalQuantity = usage.TotalQuantity,
+ totalAmount = usage.TotalAmount
+ };
+ }
+ else
+ {
+ item.batchUsageInfo = new BatchUsageInfo
{
- item.batchUsageInfo = new BatchUsageInfo
- {
- totalCount = 0,
- totalQuantity = 0,
- totalAmount = 0
- };
- }
+ totalCount = 0,
+ totalQuantity = 0,
+ totalAmount = 0
+ };
+ }
- // 领取人姓名
- if (!string.IsNullOrWhiteSpace(item.receiveUser) && receiveUserDict.ContainsKey(item.receiveUser))
- {
- item.receiveUserName = receiveUserDict[item.receiveUser];
- }
+ // 领取人姓名
+ if (!string.IsNullOrWhiteSpace(item.receiveUser) && receiveUserDict.ContainsKey(item.receiveUser))
+ {
+ item.receiveUserName = receiveUserDict[item.receiveUser];
}
}
@@ -1803,7 +1837,7 @@ namespace NCC.Extend
// 由于审批记录在审批时才创建,这里需要通过审批记录表查找当前用户已审批的记录
// 然后排除这些申请,找出状态为"审批中"但当前用户还未审批的申请
// 注意:这里需要根据实际业务逻辑调整,如果审批人信息存储在节点审批人表中,应该通过那个表查询
-
+
// 先查询当前用户已经审批过的申请ID(排除这些)
var approvedApplicationIds = await _db.Queryable()
.Where(x => x.ApproverId == currentUserId)
@@ -1811,13 +1845,13 @@ namespace NCC.Extend
.Select(x => x.ApplicationId)
.Distinct()
.ToListAsync();
-
+
// 查询所有状态为"审批中"的申请ID
var allPendingApplicationIds = await _db.Queryable()
.Where(x => x.ApprovalStatus == "审批中" && x.IsEffective == StatusEnum.有效.GetHashCode())
.Select(x => x.Id)
.ToListAsync();
-
+
// 找出当前用户需要审批的申请(状态为"审批中"且当前用户还未审批的)
// 注意:这里简化处理,实际应该通过审批人配置表来确定审批人
// 如果审批人信息没有单独存储,可能需要通过其他方式确定
@@ -1859,8 +1893,8 @@ namespace NCC.Extend
// 关键字搜索
if (!string.IsNullOrWhiteSpace(input.keyword))
{
- query = query.Where((app, store) =>
- app.Id.Contains(input.keyword) ||
+ query = query.Where((app, store) =>
+ app.Id.Contains(input.keyword) ||
app.ApplicationUserName.Contains(input.keyword) ||
store.Dm.Contains(input.keyword));
}
@@ -1965,5 +1999,106 @@ namespace NCC.Extend
#endregion
+ #region 测试接口:为现有申请记录添加审批记录
+ ///
+ /// 为现有申请记录添加审批记录(测试用)
+ ///
+ ///
+ /// 为"审批中"状态的申请记录添加当前节点的审批记录,用于测试审批人信息返回
+ ///
+ /// 申请ID(可选,不传则处理所有"审批中"状态的申请)
+ /// 审批人ID(可选,不传则使用admin)
+ /// 处理结果
+ [HttpPost("Test/AddApprovalRecord")]
+ public async Task AddApprovalRecordForTest(string applicationId = null, string approverId = null)
+ {
+ try
+ {
+ _db.Ado.BeginTran();
+
+ // 获取审批人信息(默认使用admin)
+ var defaultApproverId = approverId ?? "admin";
+ var approverUser = await _db.Queryable()
+ .Where(x => x.Id == defaultApproverId)
+ .Select(x => new { x.Id, x.RealName })
+ .FirstAsync();
+
+ if (approverUser == null)
+ {
+ throw NCCException.Oh("审批人不存在");
+ }
+
+ // 查询需要处理的申请记录
+ var query = _db.Queryable()
+ .Where(x => x.ApprovalStatus == "审批中");
+
+ if (!string.IsNullOrWhiteSpace(applicationId))
+ {
+ query = query.Where(x => x.Id == applicationId);
+ }
+
+ var applications = await query.ToListAsync();
+
+ if (!applications.Any())
+ {
+ return new { success = true, message = "没有需要处理的申请记录", count = 0 };
+ }
+
+ var successCount = 0;
+ var skipCount = 0;
+
+ foreach (var application in applications)
+ {
+ // 检查是否已存在当前节点的审批记录
+ var existingRecord = await _db.Queryable()
+ .Where(x => x.ApplicationId == application.Id && x.IsCurrentNode == 1)
+ .Where(x => x.ApprovalResult == "待审批" || x.ApprovalResult == "")
+ .FirstAsync();
+
+ if (existingRecord != null)
+ {
+ skipCount++;
+ continue;
+ }
+
+ // 创建审批记录
+ var approvalRecord = new LqInventoryUsageApprovalRecordEntity
+ {
+ Id = YitIdHelper.NextId().ToString(),
+ ApplicationId = application.Id,
+ NodeId = application.CurrentNodeId ?? application.Id, // 使用申请ID作为节点ID(如果CurrentNodeId为空)
+ NodeOrder = 1,
+ ApproverId = approverUser.Id,
+ ApproverName = approverUser.RealName ?? "",
+ ApprovalResult = "待审批",
+ ApprovalOpinion = "",
+ ApprovalTime = DateTime.Now,
+ IsCurrentNode = 1
+ };
+
+ await _db.Insertable(approvalRecord).ExecuteCommandAsync();
+ successCount++;
+ }
+
+ _db.Ado.CommitTran();
+
+ return new
+ {
+ success = true,
+ message = $"处理完成:成功添加 {successCount} 条审批记录,跳过 {skipCount} 条(已存在)",
+ total = applications.Count,
+ successCount = successCount,
+ skipCount = skipCount
+ };
+ }
+ catch (Exception ex)
+ {
+ _db.Ado.RollbackTran();
+ _logger.LogError(ex, "添加审批记录失败");
+ throw NCCException.Oh($"添加失败:{ex.Message}");
+ }
+ }
+ #endregion
+
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs
index d8e49dc..a68a498 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs
@@ -619,6 +619,7 @@ namespace NCC.Extend
salary.DailyAverageConsumption,
salary.DailyAverageProjectCount,
daysInMonth,
+ salary.WorkingDays,
isNewStore);
// 4.2 提成计算
@@ -732,7 +733,7 @@ namespace NCC.Extend
///
/// 计算底薪
///
- private decimal CalculateBaseSalary(decimal dailyAvgConsumption, decimal dailyAvgProjectCount, int daysInMonth, bool isNewStore)
+ private decimal CalculateBaseSalary(decimal dailyAvgConsumption, decimal dailyAvgProjectCount, int daysInMonth, decimal workingDays, bool isNewStore)
{
// 规则调整:按日均计算
// 一星:月消耗 10000 / 当月天数,项目数 96 / 当月天数
@@ -788,7 +789,13 @@ namespace NCC.Extend
baseSalary = 2000;
}
- return baseSalary;
+ // 最终计算:(底薪 / 当月天数) * 在店天数
+ if (daysInMonth > 0)
+ {
+ baseSalary = (baseSalary / daysInMonth) * workingDays;
+ }
+
+ return Math.Round(baseSalary, 2);
}
///
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqTechTeacherSalaryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqTechTeacherSalaryService.cs
index 84c73d4..655a5f0 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqTechTeacherSalaryService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqTechTeacherSalaryService.cs
@@ -13,6 +13,7 @@ using NCC.Extend.Entitys.lq_attendance_summary;
using NCC.Extend.Entitys.lq_tech_teacher_salary_statistics;
using NCC.Extend.Entitys.lq_xh_hyhk;
using NCC.Extend.Entitys.lq_xh_kjbsyj;
+using NCC.Extend.Entitys.lq_person_times_record;
using NCC.System.Entitys.Permission;
using SqlSugar;
using System;
@@ -509,6 +510,199 @@ namespace NCC.Extend
return (1m, consumeAchievement * 0.01m);
}
}
+
+ ///
+ /// 统计科技部老师某个月的数据
+ ///
+ ///
+ /// 实时统计科技部老师某个月的数据,包括:
+ /// - 开单业绩:从 lq_kd_kjbsyj 表统计
+ /// - 消耗业绩:从 lq_xh_kjbsyj 表统计(关联 lq_xh_hyhk 获取时间)
+ /// - 退卡业绩:从 lq_hytk_kjbsyj 表统计
+ /// - 手工费:从耗卡表(lq_xh_kjbsyj)的 F_LaborCost 字段统计
+ /// - 人头:从 lq_person_times_record 表统计(按月份+客户去重)
+ /// - 人次:从 lq_person_times_record 表统计(按日期+客户去重)
+ ///
+ /// 示例请求:
+ /// ```json
+ /// {
+ /// "year": 2025,
+ /// "month": 11
+ /// }
+ /// ```
+ ///
+ /// 查询参数(年份、月份)
+ /// 科技部老师统计数据列表
+ [HttpGet("statistics")]
+ public async Task> GetTechTeacherStatistics([FromQuery] TechTeacherStatisticsInput input)
+ {
+ // 1. 参数验证
+ if (input.Year < 2020 || input.Year > 2100)
+ {
+ throw new Exception("年份范围不正确");
+ }
+ if (input.Month < 1 || input.Month > 12)
+ {
+ throw new Exception("月份范围不正确(1-12)");
+ }
+
+ // 2. 计算时间范围
+ var startDate = new DateTime(input.Year, input.Month, 1);
+ var endDate = startDate.AddMonths(1).AddDays(-1);
+ var monthStr = $"{input.Year}{input.Month:D2}";
+
+ // 3. 获取所有科技部老师(岗位为"科技老师")
+ var techTeacherList = await _db.Queryable()
+ .Where(x => x.Gw == "科技老师")
+ .Select(x => new
+ {
+ EmployeeId = x.Id,
+ EmployeeName = x.RealName,
+ EmployeeAccount = x.Account
+ })
+ .ToListAsync();
+
+ if (techTeacherList == null || !techTeacherList.Any())
+ {
+ return new List();
+ }
+
+ var teacherIds = techTeacherList.Select(x => x.EmployeeId).ToList();
+ var teacherAccounts = techTeacherList.Where(x => !string.IsNullOrEmpty(x.EmployeeAccount)).Select(x => x.EmployeeAccount).ToList();
+
+ // 4. 使用聚合查询统计开单业绩和手工费(优化性能)
+ // 注意:kjblsyj字段是varchar类型,需要转换
+ var orderStatsList = await _db.Queryable()
+ .Where(x => x.Yjsj >= startDate && x.Yjsj <= endDate.AddDays(1) && x.IsEffective == 1)
+ .Where(x => teacherIds.Contains(x.Kjbls) || teacherAccounts.Contains(x.Kjblszh))
+ .ToListAsync();
+
+ var orderStats = orderStatsList
+ .Where(x => !string.IsNullOrEmpty(x.Kjbls))
+ .GroupBy(x => x.Kjbls)
+ .Select(g => new
+ {
+ TeacherId = g.Key,
+ OrderAchievement = g.Sum(x => decimal.TryParse(x.Kjblsyj, out var val) ? val : 0m)
+ })
+ .ToList();
+
+ // 5. 使用聚合查询统计消耗业绩和手工费(关联耗卡主表获取时间)
+ var consumeStatsList = await _db.Queryable(
+ (kjbsyj, hyhk) => kjbsyj.Glkdbh == hyhk.Id && hyhk.IsEffective == 1)
+ .Where((kjbsyj, hyhk) => kjbsyj.IsEffective == 1
+ && hyhk.Hksj >= startDate && hyhk.Hksj <= endDate.AddDays(1))
+ .Where((kjbsyj, hyhk) => teacherIds.Contains(kjbsyj.Kjbls) || teacherAccounts.Contains(kjbsyj.Kjblszh))
+ .Select((kjbsyj, hyhk) => new
+ {
+ TeacherId = kjbsyj.Kjbls,
+ ConsumeAchievement = kjbsyj.Kjblsyj,
+ LaborCost = kjbsyj.LaborCost
+ })
+ .ToListAsync();
+
+ var consumeStats = consumeStatsList
+ .Where(x => !string.IsNullOrEmpty(x.TeacherId))
+ .GroupBy(x => x.TeacherId)
+ .Select(g => new
+ {
+ TeacherId = g.Key,
+ ConsumeAchievement = g.Sum(x => x.ConsumeAchievement ?? 0m),
+ LaborCost = g.Sum(x => x.LaborCost ?? 0m)
+ })
+ .ToList();
+
+ // 6. 使用聚合查询统计退卡业绩和手工费
+ var refundStatsList = await _db.Queryable()
+ .Where(x => x.Tksj >= startDate && x.Tksj <= endDate.AddDays(1) && x.IsEffective == 1)
+ .Where(x => teacherIds.Contains(x.Kjbls) || teacherAccounts.Contains(x.Kjblszh))
+ .ToListAsync();
+
+ var refundStats = refundStatsList
+ .Where(x => !string.IsNullOrEmpty(x.Kjbls))
+ .GroupBy(x => x.Kjbls)
+ .Select(g => new
+ {
+ TeacherId = g.Key,
+ RefundAchievement = g.Sum(x => x.Kjblsyj ?? 0m)
+ })
+ .ToList();
+
+ // 7. 统计人头(按月份+客户去重)
+ var personCountRecords = await _db.Queryable()
+ .Where(x => x.PersonType == "科技老师"
+ && x.WorkMonth == monthStr
+ && x.IsEffective == 1
+ && teacherIds.Contains(x.PersonId))
+ .ToListAsync();
+
+ var personCountStats = personCountRecords
+ .GroupBy(x => new { x.PersonId, x.MemberId })
+ .Select(g => new { TeacherId = g.Key.PersonId })
+ .GroupBy(x => x.TeacherId)
+ .Select(g => new
+ {
+ TeacherId = g.Key,
+ PersonCount = g.Count()
+ })
+ .ToList();
+
+ // 8. 统计人次(按日期+客户去重,汇总数量)
+ var personTimesRecords = await _db.Queryable()
+ .Where(x => x.PersonType == "科技老师"
+ && x.WorkMonth == monthStr
+ && x.IsEffective == 1
+ && teacherIds.Contains(x.PersonId))
+ .ToListAsync();
+
+ // 先按日期+客户去重,取最大数量,然后按老师汇总
+ var personTimesStats = personTimesRecords
+ .GroupBy(x => new { x.PersonId, x.WorkDate, x.MemberId })
+ .Select(g => new
+ {
+ TeacherId = g.Key.PersonId,
+ Quantity = g.Max(x => x.Quantity ?? 0m) // 按日期+客户去重,取最大数量
+ })
+ .GroupBy(x => x.TeacherId)
+ .Select(g => new
+ {
+ TeacherId = g.Key,
+ PersonTimes = g.Sum(x => x.Quantity) // 汇总所有去重后的数量
+ })
+ .ToList();
+
+ // 9. 构建结果字典(优化查找性能)
+ var orderDict = orderStats.ToDictionary(x => x.TeacherId, x => x);
+ var consumeDict = consumeStats.ToDictionary(x => x.TeacherId, x => x);
+ var refundDict = refundStats.ToDictionary(x => x.TeacherId, x => x);
+ var personCountDict = personCountStats.ToDictionary(x => x.TeacherId, x => x);
+ var personTimesDict = personTimesStats.ToDictionary(x => x.TeacherId, x => x);
+
+ // 10. 组装结果
+ var result = new List();
+ foreach (var teacher in techTeacherList)
+ {
+ var orderStat = orderDict.ContainsKey(teacher.EmployeeId) ? orderDict[teacher.EmployeeId] : null;
+ var consumeStat = consumeDict.ContainsKey(teacher.EmployeeId) ? consumeDict[teacher.EmployeeId] : null;
+ var refundStat = refundDict.ContainsKey(teacher.EmployeeId) ? refundDict[teacher.EmployeeId] : null;
+ var personCountStat = personCountDict.ContainsKey(teacher.EmployeeId) ? personCountDict[teacher.EmployeeId] : null;
+ var personTimesStat = personTimesDict.ContainsKey(teacher.EmployeeId) ? personTimesDict[teacher.EmployeeId] : null;
+
+ result.Add(new TechTeacherStatisticsOutput
+ {
+ EmployeeId = teacher.EmployeeId,
+ EmployeeName = teacher.EmployeeName,
+ OrderAchievement = orderStat?.OrderAchievement ?? 0m,
+ ConsumeAchievement = consumeStat?.ConsumeAchievement ?? 0m,
+ RefundAchievement = refundStat?.RefundAchievement ?? 0m,
+ PersonCount = personCountStat?.PersonCount ?? 0,
+ PersonTimes = personTimesStat?.PersonTimes ?? 0m,
+ LaborCost = consumeStat?.LaborCost ?? 0m // 手工费只统计耗卡中的手工费
+ });
+ }
+
+ return result;
+ }
}
}
diff --git a/sql/创建库存使用申请审批流程表.sql b/sql/创建库存使用申请审批流程表.sql
index 595ea58..4d22796 100644
--- a/sql/创建库存使用申请审批流程表.sql
+++ b/sql/创建库存使用申请审批流程表.sql
@@ -108,3 +108,4 @@ WHERE u.`F_UnitPrice` = 0 OR u.`F_UnitPrice` IS NULL;
+