Commit 88a30b7ae3b8c8ca690b6dc898f6baf6fe09ef07
Merge branch 'master' of http://39.98.150.180/antissoft/lvqianmeiye_ERP
Showing
10 changed files
with
530 additions
and
66 deletions
netcore/src/Modularity/Extend/NCC.Extend.Entitys.Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 科技部老师统计数据输出 | |
| 7 | + /// </summary> | |
| 8 | + public class TechTeacherStatisticsOutput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 员工ID | |
| 12 | + /// </summary> | |
| 13 | + public string EmployeeId { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 员工姓名 | |
| 17 | + /// </summary> | |
| 18 | + public string EmployeeName { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 开单业绩 | |
| 22 | + /// </summary> | |
| 23 | + public decimal OrderAchievement { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 消耗业绩 | |
| 27 | + /// </summary> | |
| 28 | + public decimal ConsumeAchievement { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 退卡业绩 | |
| 32 | + /// </summary> | |
| 33 | + public decimal RefundAchievement { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 人头(按月份+客户去重统计) | |
| 37 | + /// </summary> | |
| 38 | + public int PersonCount { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 人次(按日期+客户去重统计) | |
| 42 | + /// </summary> | |
| 43 | + public decimal PersonTimes { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 手工费 | |
| 47 | + /// </summary> | |
| 48 | + public decimal LaborCost { get; set; } | |
| 49 | + } | |
| 50 | +} | |
| 51 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsageApplication/LqInventoryUsageApplicationListOutput.cs
| ... | ... | @@ -89,6 +89,11 @@ namespace NCC.Extend.Entitys.Dto.LqInventoryUsageApplication |
| 89 | 89 | public List<CurrentApproverInfo> currentApprovers { get; set; } |
| 90 | 90 | |
| 91 | 91 | /// <summary> |
| 92 | + /// 当前审批人ID列表(用于快速获取审批人ID) | |
| 93 | + /// </summary> | |
| 94 | + public List<string> approverIds { get; set; } | |
| 95 | + | |
| 96 | + /// <summary> | |
| 92 | 97 | /// 使用记录统计信息(批次总数量、总金额等) |
| 93 | 98 | /// </summary> |
| 94 | 99 | public BatchUsageInfo batchUsageInfo { get; set; } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherStatisticsInput.cs
0 → 100644
| 1 | +namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary | |
| 2 | +{ | |
| 3 | + /// <summary> | |
| 4 | + /// 科技部老师统计数据查询参数 | |
| 5 | + /// </summary> | |
| 6 | + public class TechTeacherStatisticsInput | |
| 7 | + { | |
| 8 | + /// <summary> | |
| 9 | + /// 年份 | |
| 10 | + /// </summary> | |
| 11 | + public int Year { get; set; } | |
| 12 | + | |
| 13 | + /// <summary> | |
| 14 | + /// 月份(1-12) | |
| 15 | + /// </summary> | |
| 16 | + public int Month { get; set; } | |
| 17 | + } | |
| 18 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 科技部老师统计数据输出 | |
| 7 | + /// </summary> | |
| 8 | + public class TechTeacherStatisticsOutput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 员工ID | |
| 12 | + /// </summary> | |
| 13 | + public string EmployeeId { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 员工姓名 | |
| 17 | + /// </summary> | |
| 18 | + public string EmployeeName { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 开单业绩 | |
| 22 | + /// </summary> | |
| 23 | + public decimal OrderAchievement { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 消耗业绩 | |
| 27 | + /// </summary> | |
| 28 | + public decimal ConsumeAchievement { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 退卡业绩 | |
| 32 | + /// </summary> | |
| 33 | + public decimal RefundAchievement { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 人头(按月份+客户去重统计) | |
| 37 | + /// </summary> | |
| 38 | + public int PersonCount { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 人次(按日期+客户去重统计) | |
| 42 | + /// </summary> | |
| 43 | + public decimal PersonTimes { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 手工费(仅统计耗卡中的手工费) | |
| 47 | + /// </summary> | |
| 48 | + public decimal LaborCost { get; set; } | |
| 49 | + } | |
| 50 | +} | |
| 51 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_application_node/LqInventoryUsageApplicationNodeEntity.cs
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_approval_record/LqInventoryUsageApprovalRecordEntity.cs
netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
| ... | ... | @@ -428,7 +428,7 @@ namespace NCC.Extend |
| 428 | 428 | CreateTime = DateTime.Now, |
| 429 | 429 | IsEffective = StatusEnum.有效.GetHashCode() |
| 430 | 430 | }; |
| 431 | - | |
| 431 | + | |
| 432 | 432 | // 设置申请总金额(该批次所有商品的总价) |
| 433 | 433 | // 使用反射设置,避免服务未重启时找不到属性的问题 |
| 434 | 434 | try |
| ... | ... | @@ -450,6 +450,27 @@ namespace NCC.Extend |
| 450 | 450 | { |
| 451 | 451 | throw NCCException.Oh("创建申请记录失败"); |
| 452 | 452 | } |
| 453 | + | |
| 454 | + // 创建审批记录(当前节点的审批人) | |
| 455 | + var approvalRecord = new LqInventoryUsageApprovalRecordEntity | |
| 456 | + { | |
| 457 | + Id = YitIdHelper.NextId().ToString(), | |
| 458 | + ApplicationId = applicationEntity.Id, | |
| 459 | + NodeId = applicationEntity.CurrentNodeId, | |
| 460 | + NodeOrder = 1, | |
| 461 | + ApproverId = approverUser.Id, | |
| 462 | + ApproverName = approverUser.RealName ?? "", | |
| 463 | + ApprovalResult = "待审批", | |
| 464 | + ApprovalOpinion = "", | |
| 465 | + ApprovalTime = DateTime.Now, | |
| 466 | + IsCurrentNode = 1 | |
| 467 | + }; | |
| 468 | + | |
| 469 | + var approvalInsertCount = await _db.Insertable(approvalRecord).ExecuteCommandAsync(); | |
| 470 | + if (approvalInsertCount <= 0) | |
| 471 | + { | |
| 472 | + throw NCCException.Oh("创建审批记录失败"); | |
| 473 | + } | |
| 453 | 474 | } |
| 454 | 475 | |
| 455 | 476 | _db.Ado.CommitTran(); |
| ... | ... | @@ -779,7 +800,7 @@ namespace NCC.Extend |
| 779 | 800 | ReceiveUser = application.ReceiveUser, |
| 780 | 801 | Remarks = application.Remarks |
| 781 | 802 | }; |
| 782 | - | |
| 803 | + | |
| 783 | 804 | // 设置申请总金额(该批次所有商品的总价) |
| 784 | 805 | // 使用反射设置,避免服务未重启时找不到属性的问题 |
| 785 | 806 | try |
| ... | ... | @@ -1595,8 +1616,8 @@ namespace NCC.Extend |
| 1595 | 1616 | // 关键字搜索(申请编号、申请人姓名、门店名称) |
| 1596 | 1617 | if (!string.IsNullOrWhiteSpace(input.keyword)) |
| 1597 | 1618 | { |
| 1598 | - query = query.Where((app, store) => | |
| 1599 | - app.Id.Contains(input.keyword) || | |
| 1619 | + query = query.Where((app, store) => | |
| 1620 | + app.Id.Contains(input.keyword) || | |
| 1600 | 1621 | app.ApplicationUserName.Contains(input.keyword) || |
| 1601 | 1622 | store.Dm.Contains(input.keyword)); |
| 1602 | 1623 | } |
| ... | ... | @@ -1651,17 +1672,20 @@ namespace NCC.Extend |
| 1651 | 1672 | // 获取所有申请ID,用于查询审批人和使用记录统计 |
| 1652 | 1673 | var applicationIds = pageList.list.Select(x => x.id).ToList(); |
| 1653 | 1674 | |
| 1675 | + // 初始化审批人相关数据 | |
| 1676 | + var approvalRecords = new List<LqInventoryUsageApprovalRecordEntity>(); | |
| 1677 | + var approverDict = new Dictionary<string, string>(); | |
| 1678 | + | |
| 1654 | 1679 | if (applicationIds.Any()) |
| 1655 | 1680 | { |
| 1656 | 1681 | // 查询当前审批人信息(通过审批记录表,查找当前节点的审批人) |
| 1657 | - var approvalRecords = await _db.Queryable<LqInventoryUsageApprovalRecordEntity>() | |
| 1682 | + approvalRecords = await _db.Queryable<LqInventoryUsageApprovalRecordEntity>() | |
| 1658 | 1683 | .Where(x => applicationIds.Contains(x.ApplicationId) && x.IsCurrentNode == 1) |
| 1659 | 1684 | .Where(x => x.ApprovalResult == "待审批" || x.ApprovalResult == "") |
| 1660 | 1685 | .ToListAsync(); |
| 1661 | 1686 | |
| 1662 | 1687 | // 获取审批人ID列表 |
| 1663 | - var approverIds = approvalRecords.Select(x => x.ApproverId).Distinct().ToList(); | |
| 1664 | - var approverDict = new Dictionary<string, string>(); | |
| 1688 | + var approverIds = approvalRecords.Select(x => x.ApproverId).Distinct().Where(x => !string.IsNullOrEmpty(x)).ToList(); | |
| 1665 | 1689 | if (approverIds.Any()) |
| 1666 | 1690 | { |
| 1667 | 1691 | var approvers = await _db.Queryable<UserEntity>() |
| ... | ... | @@ -1670,9 +1694,13 @@ namespace NCC.Extend |
| 1670 | 1694 | .ToListAsync(); |
| 1671 | 1695 | approverDict = approvers.ToDictionary(k => k.Id, v => v.RealName ?? ""); |
| 1672 | 1696 | } |
| 1697 | + } | |
| 1673 | 1698 | |
| 1674 | - // 查询使用记录统计(按批次ID分组) | |
| 1675 | - var batchIds = pageList.list.Select(x => x.usageBatchId).Distinct().ToList(); | |
| 1699 | + // 查询使用记录统计(按批次ID分组) | |
| 1700 | + var batchIds = pageList.list.Select(x => x.usageBatchId).Distinct().ToList(); | |
| 1701 | + var usageDict = new Dictionary<string, dynamic>(); | |
| 1702 | + if (batchIds.Any()) | |
| 1703 | + { | |
| 1676 | 1704 | var usageRecords = await _db.Queryable<LqInventoryUsageEntity>() |
| 1677 | 1705 | .Where(x => batchIds.Contains(x.UsageBatchId)) |
| 1678 | 1706 | .Where(x => x.IsEffective == StatusEnum.有效.GetHashCode()) |
| ... | ... | @@ -1686,64 +1714,70 @@ namespace NCC.Extend |
| 1686 | 1714 | }) |
| 1687 | 1715 | .ToListAsync(); |
| 1688 | 1716 | |
| 1689 | - var usageDict = usageRecords.ToDictionary(k => k.UsageBatchId, v => v); | |
| 1717 | + usageDict = usageRecords.ToDictionary(k => k.UsageBatchId, v => (dynamic)v); | |
| 1718 | + } | |
| 1690 | 1719 | |
| 1691 | - // 查询领取人信息 | |
| 1692 | - var receiveUserIds = pageList.list.Where(x => !string.IsNullOrWhiteSpace(x.receiveUser)) | |
| 1693 | - .Select(x => x.receiveUser) | |
| 1720 | + // 查询领取人信息 | |
| 1721 | + var receiveUserIds = pageList.list.Where(x => !string.IsNullOrWhiteSpace(x.receiveUser)) | |
| 1722 | + .Select(x => x.receiveUser) | |
| 1723 | + .Distinct() | |
| 1724 | + .ToList(); | |
| 1725 | + var receiveUserDict = new Dictionary<string, string>(); | |
| 1726 | + if (receiveUserIds.Any()) | |
| 1727 | + { | |
| 1728 | + var receiveUsers = await _db.Queryable<UserEntity>() | |
| 1729 | + .Where(x => receiveUserIds.Contains(x.Id)) | |
| 1730 | + .Select(x => new { x.Id, x.RealName }) | |
| 1731 | + .ToListAsync(); | |
| 1732 | + receiveUserDict = receiveUsers.ToDictionary(k => k.Id, v => v.RealName ?? ""); | |
| 1733 | + } | |
| 1734 | + | |
| 1735 | + // 填充审批人和使用记录统计信息 | |
| 1736 | + foreach (var item in pageList.list) | |
| 1737 | + { | |
| 1738 | + // 当前审批人信息 | |
| 1739 | + var currentApprovers = approvalRecords | |
| 1740 | + .Where(x => x.ApplicationId == item.id) | |
| 1741 | + .Select(x => new CurrentApproverInfo | |
| 1742 | + { | |
| 1743 | + approverId = x.ApproverId, | |
| 1744 | + approverName = approverDict.ContainsKey(x.ApproverId) ? approverDict[x.ApproverId] : x.ApproverName, | |
| 1745 | + approvalResult = x.ApprovalResult | |
| 1746 | + }) | |
| 1747 | + .ToList(); | |
| 1748 | + item.currentApprovers = currentApprovers ?? new List<CurrentApproverInfo>(); | |
| 1749 | + // 审批人ID列表(从审批人信息中提取) | |
| 1750 | + item.approverIds = currentApprovers | |
| 1751 | + .Where(x => !string.IsNullOrEmpty(x.approverId)) | |
| 1752 | + .Select(x => x.approverId) | |
| 1694 | 1753 | .Distinct() |
| 1695 | 1754 | .ToList(); |
| 1696 | - var receiveUserDict = new Dictionary<string, string>(); | |
| 1697 | - if (receiveUserIds.Any()) | |
| 1698 | - { | |
| 1699 | - var receiveUsers = await _db.Queryable<UserEntity>() | |
| 1700 | - .Where(x => receiveUserIds.Contains(x.Id)) | |
| 1701 | - .Select(x => new { x.Id, x.RealName }) | |
| 1702 | - .ToListAsync(); | |
| 1703 | - receiveUserDict = receiveUsers.ToDictionary(k => k.Id, v => v.RealName ?? ""); | |
| 1704 | - } | |
| 1705 | 1755 | |
| 1706 | - // 填充审批人和使用记录统计信息 | |
| 1707 | - foreach (var item in pageList.list) | |
| 1756 | + // 使用记录统计信息 | |
| 1757 | + if (usageDict.ContainsKey(item.usageBatchId)) | |
| 1708 | 1758 | { |
| 1709 | - // 当前审批人信息 | |
| 1710 | - var currentApprovers = approvalRecords | |
| 1711 | - .Where(x => x.ApplicationId == item.id) | |
| 1712 | - .Select(x => new CurrentApproverInfo | |
| 1713 | - { | |
| 1714 | - approverId = x.ApproverId, | |
| 1715 | - approverName = approverDict.ContainsKey(x.ApproverId) ? approverDict[x.ApproverId] : x.ApproverName, | |
| 1716 | - approvalResult = x.ApprovalResult | |
| 1717 | - }) | |
| 1718 | - .ToList(); | |
| 1719 | - item.currentApprovers = currentApprovers; | |
| 1720 | - | |
| 1721 | - // 使用记录统计信息 | |
| 1722 | - if (usageDict.ContainsKey(item.usageBatchId)) | |
| 1759 | + var usage = usageDict[item.usageBatchId]; | |
| 1760 | + item.batchUsageInfo = new BatchUsageInfo | |
| 1723 | 1761 | { |
| 1724 | - var usage = usageDict[item.usageBatchId]; | |
| 1725 | - item.batchUsageInfo = new BatchUsageInfo | |
| 1726 | - { | |
| 1727 | - totalCount = usage.TotalCount, | |
| 1728 | - totalQuantity = usage.TotalQuantity, | |
| 1729 | - totalAmount = usage.TotalAmount | |
| 1730 | - }; | |
| 1731 | - } | |
| 1732 | - else | |
| 1762 | + totalCount = usage.TotalCount, | |
| 1763 | + totalQuantity = usage.TotalQuantity, | |
| 1764 | + totalAmount = usage.TotalAmount | |
| 1765 | + }; | |
| 1766 | + } | |
| 1767 | + else | |
| 1768 | + { | |
| 1769 | + item.batchUsageInfo = new BatchUsageInfo | |
| 1733 | 1770 | { |
| 1734 | - item.batchUsageInfo = new BatchUsageInfo | |
| 1735 | - { | |
| 1736 | - totalCount = 0, | |
| 1737 | - totalQuantity = 0, | |
| 1738 | - totalAmount = 0 | |
| 1739 | - }; | |
| 1740 | - } | |
| 1771 | + totalCount = 0, | |
| 1772 | + totalQuantity = 0, | |
| 1773 | + totalAmount = 0 | |
| 1774 | + }; | |
| 1775 | + } | |
| 1741 | 1776 | |
| 1742 | - // 领取人姓名 | |
| 1743 | - if (!string.IsNullOrWhiteSpace(item.receiveUser) && receiveUserDict.ContainsKey(item.receiveUser)) | |
| 1744 | - { | |
| 1745 | - item.receiveUserName = receiveUserDict[item.receiveUser]; | |
| 1746 | - } | |
| 1777 | + // 领取人姓名 | |
| 1778 | + if (!string.IsNullOrWhiteSpace(item.receiveUser) && receiveUserDict.ContainsKey(item.receiveUser)) | |
| 1779 | + { | |
| 1780 | + item.receiveUserName = receiveUserDict[item.receiveUser]; | |
| 1747 | 1781 | } |
| 1748 | 1782 | } |
| 1749 | 1783 | |
| ... | ... | @@ -1803,7 +1837,7 @@ namespace NCC.Extend |
| 1803 | 1837 | // 由于审批记录在审批时才创建,这里需要通过审批记录表查找当前用户已审批的记录 |
| 1804 | 1838 | // 然后排除这些申请,找出状态为"审批中"但当前用户还未审批的申请 |
| 1805 | 1839 | // 注意:这里需要根据实际业务逻辑调整,如果审批人信息存储在节点审批人表中,应该通过那个表查询 |
| 1806 | - | |
| 1840 | + | |
| 1807 | 1841 | // 先查询当前用户已经审批过的申请ID(排除这些) |
| 1808 | 1842 | var approvedApplicationIds = await _db.Queryable<LqInventoryUsageApprovalRecordEntity>() |
| 1809 | 1843 | .Where(x => x.ApproverId == currentUserId) |
| ... | ... | @@ -1811,13 +1845,13 @@ namespace NCC.Extend |
| 1811 | 1845 | .Select(x => x.ApplicationId) |
| 1812 | 1846 | .Distinct() |
| 1813 | 1847 | .ToListAsync(); |
| 1814 | - | |
| 1848 | + | |
| 1815 | 1849 | // 查询所有状态为"审批中"的申请ID |
| 1816 | 1850 | var allPendingApplicationIds = await _db.Queryable<LqInventoryUsageApplicationEntity>() |
| 1817 | 1851 | .Where(x => x.ApprovalStatus == "审批中" && x.IsEffective == StatusEnum.有效.GetHashCode()) |
| 1818 | 1852 | .Select(x => x.Id) |
| 1819 | 1853 | .ToListAsync(); |
| 1820 | - | |
| 1854 | + | |
| 1821 | 1855 | // 找出当前用户需要审批的申请(状态为"审批中"且当前用户还未审批的) |
| 1822 | 1856 | // 注意:这里简化处理,实际应该通过审批人配置表来确定审批人 |
| 1823 | 1857 | // 如果审批人信息没有单独存储,可能需要通过其他方式确定 |
| ... | ... | @@ -1859,8 +1893,8 @@ namespace NCC.Extend |
| 1859 | 1893 | // 关键字搜索 |
| 1860 | 1894 | if (!string.IsNullOrWhiteSpace(input.keyword)) |
| 1861 | 1895 | { |
| 1862 | - query = query.Where((app, store) => | |
| 1863 | - app.Id.Contains(input.keyword) || | |
| 1896 | + query = query.Where((app, store) => | |
| 1897 | + app.Id.Contains(input.keyword) || | |
| 1864 | 1898 | app.ApplicationUserName.Contains(input.keyword) || |
| 1865 | 1899 | store.Dm.Contains(input.keyword)); |
| 1866 | 1900 | } |
| ... | ... | @@ -1965,5 +1999,106 @@ namespace NCC.Extend |
| 1965 | 1999 | |
| 1966 | 2000 | #endregion |
| 1967 | 2001 | |
| 2002 | + #region 测试接口:为现有申请记录添加审批记录 | |
| 2003 | + /// <summary> | |
| 2004 | + /// 为现有申请记录添加审批记录(测试用) | |
| 2005 | + /// </summary> | |
| 2006 | + /// <remarks> | |
| 2007 | + /// 为"审批中"状态的申请记录添加当前节点的审批记录,用于测试审批人信息返回 | |
| 2008 | + /// </remarks> | |
| 2009 | + /// <param name="applicationId">申请ID(可选,不传则处理所有"审批中"状态的申请)</param> | |
| 2010 | + /// <param name="approverId">审批人ID(可选,不传则使用admin)</param> | |
| 2011 | + /// <returns>处理结果</returns> | |
| 2012 | + [HttpPost("Test/AddApprovalRecord")] | |
| 2013 | + public async Task<dynamic> AddApprovalRecordForTest(string applicationId = null, string approverId = null) | |
| 2014 | + { | |
| 2015 | + try | |
| 2016 | + { | |
| 2017 | + _db.Ado.BeginTran(); | |
| 2018 | + | |
| 2019 | + // 获取审批人信息(默认使用admin) | |
| 2020 | + var defaultApproverId = approverId ?? "admin"; | |
| 2021 | + var approverUser = await _db.Queryable<UserEntity>() | |
| 2022 | + .Where(x => x.Id == defaultApproverId) | |
| 2023 | + .Select(x => new { x.Id, x.RealName }) | |
| 2024 | + .FirstAsync(); | |
| 2025 | + | |
| 2026 | + if (approverUser == null) | |
| 2027 | + { | |
| 2028 | + throw NCCException.Oh("审批人不存在"); | |
| 2029 | + } | |
| 2030 | + | |
| 2031 | + // 查询需要处理的申请记录 | |
| 2032 | + var query = _db.Queryable<LqInventoryUsageApplicationEntity>() | |
| 2033 | + .Where(x => x.ApprovalStatus == "审批中"); | |
| 2034 | + | |
| 2035 | + if (!string.IsNullOrWhiteSpace(applicationId)) | |
| 2036 | + { | |
| 2037 | + query = query.Where(x => x.Id == applicationId); | |
| 2038 | + } | |
| 2039 | + | |
| 2040 | + var applications = await query.ToListAsync(); | |
| 2041 | + | |
| 2042 | + if (!applications.Any()) | |
| 2043 | + { | |
| 2044 | + return new { success = true, message = "没有需要处理的申请记录", count = 0 }; | |
| 2045 | + } | |
| 2046 | + | |
| 2047 | + var successCount = 0; | |
| 2048 | + var skipCount = 0; | |
| 2049 | + | |
| 2050 | + foreach (var application in applications) | |
| 2051 | + { | |
| 2052 | + // 检查是否已存在当前节点的审批记录 | |
| 2053 | + var existingRecord = await _db.Queryable<LqInventoryUsageApprovalRecordEntity>() | |
| 2054 | + .Where(x => x.ApplicationId == application.Id && x.IsCurrentNode == 1) | |
| 2055 | + .Where(x => x.ApprovalResult == "待审批" || x.ApprovalResult == "") | |
| 2056 | + .FirstAsync(); | |
| 2057 | + | |
| 2058 | + if (existingRecord != null) | |
| 2059 | + { | |
| 2060 | + skipCount++; | |
| 2061 | + continue; | |
| 2062 | + } | |
| 2063 | + | |
| 2064 | + // 创建审批记录 | |
| 2065 | + var approvalRecord = new LqInventoryUsageApprovalRecordEntity | |
| 2066 | + { | |
| 2067 | + Id = YitIdHelper.NextId().ToString(), | |
| 2068 | + ApplicationId = application.Id, | |
| 2069 | + NodeId = application.CurrentNodeId ?? application.Id, // 使用申请ID作为节点ID(如果CurrentNodeId为空) | |
| 2070 | + NodeOrder = 1, | |
| 2071 | + ApproverId = approverUser.Id, | |
| 2072 | + ApproverName = approverUser.RealName ?? "", | |
| 2073 | + ApprovalResult = "待审批", | |
| 2074 | + ApprovalOpinion = "", | |
| 2075 | + ApprovalTime = DateTime.Now, | |
| 2076 | + IsCurrentNode = 1 | |
| 2077 | + }; | |
| 2078 | + | |
| 2079 | + await _db.Insertable(approvalRecord).ExecuteCommandAsync(); | |
| 2080 | + successCount++; | |
| 2081 | + } | |
| 2082 | + | |
| 2083 | + _db.Ado.CommitTran(); | |
| 2084 | + | |
| 2085 | + return new | |
| 2086 | + { | |
| 2087 | + success = true, | |
| 2088 | + message = $"处理完成:成功添加 {successCount} 条审批记录,跳过 {skipCount} 条(已存在)", | |
| 2089 | + total = applications.Count, | |
| 2090 | + successCount = successCount, | |
| 2091 | + skipCount = skipCount | |
| 2092 | + }; | |
| 2093 | + } | |
| 2094 | + catch (Exception ex) | |
| 2095 | + { | |
| 2096 | + _db.Ado.RollbackTran(); | |
| 2097 | + _logger.LogError(ex, "添加审批记录失败"); | |
| 2098 | + throw NCCException.Oh($"添加失败:{ex.Message}"); | |
| 2099 | + } | |
| 2100 | + } | |
| 2101 | + #endregion | |
| 2102 | + | |
| 1968 | 2103 | } |
| 1969 | 2104 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs
| ... | ... | @@ -619,6 +619,7 @@ namespace NCC.Extend |
| 619 | 619 | salary.DailyAverageConsumption, |
| 620 | 620 | salary.DailyAverageProjectCount, |
| 621 | 621 | daysInMonth, |
| 622 | + salary.WorkingDays, | |
| 622 | 623 | isNewStore); |
| 623 | 624 | |
| 624 | 625 | // 4.2 提成计算 |
| ... | ... | @@ -732,7 +733,7 @@ namespace NCC.Extend |
| 732 | 733 | /// <summary> |
| 733 | 734 | /// 计算底薪 |
| 734 | 735 | /// </summary> |
| 735 | - private decimal CalculateBaseSalary(decimal dailyAvgConsumption, decimal dailyAvgProjectCount, int daysInMonth, bool isNewStore) | |
| 736 | + private decimal CalculateBaseSalary(decimal dailyAvgConsumption, decimal dailyAvgProjectCount, int daysInMonth, decimal workingDays, bool isNewStore) | |
| 736 | 737 | { |
| 737 | 738 | // 规则调整:按日均计算 |
| 738 | 739 | // 一星:月消耗 10000 / 当月天数,项目数 96 / 当月天数 |
| ... | ... | @@ -788,7 +789,13 @@ namespace NCC.Extend |
| 788 | 789 | baseSalary = 2000; |
| 789 | 790 | } |
| 790 | 791 | |
| 791 | - return baseSalary; | |
| 792 | + // 最终计算:(底薪 / 当月天数) * 在店天数 | |
| 793 | + if (daysInMonth > 0) | |
| 794 | + { | |
| 795 | + baseSalary = (baseSalary / daysInMonth) * workingDays; | |
| 796 | + } | |
| 797 | + | |
| 798 | + return Math.Round(baseSalary, 2); | |
| 792 | 799 | } |
| 793 | 800 | |
| 794 | 801 | /// <summary> | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqTechTeacherSalaryService.cs
| ... | ... | @@ -13,6 +13,7 @@ using NCC.Extend.Entitys.lq_attendance_summary; |
| 13 | 13 | using NCC.Extend.Entitys.lq_tech_teacher_salary_statistics; |
| 14 | 14 | using NCC.Extend.Entitys.lq_xh_hyhk; |
| 15 | 15 | using NCC.Extend.Entitys.lq_xh_kjbsyj; |
| 16 | +using NCC.Extend.Entitys.lq_person_times_record; | |
| 16 | 17 | using NCC.System.Entitys.Permission; |
| 17 | 18 | using SqlSugar; |
| 18 | 19 | using System; |
| ... | ... | @@ -509,6 +510,199 @@ namespace NCC.Extend |
| 509 | 510 | return (1m, consumeAchievement * 0.01m); |
| 510 | 511 | } |
| 511 | 512 | } |
| 513 | + | |
| 514 | + /// <summary> | |
| 515 | + /// 统计科技部老师某个月的数据 | |
| 516 | + /// </summary> | |
| 517 | + /// <remarks> | |
| 518 | + /// 实时统计科技部老师某个月的数据,包括: | |
| 519 | + /// - 开单业绩:从 lq_kd_kjbsyj 表统计 | |
| 520 | + /// - 消耗业绩:从 lq_xh_kjbsyj 表统计(关联 lq_xh_hyhk 获取时间) | |
| 521 | + /// - 退卡业绩:从 lq_hytk_kjbsyj 表统计 | |
| 522 | + /// - 手工费:从耗卡表(lq_xh_kjbsyj)的 F_LaborCost 字段统计 | |
| 523 | + /// - 人头:从 lq_person_times_record 表统计(按月份+客户去重) | |
| 524 | + /// - 人次:从 lq_person_times_record 表统计(按日期+客户去重) | |
| 525 | + /// | |
| 526 | + /// 示例请求: | |
| 527 | + /// ```json | |
| 528 | + /// { | |
| 529 | + /// "year": 2025, | |
| 530 | + /// "month": 11 | |
| 531 | + /// } | |
| 532 | + /// ``` | |
| 533 | + /// </remarks> | |
| 534 | + /// <param name="input">查询参数(年份、月份)</param> | |
| 535 | + /// <returns>科技部老师统计数据列表</returns> | |
| 536 | + [HttpGet("statistics")] | |
| 537 | + public async Task<List<TechTeacherStatisticsOutput>> GetTechTeacherStatistics([FromQuery] TechTeacherStatisticsInput input) | |
| 538 | + { | |
| 539 | + // 1. 参数验证 | |
| 540 | + if (input.Year < 2020 || input.Year > 2100) | |
| 541 | + { | |
| 542 | + throw new Exception("年份范围不正确"); | |
| 543 | + } | |
| 544 | + if (input.Month < 1 || input.Month > 12) | |
| 545 | + { | |
| 546 | + throw new Exception("月份范围不正确(1-12)"); | |
| 547 | + } | |
| 548 | + | |
| 549 | + // 2. 计算时间范围 | |
| 550 | + var startDate = new DateTime(input.Year, input.Month, 1); | |
| 551 | + var endDate = startDate.AddMonths(1).AddDays(-1); | |
| 552 | + var monthStr = $"{input.Year}{input.Month:D2}"; | |
| 553 | + | |
| 554 | + // 3. 获取所有科技部老师(岗位为"科技老师") | |
| 555 | + var techTeacherList = await _db.Queryable<UserEntity>() | |
| 556 | + .Where(x => x.Gw == "科技老师") | |
| 557 | + .Select(x => new | |
| 558 | + { | |
| 559 | + EmployeeId = x.Id, | |
| 560 | + EmployeeName = x.RealName, | |
| 561 | + EmployeeAccount = x.Account | |
| 562 | + }) | |
| 563 | + .ToListAsync(); | |
| 564 | + | |
| 565 | + if (techTeacherList == null || !techTeacherList.Any()) | |
| 566 | + { | |
| 567 | + return new List<TechTeacherStatisticsOutput>(); | |
| 568 | + } | |
| 569 | + | |
| 570 | + var teacherIds = techTeacherList.Select(x => x.EmployeeId).ToList(); | |
| 571 | + var teacherAccounts = techTeacherList.Where(x => !string.IsNullOrEmpty(x.EmployeeAccount)).Select(x => x.EmployeeAccount).ToList(); | |
| 572 | + | |
| 573 | + // 4. 使用聚合查询统计开单业绩和手工费(优化性能) | |
| 574 | + // 注意:kjblsyj字段是varchar类型,需要转换 | |
| 575 | + var orderStatsList = await _db.Queryable<LqKdKjbsyjEntity>() | |
| 576 | + .Where(x => x.Yjsj >= startDate && x.Yjsj <= endDate.AddDays(1) && x.IsEffective == 1) | |
| 577 | + .Where(x => teacherIds.Contains(x.Kjbls) || teacherAccounts.Contains(x.Kjblszh)) | |
| 578 | + .ToListAsync(); | |
| 579 | + | |
| 580 | + var orderStats = orderStatsList | |
| 581 | + .Where(x => !string.IsNullOrEmpty(x.Kjbls)) | |
| 582 | + .GroupBy(x => x.Kjbls) | |
| 583 | + .Select(g => new | |
| 584 | + { | |
| 585 | + TeacherId = g.Key, | |
| 586 | + OrderAchievement = g.Sum(x => decimal.TryParse(x.Kjblsyj, out var val) ? val : 0m) | |
| 587 | + }) | |
| 588 | + .ToList(); | |
| 589 | + | |
| 590 | + // 5. 使用聚合查询统计消耗业绩和手工费(关联耗卡主表获取时间) | |
| 591 | + var consumeStatsList = await _db.Queryable<LqXhKjbsyjEntity, LqXhHyhkEntity>( | |
| 592 | + (kjbsyj, hyhk) => kjbsyj.Glkdbh == hyhk.Id && hyhk.IsEffective == 1) | |
| 593 | + .Where((kjbsyj, hyhk) => kjbsyj.IsEffective == 1 | |
| 594 | + && hyhk.Hksj >= startDate && hyhk.Hksj <= endDate.AddDays(1)) | |
| 595 | + .Where((kjbsyj, hyhk) => teacherIds.Contains(kjbsyj.Kjbls) || teacherAccounts.Contains(kjbsyj.Kjblszh)) | |
| 596 | + .Select((kjbsyj, hyhk) => new | |
| 597 | + { | |
| 598 | + TeacherId = kjbsyj.Kjbls, | |
| 599 | + ConsumeAchievement = kjbsyj.Kjblsyj, | |
| 600 | + LaborCost = kjbsyj.LaborCost | |
| 601 | + }) | |
| 602 | + .ToListAsync(); | |
| 603 | + | |
| 604 | + var consumeStats = consumeStatsList | |
| 605 | + .Where(x => !string.IsNullOrEmpty(x.TeacherId)) | |
| 606 | + .GroupBy(x => x.TeacherId) | |
| 607 | + .Select(g => new | |
| 608 | + { | |
| 609 | + TeacherId = g.Key, | |
| 610 | + ConsumeAchievement = g.Sum(x => x.ConsumeAchievement ?? 0m), | |
| 611 | + LaborCost = g.Sum(x => x.LaborCost ?? 0m) | |
| 612 | + }) | |
| 613 | + .ToList(); | |
| 614 | + | |
| 615 | + // 6. 使用聚合查询统计退卡业绩和手工费 | |
| 616 | + var refundStatsList = await _db.Queryable<LqHytkKjbsyjEntity>() | |
| 617 | + .Where(x => x.Tksj >= startDate && x.Tksj <= endDate.AddDays(1) && x.IsEffective == 1) | |
| 618 | + .Where(x => teacherIds.Contains(x.Kjbls) || teacherAccounts.Contains(x.Kjblszh)) | |
| 619 | + .ToListAsync(); | |
| 620 | + | |
| 621 | + var refundStats = refundStatsList | |
| 622 | + .Where(x => !string.IsNullOrEmpty(x.Kjbls)) | |
| 623 | + .GroupBy(x => x.Kjbls) | |
| 624 | + .Select(g => new | |
| 625 | + { | |
| 626 | + TeacherId = g.Key, | |
| 627 | + RefundAchievement = g.Sum(x => x.Kjblsyj ?? 0m) | |
| 628 | + }) | |
| 629 | + .ToList(); | |
| 630 | + | |
| 631 | + // 7. 统计人头(按月份+客户去重) | |
| 632 | + var personCountRecords = await _db.Queryable<LqPersonTimesRecordEntity>() | |
| 633 | + .Where(x => x.PersonType == "科技老师" | |
| 634 | + && x.WorkMonth == monthStr | |
| 635 | + && x.IsEffective == 1 | |
| 636 | + && teacherIds.Contains(x.PersonId)) | |
| 637 | + .ToListAsync(); | |
| 638 | + | |
| 639 | + var personCountStats = personCountRecords | |
| 640 | + .GroupBy(x => new { x.PersonId, x.MemberId }) | |
| 641 | + .Select(g => new { TeacherId = g.Key.PersonId }) | |
| 642 | + .GroupBy(x => x.TeacherId) | |
| 643 | + .Select(g => new | |
| 644 | + { | |
| 645 | + TeacherId = g.Key, | |
| 646 | + PersonCount = g.Count() | |
| 647 | + }) | |
| 648 | + .ToList(); | |
| 649 | + | |
| 650 | + // 8. 统计人次(按日期+客户去重,汇总数量) | |
| 651 | + var personTimesRecords = await _db.Queryable<LqPersonTimesRecordEntity>() | |
| 652 | + .Where(x => x.PersonType == "科技老师" | |
| 653 | + && x.WorkMonth == monthStr | |
| 654 | + && x.IsEffective == 1 | |
| 655 | + && teacherIds.Contains(x.PersonId)) | |
| 656 | + .ToListAsync(); | |
| 657 | + | |
| 658 | + // 先按日期+客户去重,取最大数量,然后按老师汇总 | |
| 659 | + var personTimesStats = personTimesRecords | |
| 660 | + .GroupBy(x => new { x.PersonId, x.WorkDate, x.MemberId }) | |
| 661 | + .Select(g => new | |
| 662 | + { | |
| 663 | + TeacherId = g.Key.PersonId, | |
| 664 | + Quantity = g.Max(x => x.Quantity ?? 0m) // 按日期+客户去重,取最大数量 | |
| 665 | + }) | |
| 666 | + .GroupBy(x => x.TeacherId) | |
| 667 | + .Select(g => new | |
| 668 | + { | |
| 669 | + TeacherId = g.Key, | |
| 670 | + PersonTimes = g.Sum(x => x.Quantity) // 汇总所有去重后的数量 | |
| 671 | + }) | |
| 672 | + .ToList(); | |
| 673 | + | |
| 674 | + // 9. 构建结果字典(优化查找性能) | |
| 675 | + var orderDict = orderStats.ToDictionary(x => x.TeacherId, x => x); | |
| 676 | + var consumeDict = consumeStats.ToDictionary(x => x.TeacherId, x => x); | |
| 677 | + var refundDict = refundStats.ToDictionary(x => x.TeacherId, x => x); | |
| 678 | + var personCountDict = personCountStats.ToDictionary(x => x.TeacherId, x => x); | |
| 679 | + var personTimesDict = personTimesStats.ToDictionary(x => x.TeacherId, x => x); | |
| 680 | + | |
| 681 | + // 10. 组装结果 | |
| 682 | + var result = new List<TechTeacherStatisticsOutput>(); | |
| 683 | + foreach (var teacher in techTeacherList) | |
| 684 | + { | |
| 685 | + var orderStat = orderDict.ContainsKey(teacher.EmployeeId) ? orderDict[teacher.EmployeeId] : null; | |
| 686 | + var consumeStat = consumeDict.ContainsKey(teacher.EmployeeId) ? consumeDict[teacher.EmployeeId] : null; | |
| 687 | + var refundStat = refundDict.ContainsKey(teacher.EmployeeId) ? refundDict[teacher.EmployeeId] : null; | |
| 688 | + var personCountStat = personCountDict.ContainsKey(teacher.EmployeeId) ? personCountDict[teacher.EmployeeId] : null; | |
| 689 | + var personTimesStat = personTimesDict.ContainsKey(teacher.EmployeeId) ? personTimesDict[teacher.EmployeeId] : null; | |
| 690 | + | |
| 691 | + result.Add(new TechTeacherStatisticsOutput | |
| 692 | + { | |
| 693 | + EmployeeId = teacher.EmployeeId, | |
| 694 | + EmployeeName = teacher.EmployeeName, | |
| 695 | + OrderAchievement = orderStat?.OrderAchievement ?? 0m, | |
| 696 | + ConsumeAchievement = consumeStat?.ConsumeAchievement ?? 0m, | |
| 697 | + RefundAchievement = refundStat?.RefundAchievement ?? 0m, | |
| 698 | + PersonCount = personCountStat?.PersonCount ?? 0, | |
| 699 | + PersonTimes = personTimesStat?.PersonTimes ?? 0m, | |
| 700 | + LaborCost = consumeStat?.LaborCost ?? 0m // 手工费只统计耗卡中的手工费 | |
| 701 | + }); | |
| 702 | + } | |
| 703 | + | |
| 704 | + return result; | |
| 705 | + } | |
| 512 | 706 | } |
| 513 | 707 | } |
| 514 | 708 | ... | ... |